From 9bce51f651aad297ef9eb6df832bfdaf1de05d84 Mon Sep 17 00:00:00 2001
From: WXL <wl_5969728@163.com>
Date: 星期三, 22 四月 2026 14:27:54 +0800
Subject: [PATCH] 青岛推送
---
node_modules/webpack/lib/css/CssParser.js | 1605 +++++++++++++++++++++++++++++++++++++++++-----------------
1 files changed, 1,131 insertions(+), 474 deletions(-)
diff --git a/node_modules/webpack/lib/css/CssParser.js b/node_modules/webpack/lib/css/CssParser.js
index 4ae35d8..488095e 100644
--- a/node_modules/webpack/lib/css/CssParser.js
+++ b/node_modules/webpack/lib/css/CssParser.js
@@ -7,7 +7,6 @@
const vm = require("vm");
const CommentCompilationWarning = require("../CommentCompilationWarning");
-const CssModule = require("../CssModule");
const ModuleDependencyWarning = require("../ModuleDependencyWarning");
const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");
const Parser = require("../Parser");
@@ -15,11 +14,7 @@
const WebpackError = require("../WebpackError");
const ConstDependency = require("../dependencies/ConstDependency");
const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
-const CssIcssFromIdentifierDependency = require("../dependencies/CssIcssFromIdentifierDependency");
-const CssIcssGlobalIdentifierDependency = require("../dependencies/CssIcssGlobalIdentifierDependency");
const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
-const CssIcssLocalIdentifierDependency = require("../dependencies/CssIcssLocalIdentifierDependency");
-const CssIcssSelfLocalIdentifierDependency = require("../dependencies/CssIcssSelfLocalIdentifierDependency");
const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
const CssImportDependency = require("../dependencies/CssImportDependency");
const CssUrlDependency = require("../dependencies/CssUrlDependency");
@@ -37,7 +32,8 @@
/** @typedef {import("../Parser").ParserState} ParserState */
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
/** @typedef {import("./walkCssTokens").CssTokenCallbacks} CssTokenCallbacks */
-/** @typedef {import("../../declarations/WebpackOptions").CssParserExportType} CssParserExportType */
+/** @typedef {import("../../declarations/WebpackOptions").CssModuleParserOptions} CssModuleParserOptions */
+/** @typedef {import("../CssModule")} CssModule */
/** @typedef {[number, number]} Range */
/** @typedef {{ line: number, column: number }} Position */
@@ -46,28 +42,53 @@
const CC_COLON = ":".charCodeAt(0);
const CC_SEMICOLON = ";".charCodeAt(0);
const CC_COMMA = ",".charCodeAt(0);
-const CC_SLASH = "/".charCodeAt(0);
const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);
const CC_RIGHT_PARENTHESIS = ")".charCodeAt(0);
const CC_LOWER_F = "f".charCodeAt(0);
const CC_UPPER_F = "F".charCodeAt(0);
const CC_RIGHT_CURLY = "}".charCodeAt(0);
+const CC_HYPHEN_MINUS = "-".charCodeAt(0);
+const CC_TILDE = "~".charCodeAt(0);
+const CC_EQUAL = "=".charCodeAt(0);
+const CC_FULL_STOP = ".".charCodeAt(0);
+const CC_EXCLAMATION = "!".charCodeAt(0);
// https://www.w3.org/TR/css-syntax-3/#newline
// We don't have `preprocessing` stage, so we need specify all of them
const STRING_MULTILINE = /\\[\n\r\f]/g;
// https://www.w3.org/TR/css-syntax-3/#whitespace
const TRIM_WHITE_SPACES = /(^[ \t\n\r\f]*|[ \t\n\r\f]*$)/g;
-const UNESCAPE = /\\([0-9a-fA-F]{1,6}[ \t\n\r\f]?|[\s\S])/g;
-const IMAGE_SET_FUNCTION = /^(-\w+-)?image-set$/i;
-const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
-const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
- /^(-\w+-)?animation(-name)?$/i;
-const COMPOSES_PROPERTY = /^(composes|compose-with)$/i;
-const IS_MODULES = /\.module(s)?\.[^.]+$/i;
-const CSS_COMMENT = /\/\*((?!\*\/).*?)\*\//g;
+const UNESCAPE = /\\([0-9a-f]{1,6}[ \t\n\r\f]?|[\s\S])/gi;
+const IMAGE_SET_FUNCTION = /^(?:-\w+-)?image-set$/i;
+const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(?:-\w+-)?keyframes$/;
+const COMPOSES_PROPERTY = /^(?:composes|compose-with)$/i;
+const IS_MODULES = /\.modules?\.[^.]+$/i;
+const CSS_COMMENT = /\/\*((?!\*\/)[\s\S]*?)\*\//g;
/**
+ * Returns matches.
+ * @param {RegExp} regexp a regexp
+ * @param {string} str a string
+ * @returns {RegExpExecArray[]} matches
+ */
+const matchAll = (regexp, str) => {
+ /** @type {RegExpExecArray[]} */
+ const result = [];
+
+ /** @type {null | RegExpExecArray} */
+ let match;
+
+ // Use a while loop with exec() to find all matches
+ while ((match = regexp.exec(str)) !== null) {
+ result.push(match);
+ }
+ // Return an array to be easily iterable (note: a true spec-compliant polyfill
+ // returns an iterator object, but an array spread often suffices for basic use)
+ return result;
+};
+
+/**
+ * Returns normalized url.
* @param {string} str url string
* @param {boolean} isString is url wrapped in quotes
* @returns {string} normalized url
@@ -107,12 +128,12 @@
return str;
};
-// eslint-disable-next-line no-useless-escape
-const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/;
+const regexSingleEscape = /[ -,./:-@[\]^`{-~]/;
const regexExcessiveSpaces =
/(^|\\+)?(\\[A-F0-9]{1,6})\u0020(?![a-fA-F0-9\u0020])/g;
/**
+ * Returns escaped identifier.
* @param {string} str string
* @returns {string} escaped identifier
*/
@@ -123,10 +144,10 @@
while (counter < str.length) {
const character = str.charAt(counter++);
+ /** @type {string} */
let value;
- // eslint-disable-next-line no-control-regex
- if (/[\t\n\f\r\u000B]/.test(character)) {
+ if (/[\t\n\f\r\v]/.test(character)) {
const codePoint = character.charCodeAt(0);
value = `\\${codePoint.toString(16).toUpperCase()} `;
@@ -166,6 +187,7 @@
const CONTAINS_ESCAPE = /\\/;
/**
+ * Returns hex.
* @param {string} str string
* @returns {[string, number] | undefined} hex
*/
@@ -203,6 +225,7 @@
};
/**
+ * Unescape identifier.
* @param {string} str string
* @returns {string} unescaped string
*/
@@ -238,32 +261,90 @@
return ret;
};
+/**
+ * A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.
+ * The <custom-property-name> production corresponds to this:
+ * it鈥檚 defined as any <dashed-ident> (a valid identifier that starts with two dashes),
+ * except -- itself, which is reserved for future use by CSS.
+ * @param {string} identifier identifier
+ * @returns {boolean} true when identifier is dashed, otherwise false
+ */
+const isDashedIdentifier = (identifier) =>
+ identifier.startsWith("--") && identifier.length >= 3;
+
/** @type {Record<string, number>} */
-const ANIMATION_KEYWORDS = {
- // animation-direction
- normal: 1,
- reverse: 1,
- alternate: 1,
- "alternate-reverse": 1,
- // animation-fill-mode
- forwards: 1,
- backwards: 1,
- both: 1,
- // animation-iteration-count
- infinite: 1,
- // animation-play-state
- paused: 1,
- running: 1,
- // animation-timing-function
- ease: 1,
- "ease-in": 1,
- "ease-out": 1,
- "ease-in-out": 1,
- linear: 1,
- "step-end": 1,
- "step-start": 1,
- // Special
- none: Infinity, // No matter how many times you write none, it will never be an animation name
+const PREDEFINED_COUNTER_STYLES = {
+ decimal: 1,
+ "decimal-leading-zero": 1,
+ "arabic-indic": 1,
+ armenian: 1,
+ "upper-armenian": 1,
+ "lower-armenian": 1,
+ bengali: 1,
+ cambodian: 1,
+ khmer: 1,
+ "cjk-decimal": 1,
+ devanagari: 1,
+ georgian: 1,
+ gujarati: 1,
+ /* cspell:disable-next-line */
+ gurmukhi: 1,
+ hebrew: 1,
+ kannada: 1,
+ lao: 1,
+ malayalam: 1,
+ mongolian: 1,
+ myanmar: 1,
+ oriya: 1,
+ persian: 1,
+ "lower-roman": 1,
+ "upper-roman": 1,
+ tamil: 1,
+ telugu: 1,
+ thai: 1,
+ tibetan: 1,
+
+ "lower-alpha": 1,
+ "lower-latin": 1,
+ "upper-alpha": 1,
+ "upper-latin": 1,
+ "lower-greek": 1,
+ hiragana: 1,
+ /* cspell:disable-next-line */
+ "hiragana-iroha": 1,
+ katakana: 1,
+ /* cspell:disable-next-line */
+ "katakana-iroha": 1,
+
+ disc: 1,
+ circle: 1,
+ square: 1,
+ "disclosure-open": 1,
+ "disclosure-closed": 1,
+
+ "cjk-earthly-branch": 1,
+ "cjk-heavenly-stem": 1,
+
+ "japanese-informal": 1,
+ "japanese-formal": 1,
+
+ "korean-hangul-formal": 1,
+ /* cspell:disable-next-line */
+ "korean-hanja-informal": 1,
+ /* cspell:disable-next-line */
+ "korean-hanja-formal": 1,
+
+ "simp-chinese-informal": 1,
+ "simp-chinese-formal": 1,
+ "trad-chinese-informal": 1,
+ "trad-chinese-formal": 1,
+ "cjk-ideographic": 1,
+
+ "ethiopic-numeric": 1
+};
+
+/** @type {Record<string, number>} */
+const GLOBAL_VALUES = {
// Global values
initial: Infinity,
inherit: Infinity,
@@ -272,8 +353,187 @@
"revert-layer": Infinity
};
+/** @type {Record<string, number>} */
+const GRID_AREA_OR_COLUMN_OR_ROW = {
+ auto: Infinity,
+ span: Infinity,
+ ...GLOBAL_VALUES
+};
+
+/** @type {Record<string, number>} */
+const GRID_AUTO_COLUMNS_OR_ROW = {
+ "min-content": Infinity,
+ "max-content": Infinity,
+ auto: Infinity,
+ ...GLOBAL_VALUES
+};
+
+/** @type {Record<string, number>} */
+const GRID_AUTO_FLOW = {
+ row: 1,
+ column: 1,
+ dense: 1,
+ ...GLOBAL_VALUES
+};
+
+/** @type {Record<string, number>} */
+const GRID_TEMPLATE_AREAS = {
+ // Special
+ none: 1,
+ ...GLOBAL_VALUES
+};
+
+/** @type {Record<string, number>} */
+const GRID_TEMPLATE_COLUMNS_OR_ROWS = {
+ none: 1,
+ subgrid: 1,
+ masonry: 1,
+ "max-content": Infinity,
+ "min-content": Infinity,
+ auto: Infinity,
+ ...GLOBAL_VALUES
+};
+
+/** @type {Record<string, number>} */
+const GRID_TEMPLATE = {
+ ...GRID_TEMPLATE_AREAS,
+ ...GRID_TEMPLATE_COLUMNS_OR_ROWS
+};
+
+/** @type {Record<string, number>} */
+const GRID = {
+ "auto-flow": 1,
+ dense: 1,
+ ...GRID_AUTO_COLUMNS_OR_ROW,
+ ...GRID_AUTO_FLOW,
+ ...GRID_TEMPLATE_AREAS,
+ ...GRID_TEMPLATE_COLUMNS_OR_ROWS
+};
+
+/**
+ * Gets known properties.
+ * @param {{ animation?: boolean, container?: boolean, customIdents?: boolean, grid?: boolean }=} options options
+ * @returns {Map<string, Record<string, number>>} list of known properties
+ */
+const getKnownProperties = (options = {}) => {
+ /** @type {Map<string, Record<string, number>>} */
+ const knownProperties = new Map();
+
+ if (options.animation) {
+ knownProperties.set("animation", {
+ // animation-direction
+ normal: 1,
+ reverse: 1,
+ alternate: 1,
+ "alternate-reverse": 1,
+ // animation-fill-mode
+ forwards: 1,
+ backwards: 1,
+ both: 1,
+ // animation-iteration-count
+ infinite: 1,
+ // animation-play-state
+ paused: 1,
+ running: 1,
+ // animation-timing-function
+ ease: 1,
+ "ease-in": 1,
+ "ease-out": 1,
+ "ease-in-out": 1,
+ linear: 1,
+ "step-end": 1,
+ "step-start": 1,
+ // Special
+ none: Infinity, // No matter how many times you write none, it will never be an animation name
+ ...GLOBAL_VALUES
+ });
+ knownProperties.set("animation-name", {
+ // Special
+ none: Infinity, // No matter how many times you write none, it will never be an animation name
+ ...GLOBAL_VALUES
+ });
+ }
+
+ if (options.container) {
+ knownProperties.set("container", {
+ // container-type
+ normal: 1,
+ size: 1,
+ "inline-size": 1,
+ "scroll-state": 1,
+ // Special
+ none: Infinity,
+ ...GLOBAL_VALUES
+ });
+ knownProperties.set("container-name", {
+ // Special
+ none: Infinity,
+ ...GLOBAL_VALUES
+ });
+ }
+
+ if (options.customIdents) {
+ knownProperties.set("list-style", {
+ // list-style-position
+ inside: 1,
+ outside: 1,
+ // list-style-type
+ ...PREDEFINED_COUNTER_STYLES,
+ // Special
+ none: Infinity,
+ ...GLOBAL_VALUES
+ });
+ knownProperties.set("list-style-type", {
+ // list-style-type
+ ...PREDEFINED_COUNTER_STYLES,
+ // Special
+ none: Infinity,
+ ...GLOBAL_VALUES
+ });
+ knownProperties.set("system", {
+ cyclic: 1,
+ numeric: 1,
+ alphabetic: 1,
+ symbolic: 1,
+ additive: 1,
+ fixed: 1,
+ extends: 1,
+ ...PREDEFINED_COUNTER_STYLES
+ });
+ knownProperties.set("fallback", {
+ ...PREDEFINED_COUNTER_STYLES
+ });
+ knownProperties.set("speak-as", {
+ auto: 1,
+ bullets: 1,
+ numbers: 1,
+ words: 1,
+ "spell-out": 1,
+ ...PREDEFINED_COUNTER_STYLES
+ });
+ }
+
+ if (options.grid) {
+ knownProperties.set("grid", GRID);
+ knownProperties.set("grid-area", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-column", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-column-end", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-column-start", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-row", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-row-end", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-row-start", GRID_AREA_OR_COLUMN_OR_ROW);
+ knownProperties.set("grid-template", GRID_TEMPLATE);
+ knownProperties.set("grid-template-areas", GRID_TEMPLATE_AREAS);
+ knownProperties.set("grid-template-columns", GRID_TEMPLATE_COLUMNS_OR_ROWS);
+ knownProperties.set("grid-template-rows", GRID_TEMPLATE_COLUMNS_OR_ROWS);
+ }
+
+ return knownProperties;
+};
+
class LocConverter {
/**
+ * Creates an instance of LocConverter.
* @param {string} input input
*/
constructor(input) {
@@ -284,6 +544,7 @@
}
/**
+ * Returns location converter.
* @param {number} pos position
* @returns {LocConverter} location converter
*/
@@ -323,42 +584,48 @@
const CSS_MODE_TOP_LEVEL = 0;
const CSS_MODE_IN_BLOCK = 1;
+const LOCAL_MODE = 0;
+const GLOBAL_MODE = 1;
+
const eatUntilSemi = walkCssTokens.eatUntil(";");
const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
-const eatSemi = walkCssTokens.eatUntil(";");
/**
- * @typedef {object} CssParserOptions
- * @property {boolean=} importOption need handle `@import`
- * @property {boolean=} url need handle URLs
+ * Defines the css parser own options type used by this module.
+ * @typedef {object} CssParserOwnOptions
* @property {("pure" | "global" | "local" | "auto")=} defaultMode default mode
- * @property {boolean=} namedExports is named exports
- * @property {CssParserExportType=} exportType export type
*/
+
+/** @typedef {CssModuleParserOptions & CssParserOwnOptions} CssParserOptions */
class CssParser extends Parser {
/**
+ * Creates an instance of CssParser.
* @param {CssParserOptions=} options options
*/
- constructor({
- defaultMode = "pure",
- importOption = true,
- url = true,
- namedExports = true,
- exportType
- } = {}) {
+ constructor(options = {}) {
super();
- this.defaultMode = defaultMode;
- this.import = importOption;
- this.url = url;
- this.namedExports = namedExports;
- this.exportType = exportType;
+ this.defaultMode =
+ typeof options.defaultMode !== "undefined" ? options.defaultMode : "pure";
+ this.options = {
+ url: true,
+ import: true,
+ namedExports: true,
+ animation: true,
+ container: true,
+ customIdents: true,
+ dashedIdents: true,
+ function: true,
+ grid: true,
+ ...options
+ };
/** @type {Comment[] | undefined} */
this.comments = undefined;
this.magicCommentContext = createMagicCommentContext();
}
/**
+ * Processes the provided state.
* @param {ParserState} state parser state
* @param {string} message warning message
* @param {LocConverter} locConverter location converter
@@ -378,6 +645,7 @@
}
/**
+ * Parses the provided source and updates the parser state.
* @param {string | Buffer | PreparsedAst} source the source to parse
* @param {ParserState} state the parser state
* @returns {ParserState} the parser state
@@ -407,6 +675,12 @@
}
const isModules = mode === "global" || mode === "local";
+ const knownProperties = getKnownProperties({
+ animation: this.options.animation,
+ container: this.options.container,
+ customIdents: this.options.customIdents,
+ grid: this.options.grid
+ });
/** @type {BuildMeta} */
(module.buildMeta).isCSSModule = isModules;
@@ -417,7 +691,7 @@
let scope = CSS_MODE_TOP_LEVEL;
/** @type {boolean} */
let allowImportAtRule = true;
- /** @type {[string, number, number][]} */
+ /** @type {[string, number, number, boolean?][]} */
const balanced = [];
let lastTokenEndForComments = 0;
@@ -425,78 +699,59 @@
let isNextRulePrelude = isModules;
/** @type {number} */
let blockNestingLevel = 0;
- /** @type {"local" | "global" | undefined} */
+ /** @type {0 | 1 | undefined} */
let modeData;
- /** @type {Set<string>} */
- const declaredCssVariables = new Set();
+ /** @type {number} */
+ let counter = 0;
/** @type {string[]} */
let lastLocalIdentifiers = [];
- /** @typedef {{ value: string, isReference?: boolean }} IcssDefinition */
+ /** @typedef {{ value?: string, importName?: string, localName?: string }} IcssDefinition */
/** @type {Map<string, IcssDefinition>} */
const icssDefinitions = new Map();
/**
+ * Checks whether this css parser is next nested syntax.
* @param {string} input input
* @param {number} pos position
* @returns {boolean} true, when next is nested syntax
*/
const isNextNestedSyntax = (input, pos) => {
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
- if (input[pos] === "}") {
+ if (
+ input.charCodeAt(pos) === CC_RIGHT_CURLY ||
+ (input.charCodeAt(pos) === CC_HYPHEN_MINUS &&
+ input.charCodeAt(pos + 1) === CC_HYPHEN_MINUS)
+ ) {
return false;
}
- // According spec only identifier can be used as a property name
- const isIdentifier = walkCssTokens.isIdentStartCodePoint(
- input.charCodeAt(pos)
- );
+ const identifier = walkCssTokens.eatIdentSequence(input, pos);
- return !isIdentifier;
+ if (!identifier) {
+ return true;
+ }
+
+ const leftCurly = eatUntilLeftCurly(input, pos);
+ const content = input.slice(identifier[0], leftCurly);
+
+ if (content.includes(";") || content.includes("}")) {
+ return false;
+ }
+
+ return true;
};
/**
+ * Checks whether this css parser is local mode.
* @returns {boolean} true, when in local scope
*/
const isLocalMode = () =>
- modeData === "local" || (mode === "local" && modeData === undefined);
+ modeData === LOCAL_MODE || (mode === "local" && modeData === undefined);
/**
- * @param {string} input input
- * @param {number} pos start position
- * @param {(input: string, pos: number) => number} eater eater
- * @returns {[number,string]} new position and text
- */
- const eatText = (input, pos, eater) => {
- let text = "";
- for (;;) {
- if (input.charCodeAt(pos) === CC_SLASH) {
- const newPos = walkCssTokens.eatComments(input, pos);
- if (pos !== newPos) {
- pos = newPos;
- if (pos === input.length) break;
- } else {
- text += "/";
- pos++;
- if (pos === input.length) break;
- }
- }
- const newPos = eater(input, pos);
- if (pos !== newPos) {
- text += input.slice(pos, newPos);
- pos = newPos;
- } else {
- break;
- }
- if (pos === input.length) break;
- }
- return [pos, text.trimEnd()];
- };
-
- const eatPropertyName = walkCssTokens.eatUntil(":{};");
-
- /**
+ * Returns end.
* @param {string} input input
* @param {number} start start
* @param {number} end end
@@ -523,6 +778,7 @@
// Vanilla CSS stuff
/**
+ * Processes the provided input.
* @param {string} input input
* @param {number} start name start position
* @param {number} end name end position
@@ -591,12 +847,14 @@
return newline;
}
+ /** @type {undefined | string} */
let layer;
if (tokens[1]) {
layer = input.slice(tokens[1][0] + 6, tokens[1][1] - 1).trim();
}
+ /** @type {undefined | string} */
let supports;
if (tokens[2]) {
@@ -604,8 +862,12 @@
}
const last = tokens[2] || tokens[1] || tokens[0];
- const mediaStart = walkCssTokens.eatWhitespaceAndComments(input, last[1]);
+ const mediaStart = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ last[1]
+ )[0];
+ /** @type {undefined | string} */
let media;
if (mediaStart !== semi - 1) {
@@ -629,6 +891,7 @@
};
/**
+ * Process url function.
* @param {string} input input
* @param {number} end end position
* @param {string} name the name of function
@@ -691,6 +954,7 @@
};
/**
+ * Process old url function.
* @param {string} input input
* @param {number} start start position
* @param {number} end end position
@@ -753,6 +1017,7 @@
};
/**
+ * Process image set function.
* @param {string} input input
* @param {number} start start position
* @param {number} end end position
@@ -817,13 +1082,48 @@
// CSS modules stuff
/**
+ * Returns resolved reexport (localName and importName).
+ * @param {string} value value to resolve
+ * @param {string=} localName override local name
+ * @param {boolean=} isCustomProperty true when it is custom property, otherwise false
+ * @returns {string | [string, string]} resolved reexport (`localName` and `importName`)
+ */
+ const getReexport = (value, localName, isCustomProperty) => {
+ const reexport = icssDefinitions.get(
+ isCustomProperty ? `--${value}` : value
+ );
+
+ if (reexport) {
+ if (reexport.importName) {
+ return [
+ reexport.localName || (isCustomProperty ? `--${value}` : value),
+ reexport.importName
+ ];
+ }
+
+ if (isCustomProperty) {
+ return /** @type {string} */ (reexport.value).slice(2);
+ }
+
+ return /** @type {string} */ (reexport.value);
+ }
+
+ if (localName) {
+ return [localName, value];
+ }
+
+ return value;
+ };
+
+ /**
+ * Process import or export.
* @param {0 | 1} type import or export
* @param {string} input input
* @param {number} pos start position
* @returns {number} position after parse
*/
const processImportOrExport = (type, input, pos) => {
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
/** @type {string | undefined} */
let request;
if (type === 0) {
@@ -844,7 +1144,7 @@
if (!str) {
this._emitWarning(
state,
- `Unexpected '${input[pos]}' at ${pos} during parsing of '${type ? ":import" : ":export"}' (expected string)`,
+ `Unexpected '${input[pos]}' at ${pos} during parsing of '${type === 0 ? ":import" : ":export"}' (expected string)`,
locConverter,
stringStart,
pos
@@ -853,7 +1153,7 @@
}
request = input.slice(str[0] + 1, str[1] - 1);
pos = str[1];
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
cc = input.charCodeAt(pos);
if (cc !== CC_RIGHT_PARENTHESIS) {
this._emitWarning(
@@ -866,10 +1166,11 @@
return pos;
}
pos++;
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
}
/**
+ * Creates a dep from the provided name.
* @param {string} name name
* @param {string} value value
* @param {number} start start of position
@@ -883,22 +1184,17 @@
[0, 0],
/** @type {"local" | "global"} */
(mode),
- value
+ value,
+ name
);
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
dep.setLoc(sl, sc, el, ec);
module.addDependency(dep);
- icssDefinitions.set(name, { value, isReference: true });
+ icssDefinitions.set(name, { importName: value });
} else if (type === 1) {
- const reexport = icssDefinitions.get(value);
- const dep = new CssIcssExportDependency(
- name,
- value,
- reexport && reexport.isReference ? reexport.value : undefined,
- undefined
- );
+ const dep = new CssIcssExportDependency(name, getReexport(value));
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
dep.setLoc(sl, sc, el, ec);
@@ -989,7 +1285,79 @@
return pos;
};
+ /** @typedef {{ from: string, items: ({ localName: string, importName: string })[] }} ValueAtRuleImport */
+ /** @typedef {{ localName: string, value: string }} ValueAtRuleValue */
/**
+ * Parses value at rule params.
+ * @param {string} str value at-rule params
+ * @returns {ValueAtRuleImport | ValueAtRuleValue} parsed result
+ */
+ const parseValueAtRuleParams = (str) => {
+ if (/from(\/\*|\s)(?:[\s\S]+)$/i.test(str)) {
+ str = str.replace(CSS_COMMENT, " ").trim().replace(/;$/, "");
+ const fromIdx = str.lastIndexOf("from");
+ const path = str
+ .slice(fromIdx + 5)
+ .trim()
+ .replace(/['"]/g, "");
+ let content = str.slice(0, fromIdx).trim();
+
+ if (content.startsWith("(") && content.endsWith(")")) {
+ content = content.slice(1, -1);
+ }
+
+ return {
+ from: path,
+ items: content.split(",").map((item) => {
+ item = item.trim();
+
+ if (item.includes(":")) {
+ const [local, remote] = item.split(":");
+
+ return { localName: local.trim(), importName: remote.trim() };
+ }
+
+ const asParts = item.split(/\s+as\s+/);
+
+ if (asParts.length === 2) {
+ return {
+ localName: asParts[1].trim(),
+ importName: asParts[0].trim()
+ };
+ }
+
+ return { localName: item, importName: item };
+ })
+ };
+ }
+
+ /** @type {string} */
+ let localName;
+ /** @type {string} */
+ let value;
+
+ const idx = str.indexOf(":");
+
+ if (idx !== -1) {
+ localName = str.slice(0, idx).replace(CSS_COMMENT, "").trim();
+ value = str.slice(idx + 1);
+ } else {
+ const mask = str.replace(CSS_COMMENT, (m) => " ".repeat(m.length));
+ const idx = mask.search(/\S\s/) + 1;
+
+ localName = str.slice(0, idx).replace(CSS_COMMENT, "").trim();
+ value = str.slice(idx + (str[idx] === " " ? 1 : 0));
+ }
+
+ if (value.length > 0 && !/^\s+$/.test(value.replace(CSS_COMMENT, ""))) {
+ value = value.trim();
+ }
+
+ return { localName, value };
+ };
+
+ /**
+ * Processes the provided input.
* @param {string} input input
* @param {number} start name start position
* @param {number} end name end position
@@ -999,83 +1367,12 @@
const semi = eatUntilSemi(input, end);
const atRuleEnd = semi + 1;
const params = input.slice(end, semi);
- let [alias, request] = params.split(/\s*from\s*/);
+ const parsed = parseValueAtRuleParams(params);
- if (request) {
- const aliases = alias
- .replace(CSS_COMMENT, " ")
- .trim()
- .replace(/^\(\s*|\s*\)$/g, "")
- .split(/\s*,\s*/);
-
- request = request.replace(CSS_COMMENT, "").trim();
-
- const isExplicitImport = request[0] === "'" || request[0] === '"';
-
- if (isExplicitImport) {
- request = request.slice(1, -1);
- }
-
- for (const alias of aliases) {
- const [name, aliasName] = alias.split(/\s+as\s+/);
-
- {
- const reexport = icssDefinitions.get(request);
-
- if (reexport) {
- request = reexport.value.slice(1, -1);
- }
-
- const dep = new CssIcssImportDependency(
- request,
- [0, 0],
- /** @type {"local" | "global"} */
- (mode),
- name
- );
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
-
- icssDefinitions.set(aliasName || name, {
- value: name,
- isReference: true
- });
- }
-
- if (aliasName) {
- const reexport = icssDefinitions.get(aliasName);
- const dep = new CssIcssExportDependency(
- aliasName,
- name,
- reexport && reexport.isReference ? reexport.value : undefined,
- undefined
- );
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- }
-
- {
- const reexport = icssDefinitions.get(name);
- const dep = new CssIcssExportDependency(
- name,
- name,
- reexport && reexport.isReference ? reexport.value : undefined,
- undefined
- );
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- }
- }
- } else {
- const ident = walkCssTokens.eatIdentSequence(alias, 0);
-
- if (!ident) {
+ if (
+ typeof (/** @type {ValueAtRuleImport} */ (parsed).from) !== "undefined"
+ ) {
+ if (/** @type {ValueAtRuleImport} */ (parsed).from.length === 0) {
this._emitWarning(
state,
`Broken '@value' at-rule: ${input.slice(start, atRuleEnd)}'`,
@@ -1089,33 +1386,87 @@
return atRuleEnd;
}
- const pos = walkCssTokens.eatWhitespaceAndComments(alias, ident[1]);
+ let { from, items } = /** @type {ValueAtRuleImport} */ (parsed);
- const name = alias.slice(ident[0], ident[1]);
- let value =
- alias.charCodeAt(pos) === CC_COLON
- ? alias.slice(pos + 1)
- : alias.slice(ident[1]);
+ for (const { importName, localName } of items) {
+ {
+ const reexport = icssDefinitions.get(from);
- if (value && !/^\s+$/.test(value.replace(CSS_COMMENT, ""))) {
- value = value.trim();
+ if (reexport && reexport.value) {
+ from = reexport.value.slice(1, -1);
+ }
+
+ const dep = new CssIcssImportDependency(
+ from,
+ [0, 0],
+ /** @type {"local" | "global"} */
+ (mode),
+ importName,
+ localName
+ );
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+
+ icssDefinitions.set(localName, { importName });
+ }
+
+ {
+ const dep = new CssIcssExportDependency(
+ localName,
+ getReexport(localName),
+ undefined,
+ false,
+ CssIcssExportDependency.EXPORT_MODE.REPLACE
+ );
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ }
}
+ } else {
+ if (/** @type {ValueAtRuleValue} */ (parsed).localName.length === 0) {
+ this._emitWarning(
+ state,
+ `Broken '@value' at-rule: ${input.slice(start, atRuleEnd)}'`,
+ locConverter,
+ start,
+ atRuleEnd
+ );
+
+ const dep = new ConstDependency("", [start, atRuleEnd]);
+ module.addPresentationalDependency(dep);
+ return atRuleEnd;
+ }
+
+ const { localName, value } = /** @type {ValueAtRuleValue} */ (parsed);
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
if (icssDefinitions.has(value)) {
const def =
/** @type {IcssDefinition} */
(icssDefinitions.get(value));
- value = def.value;
+ def.localName = value;
+
+ icssDefinitions.set(localName, def);
+
+ const dep = new CssIcssExportDependency(
+ localName,
+ getReexport(value)
+ );
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ } else {
+ icssDefinitions.set(localName, { value });
+
+ const dep = new CssIcssExportDependency(localName, value);
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
}
-
- icssDefinitions.set(name, { value });
-
- const dep = new CssIcssExportDependency(name, value);
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
}
const dep = new ConstDependency("", [start, atRuleEnd]);
@@ -1124,22 +1475,23 @@
};
/**
+ * Process icss symbol.
* @param {string} name ICSS symbol name
* @param {number} start start position
* @param {number} end end position
* @returns {number} position after handling
*/
const processICSSSymbol = (name, start, end) => {
- const { value, isReference } =
+ const def =
/** @type {IcssDefinition} */
(icssDefinitions.get(name));
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
const dep = new CssIcssSymbolDependency(
- name,
- value,
+ def.localName || name,
[start, end],
- isReference
+ def.value,
+ def.importName
);
dep.setLoc(sl, sc, el, ec);
module.addDependency(dep);
@@ -1147,6 +1499,7 @@
};
/**
+ * Process local or global function.
* @param {string} input input
* @param {1 | 2} type type of function
* @param {number} start start position
@@ -1164,23 +1517,36 @@
end = walkCssTokens.consumeUntil(
input,
start,
- type === 1
- ? {
- identifier(input, start, end) {
- const name = unescapeIdentifier(input.slice(start, end));
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- const dep = new CssIcssLocalIdentifierDependency(name, [
- start,
- end
- ]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
+ {
+ identifier(input, start, end) {
+ if (type === 1) {
+ let identifier = unescapeIdentifier(input.slice(start, end));
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
+ const isDashedIdent = isDashedIdentifier(identifier);
- return end;
+ if (isDashedIdent) {
+ identifier = identifier.slice(2);
}
+
+ const dep = new CssIcssExportDependency(
+ identifier,
+ getReexport(identifier),
+ [start, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE,
+ isDashedIdent
+ ? CssIcssExportDependency.EXPORT_TYPE.CUSTOM_VARIABLE
+ : CssIcssExportDependency.EXPORT_TYPE.NORMAL
+ );
+
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
}
- : {},
+
+ return end;
+ }
+ },
{},
{ onlyTopLevel: true, functionValue: true }
);
@@ -1195,37 +1561,72 @@
};
/**
+ * Process local at rule.
* @param {string} input input
* @param {number} end name end position
- * @param {{ string?: boolean, identifier: boolean, validate?: (name: string) => boolean, dashed?: boolean }} options types which allowed to handle
+ * @param {{ string?: boolean, identifier?: boolean | RegExp }} options types which allowed to handle
* @returns {number} position after handling
*/
const processLocalAtRule = (input, end, options) => {
- /** @type {[number, number, boolean] | undefined} */
- let value;
let found = false;
- walkCssTokens.consumeUntil(
+ return walkCssTokens.consumeUntil(
input,
end,
{
string(_input, start, end) {
if (!found && options.string) {
+ const value = unescapeIdentifier(input.slice(start + 1, end - 1));
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
+ const dep = new CssIcssExportDependency(
+ value,
+ value,
+ [start, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE
+ );
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
found = true;
- value = [start, end, true];
}
return end;
},
- identifier(_input, start, end) {
- if (!found && options.identifier) {
- found = true;
- value = [start, end, false];
+ identifier(input, start, end) {
+ if (!found) {
+ const value = input.slice(start, end);
+
+ if (options.identifier) {
+ const identifier = unescapeIdentifier(value);
+
+ if (
+ options.identifier instanceof RegExp &&
+ options.identifier.test(identifier)
+ ) {
+ return end;
+ }
+
+ const { line: sl, column: sc } = locConverter.get(start);
+ const { line: el, column: ec } = locConverter.get(end);
+
+ const dep = new CssIcssExportDependency(
+ identifier,
+ getReexport(identifier),
+ [start, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE,
+ CssIcssExportDependency.EXPORT_TYPE.NORMAL
+ );
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ found = true;
+ }
}
return end;
}
},
{
- function(input, start, end) {
+ function: (input, start, end) => {
// No need to handle `:` (COLON), because it's always a function
const name = input
.slice(start, end - 1)
@@ -1240,53 +1641,37 @@
return processLocalOrGlobalFunction(input, type, start, end);
}
+ if (
+ this.options.dashedIdents &&
+ isLocalMode() &&
+ (name === "var" || name === "style")
+ ) {
+ return processDashedIdent(input, end, end);
+ }
+
return end;
}
},
{ onlyTopLevel: true, atRulePrelude: true }
);
- if (!value) return end;
- let name = value[2]
- ? input.slice(value[0] + 1, value[1] - 1)
- : input.slice(value[0], value[1]);
- if (options.validate && !options.validate(name)) return end;
- name = unescapeIdentifier(name);
- const { line: sl, column: sc } = locConverter.get(value[0]);
- const { line: el, column: ec } = locConverter.get(value[1]);
- if (options.dashed) {
- name = name.slice(2);
- declaredCssVariables.add(name);
- }
- const dep = new CssIcssLocalIdentifierDependency(
- name,
- [value[0], value[1]],
- options.dashed ? "--" : ""
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return value[1];
};
/**
+ * Process dashed ident.
* @param {string} input input
+ * @param {number} start start position
* @param {number} end end position
* @returns {number} position after handling
*/
- const processVarFunction = (input, end) => {
- const customIdent = walkCssTokens.eatIdentSequence(input, end);
+ const processDashedIdent = (input, start, end) => {
+ const customIdent = walkCssTokens.eatIdentSequence(input, start);
if (!customIdent) return end;
- let name = input.slice(customIdent[0], customIdent[1]);
- // A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.
- // The <custom-property-name> production corresponds to this:
- // it鈥檚 defined as any <dashed-ident> (a valid identifier that starts with two dashes),
- // except -- itself, which is reserved for future use by CSS.
- if (!name.startsWith("--") || name.length < 3) return end;
- name = unescapeIdentifier(
+ const identifier = unescapeIdentifier(
input.slice(customIdent[0] + 2, customIdent[1])
);
const afterCustomIdent = walkCssTokens.eatWhitespaceAndComments(
input,
customIdent[1]
- );
+ )[0];
if (
input.charCodeAt(afterCustomIdent) === CC_LOWER_F ||
input.charCodeAt(afterCustomIdent) === CC_UPPER_F
@@ -1303,7 +1688,7 @@
}
const from = walkCssTokens.eatIdentSequenceOrString(
input,
- walkCssTokens.eatWhitespaceAndComments(input, fromWord[1])
+ walkCssTokens.eatWhitespaceAndComments(input, fromWord[1])[0]
);
if (!from) {
return end;
@@ -1316,18 +1701,35 @@
} else if (from[2] === false) {
const { line: sl, column: sc } = locConverter.get(customIdent[0]);
const { line: el, column: ec } = locConverter.get(from[1] - 1);
- const dep = new CssIcssFromIdentifierDependency(
- path.slice(1, -1),
- /** @type {"local" | "global"} */
- (mode),
- [customIdent[0], from[1] - 1],
- name,
- name,
- "--"
- );
+ const localName = `__ICSS_IMPORT_${counter++}__`;
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
+ {
+ const dep = new CssIcssImportDependency(
+ path.slice(1, -1),
+ [customIdent[0], from[1] - 1],
+ /** @type {"local" | "global"} */
+ (mode),
+ identifier,
+ localName
+ );
+
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ }
+
+ {
+ const dep = new CssIcssExportDependency(
+ identifier,
+ getReexport(identifier, localName, true),
+ [customIdent[0], from[1] - 1],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE,
+ CssIcssExportDependency.EXPORT_TYPE.CUSTOM_VARIABLE
+ );
+
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ }
{
const dep = new ConstDependency("", [fromWord[0], from[1]]);
@@ -1338,12 +1740,13 @@
} else {
const { line: sl, column: sc } = locConverter.get(customIdent[0]);
const { line: el, column: ec } = locConverter.get(customIdent[1]);
- const dep = new CssIcssSelfLocalIdentifierDependency(
- name,
- undefined,
+ const dep = new CssIcssExportDependency(
+ identifier,
+ getReexport(identifier, undefined, true),
[customIdent[0], customIdent[1]],
- "--",
- declaredCssVariables
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE,
+ CssIcssExportDependency.EXPORT_TYPE.CUSTOM_VARIABLE
);
dep.setLoc(sl, sc, el, ec);
module.addDependency(dep);
@@ -1353,86 +1756,148 @@
return end;
};
/**
+ * Process local declaration.
* @param {string} input input
* @param {number} pos name start position
* @param {number} end name end position
* @returns {number} position after handling
*/
const processLocalDeclaration = (input, pos, end) => {
- modeData = undefined;
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
- const propertyNameStart = pos;
- const [propertyNameEnd, propertyName] = eatText(
- input,
- pos,
- eatPropertyName
- );
- if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return end;
- pos = propertyNameEnd + 1;
- if (propertyName.startsWith("--") && propertyName.length >= 3) {
- // CSS Variable
- const { line: sl, column: sc } = locConverter.get(propertyNameStart);
- const { line: el, column: ec } = locConverter.get(propertyNameEnd);
- const name = unescapeIdentifier(propertyName.slice(2));
- const dep = new CssIcssLocalIdentifierDependency(
- name,
- [propertyNameStart, propertyNameEnd],
- "--"
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- declaredCssVariables.add(name);
- } else if (
- OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
- ) {
- /** @type {[number, number, boolean][]} */
- const animationNames = [];
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
+ const identifier = walkCssTokens.eatIdentSequence(input, pos);
+
+ if (!identifier) {
+ return end;
+ }
+
+ const propertyNameStart = identifier[0];
+
+ pos = walkCssTokens.eatWhitespaceAndComments(input, identifier[1])[0];
+
+ if (input.charCodeAt(pos) !== CC_COLON) {
+ return end;
+ }
+
+ pos += 1;
+
+ // Remove prefix and lowercase
+ const propertyName = input
+ .slice(identifier[0], identifier[1])
+ .replace(/^(-\w+-)/, "")
+ .toLowerCase();
+
+ if (isLocalMode() && knownProperties.has(propertyName)) {
+ /** @type {[number, number, boolean?][]} */
+ const values = [];
/** @type {Record<string, number>} */
- let parsedAnimationKeywords = Object.create(null);
+ let parsedKeywords = Object.create(null);
+
+ const isGridProperty = Boolean(propertyName.startsWith("grid"));
+ const isGridTemplate = isGridProperty
+ ? Boolean(
+ propertyName === "grid" ||
+ propertyName === "grid-template" ||
+ propertyName === "grid-template-columns" ||
+ propertyName === "grid-template-rows"
+ )
+ : false;
+
+ let afterExclamation = false;
const end = walkCssTokens.consumeUntil(
input,
pos,
{
+ delim(input, start, end) {
+ afterExclamation = input.charCodeAt(start) === CC_EXCLAMATION;
+ return end;
+ },
+ leftSquareBracket(input, start, end) {
+ let i = end;
+
+ while (true) {
+ i = walkCssTokens.eatWhitespaceAndComments(input, i)[0];
+ const name = walkCssTokens.eatIdentSequence(input, i);
+
+ if (!name) {
+ break;
+ }
+
+ values.push(name);
+ i = name[1];
+ }
+
+ return end;
+ },
string(_input, start, end) {
- animationNames.push([start, end, true]);
+ if (
+ propertyName === "animation" ||
+ propertyName === "animation-name"
+ ) {
+ values.push([start, end, true]);
+ }
+
+ if (
+ propertyName === "grid" ||
+ propertyName === "grid-template" ||
+ propertyName === "grid-template-areas"
+ ) {
+ const areas = unescapeIdentifier(
+ input.slice(start + 1, end - 1)
+ );
+ const matches = matchAll(/\b\w+\b/g, areas);
+
+ for (const match of matches) {
+ const areaStart = start + 1 + match.index;
+ values.push([areaStart, areaStart + match[0].length, false]);
+ }
+ }
return end;
},
identifier(input, start, end) {
- const keyword = input.slice(start, end).toLowerCase();
+ if (isGridTemplate) {
+ return end;
+ }
- parsedAnimationKeywords[keyword] =
- typeof parsedAnimationKeywords[keyword] !== "undefined"
- ? parsedAnimationKeywords[keyword] + 1
+ if (afterExclamation) {
+ afterExclamation = false;
+ return end;
+ }
+
+ const identifier = input.slice(start, end);
+ const keyword = identifier.toLowerCase();
+
+ parsedKeywords[keyword] =
+ typeof parsedKeywords[keyword] !== "undefined"
+ ? parsedKeywords[keyword] + 1
: 0;
+ const keywords =
+ /** @type {Record<string, number>} */
+ (knownProperties.get(propertyName));
if (
- ANIMATION_KEYWORDS[keyword] &&
- parsedAnimationKeywords[keyword] < ANIMATION_KEYWORDS[keyword]
+ keywords[keyword] &&
+ parsedKeywords[keyword] < keywords[keyword]
) {
return end;
}
- animationNames.push([start, end, false]);
+ values.push([start, end]);
return end;
},
comma(_input, _start, end) {
- parsedAnimationKeywords = {};
+ parsedKeywords = {};
return end;
}
},
{
- function(input, start, end) {
+ function: (input, start, end) => {
const name = input
.slice(start, end - 1)
.replace(/\\/g, "")
.toLowerCase();
-
- if (isLocalMode() && name === "var") {
- return processVarFunction(input, end);
- }
const type =
name === "local" ? 1 : name === "global" ? 2 : undefined;
@@ -1441,26 +1906,50 @@
return processLocalOrGlobalFunction(input, type, start, end);
}
+ if (
+ this.options.dashedIdents &&
+ isLocalMode() &&
+ name === "var"
+ ) {
+ return processDashedIdent(input, end, end);
+ }
+
+ if (this.options.url) {
+ if (name === "src" || name === "url") {
+ return processURLFunction(input, end, name);
+ } else if (IMAGE_SET_FUNCTION.test(name)) {
+ return processImageSetFunction(input, start, end);
+ }
+ }
+
return end;
}
},
- { onlyTopLevel: true, declarationValue: true }
+ {
+ onlyTopLevel: !isGridTemplate,
+ declarationValue: true
+ }
);
- if (animationNames.length > 0) {
- for (const animationName of animationNames) {
- const { line: sl, column: sc } = locConverter.get(animationName[0]);
- const { line: el, column: ec } = locConverter.get(animationName[1]);
- const [start, end, isString] = animationName;
+ if (values.length > 0) {
+ for (const value of values) {
+ const { line: sl, column: sc } = locConverter.get(value[0]);
+ const { line: el, column: ec } = locConverter.get(value[1]);
+ const [start, end, isString] = value;
const name = unescapeIdentifier(
isString
? input.slice(start + 1, end - 1)
: input.slice(start, end)
);
- const dep = new CssIcssSelfLocalIdentifierDependency(
+ const dep = new CssIcssExportDependency(
name,
- undefined,
- [start, end]
+ getReexport(name),
+ [start, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE,
+ isGridProperty
+ ? CssIcssExportDependency.EXPORT_TYPE.GRID_CUSTOM_IDENTIFIER
+ : CssIcssExportDependency.EXPORT_TYPE.NORMAL
);
dep.setLoc(sl, sc, el, ec);
module.addDependency(dep);
@@ -1491,7 +1980,7 @@
const classNames = new Set();
while (true) {
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
+ pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
let className = walkCssTokens.eatIdentSequence(input, pos);
@@ -1509,14 +1998,20 @@
pos = walkCssTokens.eatWhitespaceAndComments(
input,
className[1] + 1
- );
+ )[0];
className = walkCssTokens.eatIdentSequence(input, pos);
if (className) {
- pos = walkCssTokens.eatWhitespaceAndComments(input, className[1]);
+ pos = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ className[1]
+ )[0];
pos += 1;
}
} else if (className) {
- pos = walkCssTokens.eatWhitespaceAndComments(input, className[1]);
+ pos = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ className[1]
+ )[0];
pos = className[1];
}
@@ -1533,26 +2028,16 @@
for (const className of classNames) {
const [start, end] = className;
const identifier = unescapeIdentifier(input.slice(start, end));
- const reexport = icssDefinitions.get(identifier);
- const dep = isGlobalFunction
- ? new CssIcssGlobalIdentifierDependency(
- lastLocalIdentifier,
- identifier,
- reexport && reexport.isReference
- ? reexport.value
- : undefined,
- [start, end]
- )
- : new CssIcssSelfLocalIdentifierDependency(
- lastLocalIdentifier,
- identifier,
- [start, end],
- undefined,
- undefined,
- reexport && reexport.isReference
- ? reexport.value
- : undefined
- );
+ const dep = new CssIcssExportDependency(
+ lastLocalIdentifier,
+ getReexport(identifier),
+ [start, end],
+ !isGlobalFunction,
+ isGlobalFunction
+ ? CssIcssExportDependency.EXPORT_MODE.APPEND
+ : CssIcssExportDependency.EXPORT_MODE.SELF_REFERENCE,
+ CssIcssExportDependency.EXPORT_TYPE.COMPOSES
+ );
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
dep.setLoc(sl, sc, el, ec);
@@ -1582,19 +2067,35 @@
for (const className of classNames) {
const [start, end] = className;
const identifier = unescapeIdentifier(input.slice(start, end));
- const dep = new CssIcssFromIdentifierDependency(
- request,
- /** @type {"local" | "global"} */
- (mode),
- [start, end],
- identifier,
- /** @type {string} */
- (lastLocalIdentifier)
- );
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
+ const localName = `__ICSS_IMPORT_${counter++}__`;
+
+ {
+ const dep = new CssIcssImportDependency(
+ request,
+ [start, end],
+ /** @type {"local" | "global"} */
+ (mode),
+ identifier,
+ localName
+ );
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ }
+
+ {
+ const dep = new CssIcssExportDependency(
+ lastLocalIdentifier,
+ getReexport(identifier, localName),
+ [start, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.APPEND,
+ CssIcssExportDependency.EXPORT_TYPE.COMPOSES
+ );
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ }
}
classNames.clear();
@@ -1608,15 +2109,14 @@
const identifier = unescapeIdentifier(
input.slice(start, end)
);
- const reexport = icssDefinitions.get(identifier);
- const dep = new CssIcssGlobalIdentifierDependency(
+ const dep = new CssIcssExportDependency(
/** @type {string} */
(lastLocalIdentifier),
- identifier,
- reexport && reexport.isReference
- ? reexport.value
- : undefined,
- [start, end]
+ getReexport(identifier),
+ [start, end],
+ false,
+ CssIcssExportDependency.EXPORT_MODE.APPEND,
+ CssIcssExportDependency.EXPORT_TYPE.COMPOSES
);
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
@@ -1657,24 +2157,122 @@
const dep = new ConstDependency("", [propertyNameStart, end]);
module.addPresentationalDependency(dep);
}
+
return pos;
};
/**
+ * Process id selector.
* @param {string} input input
* @param {number} start start position
* @param {number} end end position
* @returns {number} position after handling
*/
- const processHashID = (input, start, end) => {
+ const processIdSelector = (input, start, end) => {
const valueStart = start + 1;
const name = unescapeIdentifier(input.slice(valueStart, end));
- const dep = new CssIcssLocalIdentifierDependency(name, [valueStart, end]);
+ const dep = new CssIcssExportDependency(
+ name,
+ getReexport(name),
+ [valueStart, end],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE
+ );
const { line: sl, column: sc } = locConverter.get(start);
const { line: el, column: ec } = locConverter.get(end);
dep.setLoc(sl, sc, el, ec);
module.addDependency(dep);
return end;
+ };
+
+ /**
+ * Process class selector.
+ * @param {string} input input
+ * @param {number} start start position
+ * @param {number} end end position
+ * @returns {number} position after handling
+ */
+ const processClassSelector = (input, start, end) => {
+ const ident = walkCssTokens.skipCommentsAndEatIdentSequence(input, end);
+ if (!ident) return end;
+ const name = unescapeIdentifier(input.slice(ident[0], ident[1]));
+ lastLocalIdentifiers.push(name);
+ const dep = new CssIcssExportDependency(
+ name,
+ getReexport(name),
+ [ident[0], ident[1]],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.ONCE
+ );
+ const { line: sl, column: sc } = locConverter.get(ident[0]);
+ const { line: el, column: ec } = locConverter.get(ident[1]);
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ return ident[1];
+ };
+
+ /**
+ * Process attribute selector.
+ * @param {string} input input
+ * @param {number} start start position
+ * @param {number} end end position
+ * @returns {number} position after handling
+ */
+ const processAttributeSelector = (input, start, end) => {
+ end = walkCssTokens.eatWhitespaceAndComments(input, end)[0];
+ const identifier = walkCssTokens.eatIdentSequence(input, end);
+ if (!identifier) return end;
+ const name = unescapeIdentifier(
+ input.slice(identifier[0], identifier[1])
+ );
+ if (name.toLowerCase() !== "class") {
+ return end;
+ }
+ end = walkCssTokens.eatWhitespaceAndComments(input, identifier[1])[0];
+
+ const isTilde = input.charCodeAt(end) === CC_TILDE;
+
+ if (
+ input.charCodeAt(end) !== CC_EQUAL &&
+ input.charCodeAt(end) !== CC_TILDE
+ ) {
+ return end;
+ }
+
+ end += 1;
+
+ if (isTilde) {
+ if (input.charCodeAt(end) !== CC_EQUAL) {
+ return end;
+ }
+
+ end += 1;
+ }
+
+ end = walkCssTokens.eatWhitespaceAndComments(input, end)[0];
+ const value = walkCssTokens.eatIdentSequenceOrString(input, end);
+
+ if (!value) {
+ return end;
+ }
+
+ const classNameStart = value[2] ? value[0] : value[0] + 1;
+ const classNameEnd = value[2] ? value[1] : value[1] - 1;
+ const className = unescapeIdentifier(
+ input.slice(classNameStart, classNameEnd)
+ );
+ const dep = new CssIcssExportDependency(
+ className,
+ getReexport(className),
+ [classNameStart, classNameEnd],
+ true,
+ CssIcssExportDependency.EXPORT_MODE.NONE
+ );
+ const { line: sl, column: sc } = locConverter.get(classNameStart);
+ const { line: el, column: ec } = locConverter.get(classNameEnd);
+ dep.setLoc(sl, sc, el, ec);
+ module.addDependency(dep);
+ return value[2] ? classNameEnd : classNameEnd + 1;
};
walkCssTokens(source, 0, {
@@ -1722,7 +2320,7 @@
return end;
},
url: (input, start, end, contentStart, contentEnd) => {
- if (!this.url) {
+ if (!this.options.url) {
return end;
}
@@ -1749,9 +2347,32 @@
return eatUntilSemi(input, start);
}
+ case "@charset": {
+ const atRuleEnd = eatUntilSemi(input, start);
+
+ if (/** @type {CssModule} */ (module).exportType === "style") {
+ return atRuleEnd;
+ }
+
+ const dep = new ConstDependency("", [start, atRuleEnd + 1]);
+ module.addPresentationalDependency(dep);
+
+ const value = walkCssTokens.eatString(input, end);
+
+ if (!value) {
+ return atRuleEnd;
+ }
+
+ /** @type {BuildInfo} */
+ (module.buildInfo).charset = input
+ .slice(value[0] + 1, value[1] - 1)
+ .toUpperCase();
+
+ return atRuleEnd;
+ }
case "@import": {
- if (!this.import) {
- return eatSemi(input, end);
+ if (!this.options.import) {
+ return eatUntilSemi(input, end);
}
if (!allowImportAtRule) {
@@ -1762,7 +2383,7 @@
start,
end
);
- return end;
+ return eatUntilSemi(input, end);
}
return processAtImport(input, start, end);
@@ -1772,6 +2393,7 @@
if (name === "@value") {
return processAtValue(input, start, end);
} else if (
+ this.options.animation &&
OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) &&
isLocalMode()
) {
@@ -1779,11 +2401,21 @@
string: true,
identifier: true
});
- } else if (name === "@property" && isLocalMode()) {
+ } else if (
+ this.options.customIdents &&
+ name === "@counter-style" &&
+ isLocalMode()
+ ) {
return processLocalAtRule(input, end, {
- identifier: true,
- dashed: true,
- validate: (name) => name.startsWith("--") && name.length >= 3
+ identifier: true
+ });
+ } else if (
+ this.options.container &&
+ name === "@container" &&
+ isLocalMode()
+ ) {
+ return processLocalAtRule(input, end, {
+ identifier: /^(none|and|or|not)$/
});
} else if (name === "@scope") {
isNextRulePrelude = true;
@@ -1805,15 +2437,23 @@
},
identifier: (input, start, end) => {
if (isModules) {
- const name = input.slice(start, end);
+ const identifier = input.slice(start, end);
- if (icssDefinitions.has(name)) {
- return processICSSSymbol(name, start, end);
+ if (
+ this.options.dashedIdents &&
+ isLocalMode() &&
+ isDashedIdentifier(identifier)
+ ) {
+ return processDashedIdent(input, start, end);
+ }
+
+ if (icssDefinitions.has(identifier)) {
+ return processICSSSymbol(identifier, start, end);
}
switch (scope) {
case CSS_MODE_IN_BLOCK: {
- if (isLocalMode()) {
+ if (isModules && !isNextRulePrelude) {
// Handle only top level values and not inside functions
return processLocalDeclaration(input, start, end);
}
@@ -1825,30 +2465,19 @@
return end;
},
delim: (input, start, end) => {
- if (isNextRulePrelude && isLocalMode()) {
- const ident = walkCssTokens.skipCommentsAndEatIdentSequence(
- input,
- end
- );
- if (!ident) return end;
- const name = unescapeIdentifier(input.slice(ident[0], ident[1]));
- lastLocalIdentifiers.push(name);
- const dep = new CssIcssLocalIdentifierDependency(name, [
- ident[0],
- ident[1]
- ]);
- const { line: sl, column: sc } = locConverter.get(ident[0]);
- const { line: el, column: ec } = locConverter.get(ident[1]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return ident[1];
+ if (
+ input.charCodeAt(start) === CC_FULL_STOP &&
+ isNextRulePrelude &&
+ isLocalMode()
+ ) {
+ return processClassSelector(input, start, end);
}
return end;
},
hash: (input, start, end, isID) => {
if (isNextRulePrelude && isLocalMode() && isID) {
- return processHashID(input, start, end);
+ return processIdSelector(input, start, end);
}
return end;
@@ -1883,18 +2512,23 @@
if (isFn && name === "local") {
// Eat extra whitespace
- const end = walkCssTokens.eatWhitespace(input, ident[1] + 1);
- modeData = "local";
+ const end = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ ident[1] + 1
+ )[0];
+ modeData = LOCAL_MODE;
const dep = new ConstDependency("", [start, end]);
module.addPresentationalDependency(dep);
- balanced.push([":local", start, end]);
+ balanced.push([":local", start, end, true]);
return end;
} else if (name === "local") {
- modeData = "local";
- // Eat extra whitespace
- end = walkCssTokens.eatWhitespace(input, ident[1]);
+ modeData = LOCAL_MODE;
+ const found = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ ident[1]
+ );
- if (ident[1] === end) {
+ if (!found[1]) {
this._emitWarning(
state,
`Missing whitespace after ':local' in '${input.slice(
@@ -1907,23 +2541,30 @@
);
}
+ end = walkCssTokens.eatWhitespace(input, ident[1]);
const dep = new ConstDependency("", [start, end]);
module.addPresentationalDependency(dep);
return end;
} else if (isFn && name === "global") {
// Eat extra whitespace
- const end = walkCssTokens.eatWhitespace(input, ident[1] + 1);
- modeData = "global";
+ const end = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ ident[1] + 1
+ )[0];
+ modeData = GLOBAL_MODE;
const dep = new ConstDependency("", [start, end]);
module.addPresentationalDependency(dep);
- balanced.push([":global", start, end]);
+ balanced.push([":global", start, end, true]);
return end;
} else if (name === "global") {
- modeData = "global";
+ modeData = GLOBAL_MODE;
// Eat extra whitespace
- end = walkCssTokens.eatWhitespace(input, ident[1]);
+ const found = walkCssTokens.eatWhitespaceAndComments(
+ input,
+ ident[1]
+ );
- if (ident[1] === end) {
+ if (!found[1]) {
this._emitWarning(
state,
`Missing whitespace after ':global' in '${input.slice(
@@ -1936,6 +2577,7 @@
);
}
+ end = walkCssTokens.eatWhitespace(input, ident[1]);
const dep = new ConstDependency("", [start, end]);
module.addPresentationalDependency(dep);
return end;
@@ -1960,21 +2602,42 @@
switch (name) {
case "src":
case "url": {
- if (!this.url) {
+ if (!this.options.url) {
return end;
}
return processURLFunction(input, end, name);
}
default: {
- if (this.url && IMAGE_SET_FUNCTION.test(name)) {
+ if (this.options.url && IMAGE_SET_FUNCTION.test(name)) {
return processImageSetFunction(input, start, end);
- } else if (isLocalMode() && name === "var") {
- return processVarFunction(input, end);
+ }
+
+ if (isModules) {
+ if (
+ this.options.function &&
+ isLocalMode() &&
+ isDashedIdentifier(name)
+ ) {
+ return processDashedIdent(input, start, end);
+ }
+
+ const type =
+ name === "local" ? 1 : name === "global" ? 2 : undefined;
+
+ if (type && !isNextRulePrelude) {
+ return processLocalOrGlobalFunction(input, type, start, end);
+ }
}
}
}
+ return end;
+ },
+ leftSquareBracket: (input, start, end) => {
+ if (isNextRulePrelude && isLocalMode()) {
+ return processAttributeSelector(input, start, end);
+ }
return end;
},
leftParenthesis: (input, start, end) => {
@@ -1985,29 +2648,35 @@
rightParenthesis: (input, start, end) => {
const popped = balanced.pop();
- if (
- isModules &&
- popped &&
- (popped[0] === ":local" || popped[0] === ":global")
- ) {
- modeData = balanced[balanced.length - 1]
- ? /** @type {"local" | "global"} */
- (balanced[balanced.length - 1][0])
- : undefined;
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
+ if (isModules && popped) {
+ const isLocal = popped[0] === ":local";
+ const isGlobal = popped[0] === ":global";
+ if (isLocal || isGlobal) {
+ modeData = balanced[balanced.length - 1]
+ ? balanced[balanced.length - 1][0] === ":local"
+ ? LOCAL_MODE
+ : balanced[balanced.length - 1][0] === ":global"
+ ? GLOBAL_MODE
+ : undefined
+ : undefined;
+ if (popped[3] && isLocal) {
+ while (walkCssTokens.isWhiteSpace(input.charCodeAt(start - 1))) {
+ start -= 1;
+ }
+ }
+ const dep = new ConstDependency("", [start, end]);
+ module.addPresentationalDependency(dep);
+ } else if (isNextRulePrelude) {
+ modeData = undefined;
+ }
}
return end;
},
comma: (input, start, end) => {
- if (isModules) {
- const popped = balanced.pop();
-
- if (!popped) {
- // Reset stack for `:global .class :local .class-other` selector after
- modeData = undefined;
- }
+ if (isModules && balanced.length === 0) {
+ // Reset stack for `:global .class :local .class-other` selector after
+ modeData = undefined;
}
lastTokenEndForComments = start;
@@ -2021,29 +2690,14 @@
const buildMeta = /** @type {BuildMeta} */ (state.module.buildMeta);
- buildMeta.exportsType = this.namedExports ? "namespace" : "default";
- buildMeta.defaultObject = this.namedExports ? false : "redirect-warn";
- buildMeta.exportType = this.exportType;
+ buildMeta.exportsType = this.options.namedExports ? "namespace" : "default";
+ buildMeta.defaultObject = this.options.namedExports
+ ? false
+ : "redirect-warn";
- if (!buildMeta.exportType) {
- // Inherit exportType from parent module to ensure consistency.
- // When a CSS file is imported with syntax like `import "./basic.css" with { type: "css" }`,
- // the parent module's exportType is set to "css-style-sheet".
- // Child modules imported via @import should inherit this exportType
- // instead of using the default "link", ensuring that the entire
- // import chain uses the same export format.
- const parent = state.compilation.moduleGraph.getIssuer(module);
- if (parent instanceof CssModule) {
- buildMeta.exportType = /** @type {BuildMeta} */ (
- parent.buildMeta
- ).exportType;
- }
- }
-
- // TODO this.namedExports?
if (
- buildMeta.exportType === "text" ||
- buildMeta.exportType === "css-style-sheet"
+ /** @type {CssModule} */ (module).exportType === "text" ||
+ /** @type {CssModule} */ (module).exportType === "css-style-sheet"
) {
module.addDependency(new StaticExportsDependency(["default"], true));
} else {
@@ -2054,6 +2708,7 @@
}
/**
+ * Returns comments in the range.
* @param {Range} range range
* @returns {Comment[]} comments in the range
*/
@@ -2061,6 +2716,7 @@
if (!this.comments) return [];
const [rangeStart, rangeEnd] = range;
/**
+ * Returns compared.
* @param {Comment} comment comment
* @param {number} needle needle
* @returns {number} compared
@@ -2083,6 +2739,7 @@
}
/**
+ * Parses comment options.
* @param {Range} range range of the comment
* @returns {{ options: Record<string, EXPECTED_ANY> | null, errors: (Error & { comment: Comment })[] | null }} result
*/
@@ -2091,7 +2748,7 @@
if (comments.length === 0) {
return EMPTY_COMMENT_OPTIONS;
}
- /** @type {Record<string, EXPECTED_ANY> } */
+ /** @type {Record<string, EXPECTED_ANY>} */
const options = {};
/** @type {(Error & { comment: Comment })[]} */
const errors = [];
--
Gitblit v1.9.3