aliascss
Version:
AliasCSS is a CSS post processor.
349 lines (348 loc) • 14.8 kB
JavaScript
import extractClassNamesFromFile from "./extractClassNamesFromFile.js";
import { compiler as statementMaker } from "../returnStatement.js";
import config from '../config.js';
import fs from "fs";
import fg from "fast-glob";
import path from 'path';
import postcss from 'postcss';
import postcssDiscardDuplicates from 'postcss-discard-duplicates';
import cssnano from 'cssnano';
import chokidar from 'chokidar';
const init = {
classList: [], // hold className for MasterCSS to avoid repeating
groups: [],
input: '', // input glob pattern
output: '', // location off output
'--file': false, // if set true compileFileByFile to [filename].css
statementMaker,
config,
'--module': false,
rawCSS: '',
customGroupStatement: '',
minify: false,
globPattern: '', // Use this to check valid new created file to add to watch during watch.on
};
export default function main(config) {
// initialize
initialize(config);
if (init.config.prefix)
init.statementMaker.prefix = init.config.prefix;
if (init.input && (init.output || init['--file'])) {
const input = fg.sync(init.input, { dot: true });
// console.log(input);
input.forEach((file) => {
createCSSFileByFile(file);
});
postify(init.output, [postcssDiscardDuplicates], init.minify);
}
else {
console.error("Please Provide input, output or set '--file' to true");
}
}
export function globalCSSCompiler() {
const classList = [];
if (init.globPattern && init.output) {
fs.truncateSync(init.output);
const input = fg.sync(init.globPattern, { dot: true });
// console.log(input);
input.forEach((file) => {
const [gbContent,] = compileFile(file, config, statementMaker, classList);
try {
fs.writeFileSync(init.output, `\n/* Start :-----------ACSS ${path.basename(file)}------------------------*/\n${gbContent}
\n/* End :-----------ACSS ${path.basename(file)}----------------------------*/\n
`, { flag: 'a+' });
console.log('AliasCSS compiled', path.basename(file), 'to main css file :' + init.output);
}
catch (error) {
console.log('\x1b[31m', "Couldn't able to append/create to main css file :" + init.output);
console.log(error);
}
});
postify(init.output, [postcssDiscardDuplicates], init.minify);
}
else {
console.error("Please Provide input, output or set '--file' to true");
}
}
export function compileFile(file, config, statementMaker, globalClassList) {
let [globalStatement, compiledStatement, moduleStatement] = ['', '', ''];
// inject config.group and config.statement
if (statementMaker.rawCSS) {
compiledStatement += `/* From:aliacss.config.statement */\n${statementMaker.rawCSS}\n/* -----End:aliacss.config.statement----- */\n\n`;
moduleStatement += `/* From:aliacss.config.statement */\n${statementMaker.rawCSS}\n/* ------End:aliacss.config.statement----- */\n\n`;
}
if (statementMaker.customGroupStatement) {
compiledStatement += `/* From:aliacss.config.group */\n${statementMaker.customGroupStatement}\n/* -----End:aliacss.config.group----- */\n\n`;
moduleStatement += `/* From:aliacss.config.group */\n${statementMaker.customGroupStatement}\n/* -----End:aliacss.config.group----- */\n\n`;
}
const [classList, groups, keyframe] = extractClassNamesFromFile(file, config);
// 2. group
for (const key in groups) {
if (groups.hasOwnProperty(key)) {
// --------------ModuleStatement
if (/^module=/.test(key)) {
const mdStatement = statementMaker.group(groups[key], key.replace(/module=/, ''));
moduleStatement += mdStatement + '\n';
}
// -------------EndOfModule
else {
const gpStatement = statementMaker.group(groups[key], key);
globalStatement += gpStatement + '\n';
compiledStatement += gpStatement + '\n';
}
}
}
// 2. ClassList
classList.forEach((e) => {
const statement = statementMaker.make(e);
if (statement) {
console.log('\x1b[32m', statement);
if (globalClassList.indexOf(e) === -1) {
globalStatement += statement + '\n';
globalClassList.push(e);
// console.log(e);
}
compiledStatement += statement + '\n';
}
});
// 3. Keyframe
for (const key in keyframe) {
if (keyframe.hasOwnProperty(key)) {
const kfStatement = keyframesStatement(key, keyframe[key], statementMaker);
globalStatement += kfStatement + '\n';
compiledStatement += kfStatement + '\n';
}
}
return [globalStatement, compiledStatement, moduleStatement];
}
export function groupStatement(name, classNames, statementMaker) {
return statementMaker.group(classNames, name) + '\n';
}
export function keyframesStatement(name, timeLine, statementMaker) {
let kfStatement = '@keyframes ' + name + "{\n";
const returnPnV = (e) => e.map((i) => statementMaker.make(i, null, true)).join(";");
const split = timeLine.split(/\s+/);
split.forEach((each) => {
try {
const [at, pNv] = each.replace(/\]\[/, ']-[').replace("-", "=").split("=");
kfStatement += ` ${at.replace('@', '').replace(/:/g, ',').replace(/,/g, "%,").replace(/[\[|\]]/g, '')}% {${returnPnV(pNv.replace(/^\[|\]$/g, '').split(','))}}`;
}
catch (error) {
console.error('Not a valid entry for AliasCSS keyframes processor : ' + each, error);
}
});
return kfStatement + "\n}\n";
}
export function createCSSFileByFile(file, bool = false) {
const [gbContent, content, module] = compileFile(file, config, statementMaker, init.classList);
// console.log(init.classList);
// If its fileByFile
if (init["--module"] && module.trim()) {
try {
fs.writeFileSync(file + '.module.css', module);
// console.log(content);
console.log('AliasCSS compiled', path.basename(file), 'module Locally ');
}
catch (error) {
console.log('\x1b[31m', "Couldn't able to append/create locally from " + file);
console.log(error);
}
}
if (init["--file"]) {
try {
fs.writeFileSync(file + '.css', content);
// console.log(content);
console.log('AliasCSS compiled', path.basename(file), 'Locally');
}
catch (error) {
console.log('\x1b[31m', "Couldn't able to append/create locally from " + file);
console.log(error);
}
}
// Check for Global
if (!bool && init.output) {
try {
fs.writeFileSync(init.output, `\n/* Start :-----------ACSS ${path.basename(file)}------------------------*/\n${postcss([postcssDiscardDuplicates]).process(gbContent)}
\n/* End :-----------ACSS ${path.basename(file)}----------------------------*/\n
`, { flag: 'a+' });
console.log('AliasCSS compiled', path.basename(file), 'to main css file :' + init.output);
}
catch (error) {
console.log('\x1b[31m', "Couldn't able to append/create to main css file :" + init.output);
console.log(error);
}
}
}
export function postify(file, plugin, minify = false) {
const data = fs.readFileSync(file, 'utf-8');
if (fs.existsSync(file)) {
if (minify === true)
plugin.push(cssnano);
postcss(plugin).process(data).then(result => {
fs.truncateSync(file);
fs.writeFileSync(file, result.css);
});
}
// fs.readFile(file, (err, css) => {
// postcss(plugin)
// .process(css, { from: file, to: file+"post.css" })
// .then(result => {
// fs.writeFile(file+"post.css", result.css, () => true)
// // if ( result.map ) {
// // fs.writeFile(file+'.map', result.map.toString(), () => true)
// // }
// })
// })
}
export function writeStatementToFile(file, content, from) {
// Check for Global
if (init.output) {
try {
fs.writeFileSync(init.output, `\n/* Start :-----------ACSS:From aliasCSSConfig.${from}------------------------*/\n${content}
\n/* End :-----------ACSS aliasCSSConfig.${from}----------------------------*/\n
`, { flag: 'a+' });
console.log('AliasCSS compiled', '[aliasCSSConfig.statement]', 'aliascss.config.js');
}
catch (error) {
console.log('\x1b[31m', "Couldn't able to append/create [key:statement] from alias.config.js ");
console.log(error);
}
}
}
// Initialize
export function initialize(configFile) {
// ----------------input-------------------
if (configFile.hasOwnProperty('input')) {
init.input = configFile.input;
init.globPattern = configFile.input;
}
// ----------------Prefix-------------------
if (configFile.hasOwnProperty('prefix')) {
init.config.prefix = configFile.prefix;
}
// ----------------output-------------------
if (configFile.hasOwnProperty('output')) {
const op = configFile.output;
if (op.hasOwnProperty('location')) {
init.output = op.location;
}
if (op.hasOwnProperty('--file') && op['--file'] === true) {
init["--file"] = true;
}
}
// Adding Custom color, length etc
if (configFile.hasOwnProperty('custom') && typeof configFile.custom === 'object') {
Object.keys(configFile.custom).forEach((key) => {
init.statementMaker.addCustom(key, configFile.custom[key]);
});
}
// Extend custom class name define {'border-color-native":'border-color: skyBlue',}
if (configFile.hasOwnProperty('prebuild')) {
init.statementMaker.prebuild(configFile.prebuild);
}
// Ignore these class name
if (configFile.hasOwnProperty('ignore')) {
if (Array.isArray(configFile.ignore)) {
configFile.ignore.forEach((each) => init.config.ignore.push(each.trim()));
}
}
// --module
if (configFile.hasOwnProperty('--module') && configFile.hasOwnProperty('importModuleAs')) {
init["--module"] = true;
init.config.useCSSModule = init["--module"] ? true : false;
if (init.config.useCSSModule)
init.config.matchCSSModuleFunction = init.config.createCSSModuleRegex(configFile.importModuleAs);
}
// ---------output Minify
if (configFile.hasOwnProperty('minify')) {
init.minify = configFile.minify;
}
// ------------Extractor function-------
if (configFile.hasOwnProperty('extractorFunction')) {
init.config.useExtractorFunction = configFile.extractorFunction.trim() ? true : false;
if (init.config.useExtractorFunction)
init.config.matchExtractorFunction = init.config.createExtractorRegex(configFile.extractorFunction);
}
// ---------Extend----------------
if (configFile.hasOwnProperty('extend') && typeof configFile.extend === 'object') {
const filteredObj = {};
Object.keys(configFile.extend).map((key) => {
// if (configFile.extend[key].hasOwnProperty('compiler') && (typeof configFile.extend[key].compiler === 'function')){
filteredObj[key] = configFile.extend[key];
// }
});
init.statementMaker.extend(filteredObj);
}
// -----------------useColon----------------------------
if (configFile.hasOwnProperty('useColon')) {
init.config.useColon = configFile.useColon;
}
// ---------------addMedia----------------
if (configFile.hasOwnProperty('media') && typeof configFile.media === 'object') {
init.statementMaker.addMedia(configFile.media);
}
// /Truncate File every time we bundle
if (configFile.hasOwnProperty('truncate') && configFile.truncate === false) {
// do nothing
}
else {
if (fs.existsSync(init.output))
fs.truncateSync(path.resolve(init.output));
}
// Custom CSS statement
if (configFile.hasOwnProperty('statement')) {
init.rawCSS = configFile.statement;
init.statementMaker.rawCSS = configFile.statement;
writeStatementToFile(init.output, configFile.statement, 'config.statement');
}
// Custom Groups bundling acss classnames in single class name
if (configFile.hasOwnProperty('group')) {
init.customGroupStatement = init.statementMaker.groupObj(configFile.group);
init.statementMaker.customGroupStatement = init.statementMaker.groupObj(configFile.group);
if (init.customGroupStatement)
writeStatementToFile(init.output, init.customGroupStatement, 'config.group');
}
}
// ----------------WATCH-------------------------------
export function watch(config) {
main(config);
const watcher = chokidar.watch(init.input, {
ignored: '*.css', // ignore dot-files
persistent: true
});
const compileFile = (file) => {
console.log(`--processing file : ${file}`);
createCSSFileByFile(file, true);
globalCSSCompiler();
postify(init.output, [postcssDiscardDuplicates], init.minify);
console.log('Done! ');
};
// Something to use when events are received.
const log = console.log.bind(console);
// Add event listeners.
watcher
.on('add', path => log(`File ${path} has been added to watch`))
.on('change', path => compileFile(path));
// .on('unlink', path => log(`File ${path} has been removed`));
// More possible events.
watcher
.on('addDir', path => log(`Directory ${path} has been added`))
.on('unlinkDir', path => log(`Directory ${path} has been removed`))
// .on('error', error => log(`Watcher error: ${error}`))
// .on('ready', () => log('Initial scan complete. Ready for changes'))
.on('raw', (event, path, details) => {
// log('Raw event info:', event, path, details);
if (event === 'created' && details.type === 'file') {
if (init.globPattern) {
const files = fg.sync(init.globPattern, { absolute: true });
if (files.indexOf(path) !== -1) {
watcher.add(path);
// console.log(path,123123);
}
}
else {
watcher.add(path);
}
}
});
}