From a0cc4ab43ba1920e37bb685e1651b36d2e1fda2e Mon Sep 17 00:00:00 2001 From: Sosuke Suzuki Date: Mon, 31 Jan 2022 16:46:47 +0900 Subject: [PATCH] Reduce bundle size of `parser-postcss.js` (#12204) * Extract utils * Move `utils.js` to `utils/index.js` --- src/language-css/loc.js | 3 +- src/language-css/parser-postcss.js | 18 ++-- src/language-css/printer-postcss.js | 6 +- .../utils/has-SCSS-interpolation.js | 22 ++++ .../utils/has-string-or-function.js | 16 +++ src/language-css/{utils.js => utils/index.js} | 101 ------------------ .../utils/is-SCSS-nested-property-node.js | 16 +++ src/language-css/utils/is-SCSS-variable.js | 7 ++ src/language-css/utils/is-less-parser.js | 8 ++ src/language-css/utils/is-module-rule-name.js | 9 ++ src/language-css/utils/is-scss.js | 11 ++ src/language-css/utils/stringify-node.js | 32 ++++++ 12 files changed, 134 insertions(+), 115 deletions(-) create mode 100644 src/language-css/utils/has-SCSS-interpolation.js create mode 100644 src/language-css/utils/has-string-or-function.js rename src/language-css/{utils.js => utils/index.js} (79%) create mode 100644 src/language-css/utils/is-SCSS-nested-property-node.js create mode 100644 src/language-css/utils/is-SCSS-variable.js create mode 100644 src/language-css/utils/is-less-parser.js create mode 100644 src/language-css/utils/is-module-rule-name.js create mode 100644 src/language-css/utils/is-scss.js create mode 100644 src/language-css/utils/stringify-node.js diff --git a/src/language-css/loc.js b/src/language-css/loc.js index 5c077301a..fd0fa8646 100644 --- a/src/language-css/loc.js +++ b/src/language-css/loc.js @@ -1,7 +1,8 @@ "use strict"; +const { skipEverythingButNewLine } = require("../utils/text/skip.js"); +const getLast = require("../utils/get-last.js"); const lineColumnToIndex = require("../utils/line-column-to-index.js"); -const { getLast, skipEverythingButNewLine } = require("../common/util.js"); function calculateLocStart(node, text) { // value-* nodes have this diff --git a/src/language-css/parser-postcss.js b/src/language-css/parser-postcss.js index 81f319f9f..5f60fac95 100644 --- a/src/language-css/parser-postcss.js +++ b/src/language-css/parser-postcss.js @@ -4,18 +4,16 @@ const createError = require("../common/parser-create-error.js"); const getLast = require("../utils/get-last.js"); const parseFrontMatter = require("../utils/front-matter/parse.js"); const { hasPragma } = require("./pragma.js"); -const { - hasSCSSInterpolation, - hasStringOrFunction, - isLessParser, - isSCSS, - isSCSSNestedPropertyNode, - isSCSSVariable, - stringifyNode, - isModuleRuleName, -} = require("./utils.js"); const { locStart, locEnd } = require("./loc.js"); const { calculateLoc, replaceQuotesInInlineComments } = require("./loc.js"); +const hasSCSSInterpolation = require("./utils/has-SCSS-interpolation.js"); +const hasStringOrFunction = require("./utils/has-string-or-function.js"); +const isLessParser = require("./utils/is-less-parser.js"); +const isSCSS = require("./utils/is-scss.js"); +const isSCSSNestedPropertyNode = require("./utils/is-SCSS-nested-property-node.js"); +const isSCSSVariable = require("./utils/is-SCSS-variable.js"); +const stringifyNode = require("./utils/stringify-node.js"); +const isModuleRuleName = require("./utils/is-module-rule-name.js"); const getHighestAncestor = (node) => { while (node.parent) { diff --git a/src/language-css/printer-postcss.js b/src/language-css/printer-postcss.js index 5758ba818..d33763415 100644 --- a/src/language-css/printer-postcss.js +++ b/src/language-css/printer-postcss.js @@ -38,9 +38,7 @@ const { insideURLFunctionInImportAtRuleNode, isKeyframeAtRuleKeywords, isWideKeywords, - isSCSS, isLastNode, - isLessParser, isSCSSControlDirectiveNode, isDetachedRulesetDeclarationNode, isRelationalOperatorNode, @@ -76,8 +74,10 @@ const { isAtWordPlaceholderNode, isConfigurationNode, isParenGroupNode, -} = require("./utils.js"); +} = require("./utils/index.js"); const { locStart, locEnd } = require("./loc.js"); +const isLessParser = require("./utils/is-less-parser.js"); +const isSCSS = require("./utils/is-scss.js"); function shouldPrintComma(options) { return options.trailingComma === "es5" || options.trailingComma === "all"; diff --git a/src/language-css/utils/has-SCSS-interpolation.js b/src/language-css/utils/has-SCSS-interpolation.js new file mode 100644 index 000000000..0ef726e18 --- /dev/null +++ b/src/language-css/utils/has-SCSS-interpolation.js @@ -0,0 +1,22 @@ +"use strict"; + +const isNonEmptyArray = require("../../utils/is-non-empty-array.js"); + +function hasSCSSInterpolation(groupList) { + if (isNonEmptyArray(groupList)) { + for (let i = groupList.length - 1; i > 0; i--) { + // If we find `#{`, return true. + if ( + groupList[i].type === "word" && + groupList[i].value === "{" && + groupList[i - 1].type === "word" && + groupList[i - 1].value.endsWith("#") + ) { + return true; + } + } + } + return false; +} + +module.exports = hasSCSSInterpolation; diff --git a/src/language-css/utils/has-string-or-function.js b/src/language-css/utils/has-string-or-function.js new file mode 100644 index 000000000..d11bde837 --- /dev/null +++ b/src/language-css/utils/has-string-or-function.js @@ -0,0 +1,16 @@ +"use strict"; + +const isNonEmptyArray = require("../../utils/is-non-empty-array.js"); + +function hasStringOrFunction(groupList) { + if (isNonEmptyArray(groupList)) { + for (let i = 0; i < groupList.length; i++) { + if (groupList[i].type === "string" || groupList[i].type === "func") { + return true; + } + } + } + return false; +} + +module.exports = hasStringOrFunction; diff --git a/src/language-css/utils.js b/src/language-css/utils/index.js similarity index 79% rename from src/language-css/utils.js rename to src/language-css/utils/index.js index 775a4ee21..efcf7f625 100644 --- a/src/language-css/utils.js +++ b/src/language-css/utils/index.js @@ -1,6 +1,5 @@ "use strict"; -const { isNonEmptyArray } = require("../common/util.js"); const colorAdjusterFunctions = new Set([ "red", "green", @@ -28,7 +27,6 @@ const colorAdjusterFunctions = new Set([ "hwb", "hwba", ]); -const moduleRuleNames = new Set(["import", "use", "forward"]); function getAncestorCounter(path, typeOrTypes) { const types = Array.isArray(typeOrTypes) ? typeOrTypes : [typeOrTypes]; @@ -60,46 +58,6 @@ function getPropOfDeclNode(path) { ); } -function hasSCSSInterpolation(groupList) { - if (isNonEmptyArray(groupList)) { - for (let i = groupList.length - 1; i > 0; i--) { - // If we find `#{`, return true. - if ( - groupList[i].type === "word" && - groupList[i].value === "{" && - groupList[i - 1].type === "word" && - groupList[i - 1].value.endsWith("#") - ) { - return true; - } - } - } - return false; -} - -function hasStringOrFunction(groupList) { - if (isNonEmptyArray(groupList)) { - for (let i = 0; i < groupList.length; i++) { - if (groupList[i].type === "string" || groupList[i].type === "func") { - return true; - } - } - } - return false; -} - -function isSCSS(parser, text) { - const hasExplicitParserChoice = parser === "less" || parser === "scss"; - const IS_POSSIBLY_SCSS = /(?:\w\s*:\s*[^:}]+|#){|@import[^\n]+(?:url|,)/; - return hasExplicitParserChoice - ? parser === "scss" - : IS_POSSIBLY_SCSS.test(text); -} - -function isSCSSVariable(node) { - return Boolean(node && node.type === "word" && node.value.startsWith("$")); -} - function isWideKeywords(value) { return ["initial", "inherit", "unset", "revert"].includes( value.toLowerCase() @@ -267,19 +225,6 @@ function isSCSSControlDirectiveNode(node) { ); } -function isSCSSNestedPropertyNode(node) { - /* istanbul ignore next */ - if (!node.selector) { - return false; - } - - return node.selector - .replace(/\/\*.*?\*\//, "") - .replace(/\/\/.*\n/, "") - .trim() - .endsWith(":"); -} - function isDetachedRulesetCallNode(node) { return node.raws && node.raws.params && /^\(\s*\)$/.test(node.raws.params); } @@ -434,44 +379,10 @@ function isColorAdjusterFuncNode(node) { return colorAdjusterFunctions.has(node.value.toLowerCase()); } -// TODO: only check `less` when we don't use `less` to parse `css` -function isLessParser(options) { - return options.parser === "css" || options.parser === "less"; -} - function lastLineHasInlineComment(text) { return /\/\//.test(text.split(/[\n\r]/).pop()); } -function stringifyNode(node) { - if (node.groups) { - const open = node.open && node.open.value ? node.open.value : ""; - const groups = node.groups.reduce( - (previousValue, currentValue, index) => - previousValue + - stringifyNode(currentValue) + - (node.groups[0].type === "comma_group" && - index !== node.groups.length - 1 - ? "," - : ""), - "" - ); - const close = node.close && node.close.value ? node.close.value : ""; - - return open + groups + close; - } - - const before = node.raws && node.raws.before ? node.raws.before : ""; - const quote = node.raws && node.raws.quote ? node.raws.quote : ""; - const atword = node.type === "atword" ? "@" : ""; - const value = node.value ? node.value : ""; - const unit = node.unit ? node.unit : ""; - const group = node.group ? stringifyNode(node.group) : ""; - const after = node.raws && node.raws.after ? node.raws.after : ""; - - return before + quote + atword + value + quote + unit + group + after; -} - function isAtWordPlaceholderNode(node) { return ( node && @@ -480,10 +391,6 @@ function isAtWordPlaceholderNode(node) { ); } -function isModuleRuleName(name) { - return moduleRuleNames.has(name); -} - function isConfigurationNode(node, parentNode) { if ( !node.open || @@ -522,8 +429,6 @@ module.exports = { getAncestorCounter, getAncestorNode, getPropOfDeclNode, - hasSCSSInterpolation, - hasStringOrFunction, maybeToLowerCase, insideValueFunctionNode, insideICSSRuleNode, @@ -531,10 +436,7 @@ module.exports = { insideURLFunctionInImportAtRuleNode, isKeyframeAtRuleKeywords, isWideKeywords, - isSCSS, - isSCSSVariable, isLastNode, - isLessParser, isSCSSControlDirectiveNode, isDetachedRulesetDeclarationNode, isRelationalOperatorNode, @@ -552,7 +454,6 @@ module.exports = { hasComposesNode, hasParensAroundNode, hasEmptyRawBefore, - isSCSSNestedPropertyNode, isDetachedRulesetCallNode, isTemplatePlaceholderNode, isTemplatePropNode, @@ -570,9 +471,7 @@ module.exports = { isMediaAndSupportsKeywords, isColorAdjusterFuncNode, lastLineHasInlineComment, - stringifyNode, isAtWordPlaceholderNode, - isModuleRuleName, isConfigurationNode, isParenGroupNode, }; diff --git a/src/language-css/utils/is-SCSS-nested-property-node.js b/src/language-css/utils/is-SCSS-nested-property-node.js new file mode 100644 index 000000000..c1bd11af1 --- /dev/null +++ b/src/language-css/utils/is-SCSS-nested-property-node.js @@ -0,0 +1,16 @@ +"use strict"; + +function isSCSSNestedPropertyNode(node) { + /* istanbul ignore next */ + if (!node.selector) { + return false; + } + + return node.selector + .replace(/\/\*.*?\*\//, "") + .replace(/\/\/.*\n/, "") + .trim() + .endsWith(":"); +} + +module.exports = isSCSSNestedPropertyNode; diff --git a/src/language-css/utils/is-SCSS-variable.js b/src/language-css/utils/is-SCSS-variable.js new file mode 100644 index 000000000..9529028a5 --- /dev/null +++ b/src/language-css/utils/is-SCSS-variable.js @@ -0,0 +1,7 @@ +"use strict"; + +function isSCSSVariable(node) { + return Boolean(node && node.type === "word" && node.value.startsWith("$")); +} + +module.exports = isSCSSVariable; diff --git a/src/language-css/utils/is-less-parser.js b/src/language-css/utils/is-less-parser.js new file mode 100644 index 000000000..df2a58318 --- /dev/null +++ b/src/language-css/utils/is-less-parser.js @@ -0,0 +1,8 @@ +"use strict"; + +// TODO: only check `less` when we don't use `less` to parse `css` +function isLessParser(options) { + return options.parser === "css" || options.parser === "less"; +} + +module.exports = isLessParser; diff --git a/src/language-css/utils/is-module-rule-name.js b/src/language-css/utils/is-module-rule-name.js new file mode 100644 index 000000000..8ee9c47d8 --- /dev/null +++ b/src/language-css/utils/is-module-rule-name.js @@ -0,0 +1,9 @@ +"use strict"; + +const moduleRuleNames = new Set(["import", "use", "forward"]); + +function isModuleRuleName(name) { + return moduleRuleNames.has(name); +} + +module.exports = isModuleRuleName; diff --git a/src/language-css/utils/is-scss.js b/src/language-css/utils/is-scss.js new file mode 100644 index 000000000..41a42b188 --- /dev/null +++ b/src/language-css/utils/is-scss.js @@ -0,0 +1,11 @@ +"use strict"; + +function isSCSS(parser, text) { + const hasExplicitParserChoice = parser === "less" || parser === "scss"; + const IS_POSSIBLY_SCSS = /(?:\w\s*:\s*[^:}]+|#){|@import[^\n]+(?:url|,)/; + return hasExplicitParserChoice + ? parser === "scss" + : IS_POSSIBLY_SCSS.test(text); +} + +module.exports = isSCSS; diff --git a/src/language-css/utils/stringify-node.js b/src/language-css/utils/stringify-node.js new file mode 100644 index 000000000..f0fe3747f --- /dev/null +++ b/src/language-css/utils/stringify-node.js @@ -0,0 +1,32 @@ +"use strict"; + +function stringifyNode(node) { + if (node.groups) { + const open = node.open && node.open.value ? node.open.value : ""; + const groups = node.groups.reduce( + (previousValue, currentValue, index) => + previousValue + + stringifyNode(currentValue) + + (node.groups[0].type === "comma_group" && + index !== node.groups.length - 1 + ? "," + : ""), + "" + ); + const close = node.close && node.close.value ? node.close.value : ""; + + return open + groups + close; + } + + const before = node.raws && node.raws.before ? node.raws.before : ""; + const quote = node.raws && node.raws.quote ? node.raws.quote : ""; + const atword = node.type === "atword" ? "@" : ""; + const value = node.value ? node.value : ""; + const unit = node.unit ? node.unit : ""; + const group = node.group ? stringifyNode(node.group) : ""; + const after = node.raws && node.raws.after ? node.raws.after : ""; + + return before + quote + atword + value + quote + unit + group + after; +} + +module.exports = stringifyNode;