UNPKG

@zohodesk/client_build_tool

Version:

A CLI tool to build web applications and client libraries

362 lines (302 loc) 12.1 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _postcss = _interopRequireDefault(require("postcss")); var _fs = _interopRequireDefault(require("fs")); var _checkIsPatternsMatchFilename = require("../../loaderConfigs/checkIsPatternsMatchFilename"); var _ErrorHandler = require("./ErrorHandler"); function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } // import { RawSource } from 'webpack-sources'; const ignoreVals = ['--zd_size', '--zd_font_size', '--size', '--size_']; let variablesRead = {}; const supportedProps = ['font-size', 'margin', 'margin-top', 'margin-bottom', 'margin-left', 'margin-right', 'padding', 'padding-top', 'padding-bottom', 'padding-left', 'padding-right', '^top', '^right', '^bottom', '^left', '^width', 'min-width', 'max-width', '^height', 'min-height', 'max-height', 'text-indent', 'clip', 'flex-basis', 'row-gap', 'gap', 'column-gap', 'flex']; // const avoidProps = []; // -- is issue IO -- /* issues eg : issues = ['--zd_size', '--zd_font_size', '--size', '--size_']; input : --zd_size output : true comment : do not execute when --zd_size comes as prop */ function isIgnoreValuePresent(ignoreVals, prop) { let present = false; ignoreVals.forEach(issue => { if (prop && prop.includes(issue)) { present = true; } }); return present; } // -- to convert the hyphen values to values -- /* input : var(--zdt_uploadlist_default_width) output : --zdt_uploadlist_default_width comment : to make the variable object using the output as key and decl.prop such as font-size as value */ function extractVariableName(val) { return val.replace(/calc\((.+)\)/gi, '$1').replace(/var\((.+)\)/gi, '$1').replace('-1', '').replace('*', '').replace('\n', '').trim(); } function variableConvertor(rootOriginal, variables, settingsObject) { rootOriginal.walkRules(rule => { rule.nodes.forEach((decl, index) => { const prevNode = rule.nodes[index - 1]; const currentNode = rule.nodes[index]; if (decl.prop && decl.prop.includes('--')) { if (prevNode && prevNode.type === 'comment' && prevNode.text.toLowerCase() === 'variable:ignore') { return; } if (isIgnoreValuePresent(ignoreVals, decl.prop)) { return; } if (settingsObject[variables[decl.prop]]) { /* if there is no value for property, set it to default so that undefined doesn't get called as key */ if (!variables[decl.prop]) { // eslint-disable-next-line no-param-reassign variables[decl.prop] = 'default'; } const pxReplacement = settingsObject[variables[decl.prop]].replacements.px; const valArr = decl.value.split(' '); // single values are considered in the above array and converted below valArr.forEach((value, index) => { if (value.includes('px')) { const num = value.replace('px', ''); valArr[index] = pxReplacement.replace('$$', num); } }); currentNode.value = valArr.join(' '); } } }); }); return rootOriginal; } function createFolderIfNonExistent(path) { if (!_fs.default.existsSync(path)) { _fs.default.mkdirSync(path, { recursive: true }); } } function createFileIfNonExistent(path, content) { if (_fs.default.existsSync(path)) { _fs.default.writeFileSync(path, content, 'utf-8'); } } class VariableConversionCollector { constructor(options = {}) { this.configFile = options.configFile; this.patterns = options.patterns; this.initializeFiles(); } // eslint-disable-next-line class-methods-use-this initializeFiles() { createFolderIfNonExistent('./.cli/logs/'); createFolderIfNonExistent('./.cli/config/variables/'); createFolderIfNonExistent('./.cli/config/selectorWeight/'); createFileIfNonExistent('./.cli/logs/unassignedVariables.log', '{}'); createFileIfNonExistent('./.cli/logs/css_error.log', '{}'); } apply(compiler) { const { patterns } = this; const variables = {}; const unassigned = {}; // console.log(windowsModification([this.filename])[0]); const rawdata = _fs.default.readFileSync(this.configFile); const data = JSON.parse(rawdata); const { settings: settingsObject, errorLog: errorLogStatus, errorInConsole: errorConsoleStatus, errorsAllowed, strictMode } = data; // If theres is no setting for default prop in settingsObject, set one. if (!settingsObject.default) { settingsObject.default = { allowed: ['px', 'em', 'fit-content', 'auto', '%', 'inherit', '-moz-fit-content', 'vh', '0', 'initial', 'vw'], replacements: { px: 'var(--zd_size$$)' }, range: { start: -99999, end: 99999 } }; } /* purpose of tap : to create a variable object such as: { --zdt_uploadlist_default_width : width, --zdt_uploadlist_default_height : height, } which will help in the conversion further */ if (_fs.default.existsSync('./.cli/config/variables/variableMapping.json')) { variablesRead = JSON.parse(_fs.default.readFileSync('./.cli/config/variables/variableMapping.json', 'utf-8')); Object.keys(variablesRead.changes).forEach(key => { variables[key] = variablesRead.changes[key]; }); } compiler.hooks.compilation.tap('VariableConversionCollector', compilation => { compilation.hooks.optimizeModules.tap('VariableConversionCollector', modulesIterable => { const modules = Array.from(modulesIterable); const mods = modules.filter(x => x.type.includes('css')); mods.forEach(module => { const rootOriginal = _postcss.default.parse(module.content); const filename = module.issuer.resource; if (!filename.includes('node_modules')) { rootOriginal.walkRules(rule => { rule.walkDecls(decl => { decl.value.split(' ').forEach(val => { if (val && val.includes('--') && !new RegExp(ignoreVals.join('|'), 'gi').test(val) && decl.prop) { const extractedValue = extractVariableName(val); if (!variables[extractedValue]) { variables[extractedValue] = decl.prop; } else if (new RegExp(supportedProps.join('|'), 'gi').test(decl.prop)) { // console.log( // `${extractedValue} : ${variables[extractedValue]} already exists please check!` // ); if (errorsAllowed.MULTIPLE_OCCURANCES) { const errObj = { decl, type: 'MULTIPLE_OCCURANCES', filename, message: `${extractedValue} : ${variables[extractedValue]} already exists please check!` }; _ErrorHandler.errHandler.errorTable.push(errObj); _ErrorHandler.errHandler.errorFunction(errObj); } } // console.log(decl.prop); } else if (/^--/gi.test(decl.prop) && val.trim() !== '' && !variables[decl.prop]) { if (!Object.keys(variablesRead.ignore).includes(decl.prop)) { unassigned[decl.prop] = variables[decl.prop]; } } }); }); }); /* current value example: { --zdt_uploadlist_default_width : --zd_upload_width, --zd_upload_width : width } expected value : { --zdt_uploadlist_default_width : width, --zd_upload_width : width } conversion is done in the while loop below */ Object.keys(variables).forEach(key => { while (variables[variables[key]]) { variables[key] = variables[variables[key]]; } }); } }); }); // -- conversion for the root using variableConvertor -- /* input : .a{ padding : 20px } output : // on settingObject file : { padding : { replacements : { px : 'zd_size$$' }}} .a{ padding : zd_size20; } */ compilation.hooks.optimizeModules.tap('VariableConversionCollector', modules => { const mods = Array.from(modules).filter(x => x.type.includes('css')); mods.forEach(module => { const filename = module.issuer.resource; /* input : filename : 'D:/MyWork/..../desk_client_app/supportapp/src/components/Avatar/Avatar.module.css, patterns.cssVariableReplacement: // include src folder, include deskapp folder, exclude node modules [ "src", "deskapp", "!node_modules" ] output : true or false */ if ((0, _checkIsPatternsMatchFilename.checkIsPatternsMatchFilename)(patterns, filename) === false) { return; } const rootOriginal = _postcss.default.parse(module.content); // eslint-disable-next-line no-param-reassign module.content = variableConvertor(rootOriginal, variables, settingsObject).toString(); }); }); }); /* purpose of tap : to display the errors encountered so far input : all css files output : all errors that are present in the errTable arr */ compiler.hooks.afterEmit.tap('error-display', () => { const { errors, errorTable: errTable } = _ErrorHandler.errHandler; if (Object.keys(unassigned).length > 0 && strictMode) { console.log(); console.log(unassigned); console.log(); let str = '{\n'; Object.keys(unassigned).forEach(key => { str += `"${key}" : "${unassigned[key]}",\n`; }); str += '}'; _fs.default.writeFileSync('./.cli/logs/unassignedVariables.log', str, 'utf-8'); throw new Error('^^^ Variables above have not been assigned! ^^^'); } const avlTypes = new Set([]); // eslint-disable-next-line array-callback-return, consistent-return const srtArr = errTable.sort((a, b) => { avlTypes.add(a.type); avlTypes.add(b.type); if (a.type < b.type) { return -1; } }); if (errorConsoleStatus) { const errorHandler = new _ErrorHandler.ErrorHandler(); avlTypes.forEach(type => { console.log('---------------------------------------------------------------------------------------------------------------------------'); console.log(`Error Type : ${type}`); console.log('---------------------------------------------------------------------------------------------------------------------------'); srtArr.forEach(err => { if (err.decl.prop && err.decl.value && err.type === type) { errorHandler.printError(err); } }); console.log('---------------------------------------------------------------------------------------------------------------------------'); }); } if (errorLogStatus) { _fs.default.writeFileSync('./.cli/logs/css_error.log', ''); console.log('writing to logFile...'); if (errors.length > 0) { errors.forEach((err, index) => { if (errTable[index].decl.prop && errTable[index].decl.value) { _fs.default.appendFileSync('./.cli/logs/css_error.log', err); } }); } } }); } } var _default = VariableConversionCollector; exports.default = _default;