2021-11-30 19:55:51 +08:00
|
|
|
/*
|
|
|
|
MIT License http://www.opensource.org/licenses/mit-license.php
|
|
|
|
Author Tobias Koppers @sokra
|
|
|
|
*/
|
|
|
|
|
|
|
|
"use strict";
|
|
|
|
|
2023-05-02 18:12:41 +08:00
|
|
|
const ModuleDependencyWarning = require("../ModuleDependencyWarning");
|
2022-12-16 20:56:14 +08:00
|
|
|
const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");
|
2021-11-30 19:55:51 +08:00
|
|
|
const Parser = require("../Parser");
|
2023-05-02 18:12:41 +08:00
|
|
|
const WebpackError = require("../WebpackError");
|
2021-12-14 23:02:26 +08:00
|
|
|
const ConstDependency = require("../dependencies/ConstDependency");
|
|
|
|
const CssExportDependency = require("../dependencies/CssExportDependency");
|
2021-12-01 20:27:00 +08:00
|
|
|
const CssImportDependency = require("../dependencies/CssImportDependency");
|
2021-12-15 15:34:31 +08:00
|
|
|
const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");
|
2021-12-17 03:42:44 +08:00
|
|
|
const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
|
2021-12-01 21:15:19 +08:00
|
|
|
const CssUrlDependency = require("../dependencies/CssUrlDependency");
|
2021-11-30 19:55:51 +08:00
|
|
|
const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
|
2023-06-11 21:33:10 +08:00
|
|
|
const { parseResource } = require("../util/identifier");
|
2021-11-30 19:55:51 +08:00
|
|
|
const walkCssTokens = require("./walkCssTokens");
|
|
|
|
|
2024-10-01 03:05:27 +08:00
|
|
|
/** @typedef {import("../Module").BuildInfo} BuildInfo */
|
|
|
|
/** @typedef {import("../Module").BuildMeta} BuildMeta */
|
2021-11-30 19:55:51 +08:00
|
|
|
/** @typedef {import("../Parser").ParserState} ParserState */
|
|
|
|
/** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
|
2024-10-01 03:05:27 +08:00
|
|
|
|
2023-05-22 04:31:30 +08:00
|
|
|
/** @typedef {[number, number]} Range */
|
|
|
|
|
2021-12-14 23:02:26 +08:00
|
|
|
const CC_LEFT_CURLY = "{".charCodeAt(0);
|
|
|
|
const CC_RIGHT_CURLY = "}".charCodeAt(0);
|
|
|
|
const CC_COLON = ":".charCodeAt(0);
|
|
|
|
const CC_SLASH = "/".charCodeAt(0);
|
|
|
|
const CC_SEMICOLON = ";".charCodeAt(0);
|
|
|
|
|
2023-04-15 00:19:27 +08:00
|
|
|
// 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;
|
2023-04-13 07:27:04 +08:00
|
|
|
const UNESCAPE = /\\([0-9a-fA-F]{1,6}[ \t\n\r\f]?|[\s\S])/g;
|
2024-10-09 14:01:49 +08:00
|
|
|
const IMAGE_SET_FUNCTION = /^(-\w+-)?image-set$/i;
|
2023-04-17 00:43:06 +08:00
|
|
|
const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;
|
|
|
|
const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =
|
|
|
|
/^(-\w+-)?animation(-name)?$/i;
|
2023-06-20 00:06:01 +08:00
|
|
|
const IS_MODULES = /\.module(s)?\.[^.]+$/i;
|
2023-04-13 07:27:04 +08:00
|
|
|
|
2023-04-29 02:50:41 +08:00
|
|
|
/**
|
|
|
|
* @param {string} str url string
|
|
|
|
* @param {boolean} isString is url wrapped in quotes
|
|
|
|
* @returns {string} normalized url
|
|
|
|
*/
|
2023-04-13 07:27:04 +08:00
|
|
|
const normalizeUrl = (str, isString) => {
|
2023-04-13 07:36:01 +08:00
|
|
|
// Remove extra spaces and newlines:
|
2023-04-13 07:27:04 +08:00
|
|
|
// `url("im\
|
|
|
|
// g.png")`
|
|
|
|
if (isString) {
|
|
|
|
str = str.replace(STRING_MULTILINE, "");
|
|
|
|
}
|
|
|
|
|
2023-04-13 07:36:01 +08:00
|
|
|
str = str
|
|
|
|
// Remove unnecessary spaces from `url(" img.png ")`
|
|
|
|
.replace(TRIM_WHITE_SPACES, "")
|
|
|
|
// Unescape
|
|
|
|
.replace(UNESCAPE, match => {
|
|
|
|
if (match.length > 2) {
|
2024-08-02 02:36:27 +08:00
|
|
|
return String.fromCharCode(Number.parseInt(match.slice(1).trim(), 16));
|
2023-04-13 07:36:01 +08:00
|
|
|
}
|
2024-07-31 04:21:27 +08:00
|
|
|
return match[1];
|
2023-04-13 07:36:01 +08:00
|
|
|
});
|
|
|
|
|
|
|
|
if (/^data:/i.test(str)) {
|
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (str.includes("%")) {
|
2023-04-13 09:08:07 +08:00
|
|
|
// Convert `url('%2E/img.png')` -> `url('./img.png')`
|
2023-04-13 07:36:01 +08:00
|
|
|
try {
|
|
|
|
str = decodeURIComponent(str);
|
2024-07-31 15:37:05 +08:00
|
|
|
} catch (_err) {
|
2023-04-13 07:36:01 +08:00
|
|
|
// Ignore
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return str;
|
2021-11-30 19:55:51 +08:00
|
|
|
};
|
|
|
|
|
2021-12-01 21:15:19 +08:00
|
|
|
class LocConverter {
|
2023-04-29 02:50:41 +08:00
|
|
|
/**
|
|
|
|
* @param {string} input input
|
|
|
|
*/
|
2021-12-01 21:15:19 +08:00
|
|
|
constructor(input) {
|
|
|
|
this._input = input;
|
|
|
|
this.line = 1;
|
|
|
|
this.column = 0;
|
|
|
|
this.pos = 0;
|
|
|
|
}
|
|
|
|
|
2023-04-29 02:50:41 +08:00
|
|
|
/**
|
|
|
|
* @param {number} pos position
|
|
|
|
* @returns {LocConverter} location converter
|
|
|
|
*/
|
2021-12-01 21:15:19 +08:00
|
|
|
get(pos) {
|
|
|
|
if (this.pos !== pos) {
|
|
|
|
if (this.pos < pos) {
|
|
|
|
const str = this._input.slice(this.pos, pos);
|
|
|
|
let i = str.lastIndexOf("\n");
|
|
|
|
if (i === -1) {
|
|
|
|
this.column += str.length;
|
|
|
|
} else {
|
|
|
|
this.column = str.length - i - 1;
|
|
|
|
this.line++;
|
2021-12-03 02:29:55 +08:00
|
|
|
while (i > 0 && (i = str.lastIndexOf("\n", i - 1)) !== -1)
|
|
|
|
this.line++;
|
2021-12-01 21:15:19 +08:00
|
|
|
}
|
|
|
|
} else {
|
|
|
|
let i = this._input.lastIndexOf("\n", this.pos);
|
|
|
|
while (i >= pos) {
|
|
|
|
this.line--;
|
2021-12-03 02:29:55 +08:00
|
|
|
i = i > 0 ? this._input.lastIndexOf("\n", i - 1) : -1;
|
2021-12-01 21:15:19 +08:00
|
|
|
}
|
|
|
|
this.column = pos - i;
|
|
|
|
}
|
|
|
|
this.pos = pos;
|
|
|
|
}
|
|
|
|
return this;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-12-01 20:27:00 +08:00
|
|
|
const CSS_MODE_TOP_LEVEL = 0;
|
2023-05-05 07:49:09 +08:00
|
|
|
const CSS_MODE_IN_BLOCK = 1;
|
2023-05-20 00:05:14 +08:00
|
|
|
const CSS_MODE_IN_AT_IMPORT = 2;
|
|
|
|
const CSS_MODE_AT_IMPORT_INVALID = 3;
|
|
|
|
const CSS_MODE_AT_NAMESPACE_INVALID = 4;
|
2021-12-01 20:27:00 +08:00
|
|
|
|
2021-11-30 19:55:51 +08:00
|
|
|
class CssParser extends Parser {
|
2024-10-04 23:19:57 +08:00
|
|
|
/**
|
|
|
|
* @param {object} options options
|
|
|
|
* @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
|
|
|
|
* @param {boolean=} options.namedExports is named exports
|
|
|
|
*/
|
|
|
|
constructor({ defaultMode = "pure", namedExports = true } = {}) {
|
2021-11-30 19:55:51 +08:00
|
|
|
super();
|
2021-12-15 15:34:31 +08:00
|
|
|
this.defaultMode = defaultMode;
|
2024-01-13 18:23:30 +08:00
|
|
|
this.namedExports = namedExports;
|
2021-11-30 19:55:51 +08:00
|
|
|
}
|
|
|
|
|
2023-05-02 08:24:36 +08:00
|
|
|
/**
|
|
|
|
* @param {ParserState} state parser state
|
|
|
|
* @param {string} message warning message
|
|
|
|
* @param {LocConverter} locConverter location converter
|
|
|
|
* @param {number} start start offset
|
|
|
|
* @param {number} end end offset
|
|
|
|
*/
|
|
|
|
_emitWarning(state, message, locConverter, start, end) {
|
|
|
|
const { line: sl, column: sc } = locConverter.get(start);
|
|
|
|
const { line: el, column: ec } = locConverter.get(end);
|
|
|
|
|
|
|
|
state.current.addWarning(
|
|
|
|
new ModuleDependencyWarning(state.module, new WebpackError(message), {
|
|
|
|
start: { line: sl, column: sc },
|
|
|
|
end: { line: el, column: ec }
|
|
|
|
})
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
2021-11-30 19:55:51 +08:00
|
|
|
/**
|
|
|
|
* @param {string | Buffer | PreparsedAst} source the source to parse
|
|
|
|
* @param {ParserState} state the parser state
|
|
|
|
* @returns {ParserState} the parser state
|
|
|
|
*/
|
|
|
|
parse(source, state) {
|
|
|
|
if (Buffer.isBuffer(source)) {
|
|
|
|
source = source.toString("utf-8");
|
|
|
|
} else if (typeof source === "object") {
|
|
|
|
throw new Error("webpackAst is unexpected for the CssParser");
|
|
|
|
}
|
2024-08-02 02:36:27 +08:00
|
|
|
if (source[0] === "\uFEFF") {
|
2021-11-30 19:55:51 +08:00
|
|
|
source = source.slice(1);
|
|
|
|
}
|
|
|
|
|
2024-10-04 23:19:57 +08:00
|
|
|
let mode = this.defaultMode;
|
2023-06-21 04:40:47 +08:00
|
|
|
|
2024-10-04 23:19:57 +08:00
|
|
|
const module = state.module;
|
2023-06-21 04:40:47 +08:00
|
|
|
|
2022-12-16 20:56:14 +08:00
|
|
|
if (
|
2024-10-04 23:19:57 +08:00
|
|
|
mode === "auto" &&
|
2022-12-16 20:56:14 +08:00
|
|
|
module.type === CSS_MODULE_TYPE_AUTO &&
|
2023-06-11 21:33:10 +08:00
|
|
|
IS_MODULES.test(
|
|
|
|
parseResource(module.matchResource || module.resource).path
|
|
|
|
)
|
2022-12-16 20:56:14 +08:00
|
|
|
) {
|
2024-10-04 23:19:57 +08:00
|
|
|
mode = "local";
|
2022-12-16 20:56:14 +08:00
|
|
|
}
|
|
|
|
|
2024-10-04 23:19:57 +08:00
|
|
|
const isModules = mode === "global" || mode === "local";
|
|
|
|
|
2021-12-01 21:15:19 +08:00
|
|
|
const locConverter = new LocConverter(source);
|
2024-07-31 12:23:44 +08:00
|
|
|
/** @type {Set<string>} */
|
2023-05-05 05:38:41 +08:00
|
|
|
const declaredCssVariables = new Set();
|
2023-04-29 02:50:41 +08:00
|
|
|
/** @type {number} */
|
2023-05-05 07:53:57 +08:00
|
|
|
let scope = CSS_MODE_TOP_LEVEL;
|
2023-04-29 02:50:41 +08:00
|
|
|
/** @type {number} */
|
2023-05-05 07:49:09 +08:00
|
|
|
let blockNestingLevel = 0;
|
2023-05-02 08:24:36 +08:00
|
|
|
/** @type {boolean} */
|
|
|
|
let allowImportAtRule = true;
|
2023-05-05 05:27:59 +08:00
|
|
|
/** @type {"local" | "global" | undefined} */
|
2024-07-31 06:15:03 +08:00
|
|
|
let modeData;
|
2023-04-29 02:50:41 +08:00
|
|
|
/** @type {[number, number] | undefined} */
|
2024-07-31 06:15:03 +08:00
|
|
|
let lastIdentifier;
|
2023-04-14 06:52:50 +08:00
|
|
|
/** @type [string, number, number][] */
|
2024-07-31 04:09:42 +08:00
|
|
|
const balanced = [];
|
2023-05-20 00:05:14 +08:00
|
|
|
/** @type {undefined | { start: number, url?: string, urlStart?: number, urlEnd?: number, layer?: string, layerStart?: number, layerEnd?: number, supports?: string, supportsStart?: number, supportsEnd?: number, inSupports?:boolean, media?: string }} */
|
2024-07-31 06:15:03 +08:00
|
|
|
let importData;
|
2023-05-05 04:59:30 +08:00
|
|
|
/** @type {boolean} */
|
|
|
|
let inAnimationProperty = false;
|
2023-05-05 06:13:27 +08:00
|
|
|
/** @type {boolean} */
|
2023-05-05 09:28:48 +08:00
|
|
|
let isNextRulePrelude = true;
|
2023-04-14 04:25:46 +08:00
|
|
|
|
2023-05-05 09:04:20 +08:00
|
|
|
/**
|
|
|
|
* @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);
|
|
|
|
|
|
|
|
if (input[pos] === "}") {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// According spec only identifier can be used as a property name
|
|
|
|
const isIdentifier = walkCssTokens.isIdentStartCodePoint(
|
|
|
|
input.charCodeAt(pos)
|
|
|
|
);
|
|
|
|
|
|
|
|
return !isIdentifier;
|
|
|
|
};
|
2023-05-05 02:28:09 +08:00
|
|
|
/**
|
2023-05-05 07:53:57 +08:00
|
|
|
* @returns {boolean} true, when in local scope
|
2023-05-05 02:28:09 +08:00
|
|
|
*/
|
|
|
|
const isLocalMode = () =>
|
2024-10-04 23:19:57 +08:00
|
|
|
modeData === "local" || (mode === "local" && modeData === undefined);
|
2023-05-05 05:38:41 +08:00
|
|
|
/**
|
|
|
|
* @param {string} chars characters
|
|
|
|
* @returns {(input: string, pos: number) => number} function to eat characters
|
|
|
|
*/
|
2021-12-14 23:02:26 +08:00
|
|
|
const eatUntil = chars => {
|
|
|
|
const charCodes = Array.from({ length: chars.length }, (_, i) =>
|
|
|
|
chars.charCodeAt(i)
|
|
|
|
);
|
|
|
|
const arr = Array.from(
|
|
|
|
{ length: charCodes.reduce((a, b) => Math.max(a, b), 0) + 1 },
|
|
|
|
() => false
|
|
|
|
);
|
2024-08-02 02:36:27 +08:00
|
|
|
for (const cc of charCodes) {
|
|
|
|
arr[cc] = true;
|
|
|
|
}
|
2021-12-14 23:02:26 +08:00
|
|
|
return (input, pos) => {
|
|
|
|
for (;;) {
|
|
|
|
const cc = input.charCodeAt(pos);
|
|
|
|
if (cc < arr.length && arr[cc]) {
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
2023-05-05 05:38:41 +08:00
|
|
|
/**
|
|
|
|
* @param {string} input input
|
|
|
|
* @param {number} pos start position
|
|
|
|
* @param {(input: string, pos: number) => number} eater eater
|
|
|
|
* @returns {[number,string]} new position and text
|
|
|
|
*/
|
2021-12-14 23:02:26 +08:00
|
|
|
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;
|
|
|
|
}
|
2022-08-31 17:56:03 +08:00
|
|
|
return [pos, text.trimEnd()];
|
2021-12-14 23:02:26 +08:00
|
|
|
};
|
|
|
|
const eatExportName = eatUntil(":};/");
|
|
|
|
const eatExportValue = eatUntil("};/");
|
2023-05-05 05:38:41 +08:00
|
|
|
/**
|
|
|
|
* @param {string} input input
|
|
|
|
* @param {number} pos start position
|
|
|
|
* @returns {number} position after parse
|
|
|
|
*/
|
2021-12-14 23:02:26 +08:00
|
|
|
const parseExports = (input, pos) => {
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
const cc = input.charCodeAt(pos);
|
2023-05-02 17:15:52 +08:00
|
|
|
if (cc !== CC_LEFT_CURLY) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Unexpected '${input[pos]}' at ${pos} during parsing of ':export' (expected '{')`,
|
|
|
|
locConverter,
|
|
|
|
pos,
|
|
|
|
pos
|
2021-12-14 23:02:26 +08:00
|
|
|
);
|
2023-05-02 17:15:52 +08:00
|
|
|
return pos;
|
|
|
|
}
|
2021-12-14 23:02:26 +08:00
|
|
|
pos++;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
for (;;) {
|
|
|
|
if (input.charCodeAt(pos) === CC_RIGHT_CURLY) break;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
if (pos === input.length) return pos;
|
2024-07-31 04:09:42 +08:00
|
|
|
const start = pos;
|
2021-12-14 23:02:26 +08:00
|
|
|
let name;
|
|
|
|
[pos, name] = eatText(input, pos, eatExportName);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
if (input.charCodeAt(pos) !== CC_COLON) {
|
2023-05-02 17:15:52 +08:00
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Unexpected '${input[pos]}' at ${pos} during parsing of export name in ':export' (expected ':')`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
pos
|
2021-12-14 23:02:26 +08:00
|
|
|
);
|
2023-05-02 17:15:52 +08:00
|
|
|
return pos;
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
let value;
|
|
|
|
[pos, value] = eatText(input, pos, eatExportValue);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
const cc = input.charCodeAt(pos);
|
|
|
|
if (cc === CC_SEMICOLON) {
|
|
|
|
pos++;
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
} else if (cc !== CC_RIGHT_CURLY) {
|
2023-05-02 17:15:52 +08:00
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Unexpected '${input[pos]}' at ${pos} during parsing of export value in ':export' (expected ';' or '}')`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
pos
|
2021-12-14 23:02:26 +08:00
|
|
|
);
|
2023-05-02 17:15:52 +08:00
|
|
|
return pos;
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
const dep = new CssExportDependency(name, value);
|
|
|
|
const { line: sl, column: sc } = locConverter.get(start);
|
|
|
|
const { line: el, column: ec } = locConverter.get(pos);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
}
|
|
|
|
pos++;
|
|
|
|
if (pos === input.length) return pos;
|
2023-05-01 22:46:47 +08:00
|
|
|
pos = walkCssTokens.eatWhiteLine(input, pos);
|
2021-12-14 23:02:26 +08:00
|
|
|
return pos;
|
|
|
|
};
|
2021-12-17 03:42:44 +08:00
|
|
|
const eatPropertyName = eatUntil(":{};");
|
2023-05-05 05:27:59 +08:00
|
|
|
/**
|
|
|
|
* @param {string} input input
|
|
|
|
* @param {number} pos name start position
|
|
|
|
* @param {number} end name end position
|
|
|
|
* @returns {number} position after handling
|
|
|
|
*/
|
2023-05-05 03:40:00 +08:00
|
|
|
const processLocalDeclaration = (input, pos, end) => {
|
2021-12-17 03:42:44 +08:00
|
|
|
modeData = undefined;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
const propertyNameStart = pos;
|
|
|
|
const [propertyNameEnd, propertyName] = eatText(
|
|
|
|
input,
|
|
|
|
pos,
|
|
|
|
eatPropertyName
|
|
|
|
);
|
2023-05-05 03:40:00 +08:00
|
|
|
if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return end;
|
2021-12-17 03:42:44 +08:00
|
|
|
pos = propertyNameEnd + 1;
|
|
|
|
if (propertyName.startsWith("--")) {
|
|
|
|
// CSS Variable
|
|
|
|
const { line: sl, column: sc } = locConverter.get(propertyNameStart);
|
|
|
|
const { line: el, column: ec } = locConverter.get(propertyNameEnd);
|
|
|
|
const name = propertyName.slice(2);
|
|
|
|
const dep = new CssLocalIdentifierDependency(
|
|
|
|
name,
|
|
|
|
[propertyNameStart, propertyNameEnd],
|
|
|
|
"--"
|
|
|
|
);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
declaredCssVariables.add(name);
|
2023-04-17 00:43:06 +08:00
|
|
|
} else if (
|
2023-05-05 03:24:13 +08:00
|
|
|
!propertyName.startsWith("--") &&
|
2023-04-17 00:43:06 +08:00
|
|
|
OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
|
|
|
|
) {
|
2023-05-05 04:59:30 +08:00
|
|
|
inAnimationProperty = true;
|
2021-12-17 03:42:44 +08:00
|
|
|
}
|
|
|
|
return pos;
|
|
|
|
};
|
2023-05-05 04:59:30 +08:00
|
|
|
/**
|
|
|
|
* @param {string} input input
|
|
|
|
*/
|
|
|
|
const processDeclarationValueDone = input => {
|
|
|
|
if (inAnimationProperty && lastIdentifier) {
|
2021-12-17 03:42:44 +08:00
|
|
|
const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);
|
|
|
|
const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);
|
|
|
|
const name = input.slice(lastIdentifier[0], lastIdentifier[1]);
|
|
|
|
const dep = new CssSelfLocalIdentifierDependency(name, lastIdentifier);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
2023-05-05 04:59:30 +08:00
|
|
|
lastIdentifier = undefined;
|
2021-12-17 03:42:44 +08:00
|
|
|
}
|
|
|
|
};
|
|
|
|
const eatKeyframes = eatUntil("{};/");
|
|
|
|
const eatNameInVar = eatUntil(",)};/");
|
2021-11-30 19:55:51 +08:00
|
|
|
walkCssTokens(source, {
|
2024-07-31 11:31:11 +08:00
|
|
|
isSelector: () => isNextRulePrelude,
|
2024-10-09 14:21:00 +08:00
|
|
|
leftCurlyBracket: (input, start, end) => {
|
|
|
|
switch (scope) {
|
|
|
|
case CSS_MODE_TOP_LEVEL: {
|
|
|
|
allowImportAtRule = false;
|
|
|
|
scope = CSS_MODE_IN_BLOCK;
|
|
|
|
blockNestingLevel = 1;
|
|
|
|
|
|
|
|
if (isModules) {
|
|
|
|
isNextRulePrelude = isNextNestedSyntax(input, end);
|
|
|
|
}
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case CSS_MODE_IN_BLOCK: {
|
|
|
|
blockNestingLevel++;
|
|
|
|
isNextRulePrelude = isNextNestedSyntax(input, end);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
|
|
|
rightCurlyBracket: (input, start, end) => {
|
|
|
|
switch (scope) {
|
|
|
|
case CSS_MODE_IN_BLOCK: {
|
|
|
|
if (isLocalMode()) {
|
|
|
|
processDeclarationValueDone(input);
|
|
|
|
inAnimationProperty = false;
|
|
|
|
}
|
|
|
|
if (--blockNestingLevel === 0) {
|
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
|
|
|
isNextRulePrelude = true;
|
|
|
|
|
|
|
|
if (isModules) {
|
|
|
|
modeData = undefined;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
isNextRulePrelude = isNextNestedSyntax(input, end);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
2023-05-02 08:24:36 +08:00
|
|
|
url: (input, start, end, contentStart, contentEnd) => {
|
2024-07-31 04:09:42 +08:00
|
|
|
const value = normalizeUrl(
|
|
|
|
input.slice(contentStart, contentEnd),
|
|
|
|
false
|
|
|
|
);
|
2023-05-20 00:05:14 +08:00
|
|
|
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_IN_AT_IMPORT: {
|
|
|
|
// Do not parse URLs in `supports(...)`
|
|
|
|
if (importData.inSupports) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-20 00:13:04 +08:00
|
|
|
if (importData.url) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Duplicate of 'url(...)' in '${input.slice(
|
|
|
|
importData.start,
|
|
|
|
end
|
|
|
|
)}'`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-05 05:27:59 +08:00
|
|
|
importData.url = value;
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.urlStart = start;
|
|
|
|
importData.urlEnd = end;
|
2021-12-01 20:27:00 +08:00
|
|
|
break;
|
|
|
|
}
|
2023-05-02 08:24:36 +08:00
|
|
|
// Do not parse URLs in import between rules
|
2023-05-02 09:23:46 +08:00
|
|
|
case CSS_MODE_AT_NAMESPACE_INVALID:
|
2023-05-02 08:24:36 +08:00
|
|
|
case CSS_MODE_AT_IMPORT_INVALID: {
|
|
|
|
break;
|
|
|
|
}
|
2023-05-05 08:01:12 +08:00
|
|
|
case CSS_MODE_IN_BLOCK: {
|
2023-05-02 06:24:01 +08:00
|
|
|
// Ignore `url()`, `url('')` and `url("")`, they are valid by spec
|
|
|
|
if (value.length === 0) {
|
2023-04-13 06:23:57 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2021-12-03 23:23:09 +08:00
|
|
|
const dep = new CssUrlDependency(value, [start, end], "url");
|
2021-12-01 21:15:19 +08:00
|
|
|
const { line: sl, column: sc } = locConverter.get(start);
|
|
|
|
const { line: el, column: ec } = locConverter.get(end);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
2021-12-01 20:27:00 +08:00
|
|
|
module.addDependency(dep);
|
|
|
|
module.addCodeGenerationDependency(dep);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
|
|
|
string: (input, start, end) => {
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_IN_AT_IMPORT: {
|
2023-05-20 00:13:04 +08:00
|
|
|
const insideURLFunction =
|
|
|
|
balanced[balanced.length - 1] &&
|
|
|
|
balanced[balanced.length - 1][0] === "url";
|
|
|
|
|
2023-05-20 00:05:14 +08:00
|
|
|
// Do not parse URLs in `supports(...)` and other strings if we already have a URL
|
2023-05-20 00:13:04 +08:00
|
|
|
if (
|
|
|
|
importData.inSupports ||
|
|
|
|
(!insideURLFunction && importData.url)
|
|
|
|
) {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (insideURLFunction && importData.url) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Duplicate of 'url(...)' in '${input.slice(
|
|
|
|
importData.start,
|
|
|
|
end
|
|
|
|
)}'`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
2023-05-20 00:05:14 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-05-05 05:27:59 +08:00
|
|
|
importData.url = normalizeUrl(
|
|
|
|
input.slice(start + 1, end - 1),
|
|
|
|
true
|
|
|
|
);
|
2023-04-25 09:17:51 +08:00
|
|
|
|
|
|
|
if (!insideURLFunction) {
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.urlStart = start;
|
|
|
|
importData.urlEnd = end;
|
2023-04-25 09:17:51 +08:00
|
|
|
}
|
2023-05-20 00:13:04 +08:00
|
|
|
|
2021-12-01 20:27:00 +08:00
|
|
|
break;
|
|
|
|
}
|
2023-05-05 08:01:12 +08:00
|
|
|
case CSS_MODE_IN_BLOCK: {
|
2023-04-14 07:35:53 +08:00
|
|
|
// TODO move escaped parsing to tokenizer
|
2023-04-26 08:52:17 +08:00
|
|
|
const last = balanced[balanced.length - 1];
|
2023-04-14 06:52:50 +08:00
|
|
|
|
2023-04-14 04:25:46 +08:00
|
|
|
if (
|
2023-04-26 08:52:17 +08:00
|
|
|
last &&
|
|
|
|
(last[0].replace(/\\/g, "").toLowerCase() === "url" ||
|
|
|
|
IMAGE_SET_FUNCTION.test(last[0].replace(/\\/g, "")))
|
2023-04-14 04:25:46 +08:00
|
|
|
) {
|
2024-07-31 04:09:42 +08:00
|
|
|
const value = normalizeUrl(input.slice(start + 1, end - 1), true);
|
2023-04-14 04:25:46 +08:00
|
|
|
|
2023-05-02 06:24:01 +08:00
|
|
|
// Ignore `url()`, `url('')` and `url("")`, they are valid by spec
|
|
|
|
if (value.length === 0) {
|
2023-04-14 04:25:46 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2023-04-26 08:52:17 +08:00
|
|
|
const isUrl = last[0].replace(/\\/g, "").toLowerCase() === "url";
|
2023-04-14 06:52:50 +08:00
|
|
|
const dep = new CssUrlDependency(
|
|
|
|
value,
|
|
|
|
[start, end],
|
|
|
|
isUrl ? "string" : "url"
|
|
|
|
);
|
2023-04-14 04:25:46 +08:00
|
|
|
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);
|
|
|
|
module.addCodeGenerationDependency(dep);
|
|
|
|
}
|
|
|
|
}
|
2021-12-01 20:27:00 +08:00
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
|
|
|
atKeyword: (input, start, end) => {
|
2023-04-06 04:06:29 +08:00
|
|
|
const name = input.slice(start, end).toLowerCase();
|
2021-12-01 20:27:00 +08:00
|
|
|
if (name === "@namespace") {
|
2023-05-05 07:53:57 +08:00
|
|
|
scope = CSS_MODE_AT_NAMESPACE_INVALID;
|
2023-05-02 08:24:36 +08:00
|
|
|
this._emitWarning(
|
|
|
|
state,
|
2023-05-20 00:13:04 +08:00
|
|
|
"'@namespace' is not supported in bundled CSS",
|
2023-05-02 08:24:36 +08:00
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
return end;
|
|
|
|
} else if (name === "@import") {
|
|
|
|
if (!allowImportAtRule) {
|
2023-05-05 07:53:57 +08:00
|
|
|
scope = CSS_MODE_AT_IMPORT_INVALID;
|
2023-05-02 08:24:36 +08:00
|
|
|
this._emitWarning(
|
|
|
|
state,
|
2023-05-20 00:13:04 +08:00
|
|
|
"Any '@import' rules must precede all other rules",
|
2023-05-02 08:24:36 +08:00
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
2021-12-17 04:07:22 +08:00
|
|
|
);
|
2023-05-02 08:24:36 +08:00
|
|
|
return end;
|
2021-12-17 04:07:22 +08:00
|
|
|
}
|
2023-05-02 08:24:36 +08:00
|
|
|
|
2023-05-20 00:05:14 +08:00
|
|
|
scope = CSS_MODE_IN_AT_IMPORT;
|
2023-05-19 22:37:38 +08:00
|
|
|
importData = { start };
|
2023-05-02 19:23:58 +08:00
|
|
|
} else if (
|
2024-10-04 23:19:57 +08:00
|
|
|
isModules &&
|
2023-05-02 19:23:58 +08:00
|
|
|
OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name)
|
|
|
|
) {
|
2021-12-17 03:42:44 +08:00
|
|
|
let pos = end;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
const [newPos, name] = eatText(input, pos, eatKeyframes);
|
2023-05-02 09:54:40 +08:00
|
|
|
if (newPos === input.length) return newPos;
|
|
|
|
if (input.charCodeAt(newPos) !== CC_LEFT_CURLY) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Unexpected '${input[newPos]}' at ${newPos} during parsing of @keyframes (expected '{')`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
|
|
|
return newPos;
|
|
|
|
}
|
2024-04-20 11:29:06 +08:00
|
|
|
if (isLocalMode()) {
|
|
|
|
const { line: sl, column: sc } = locConverter.get(pos);
|
|
|
|
const { line: el, column: ec } = locConverter.get(newPos);
|
|
|
|
const dep = new CssLocalIdentifierDependency(name, [pos, newPos]);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
}
|
2021-12-17 03:42:44 +08:00
|
|
|
pos = newPos;
|
|
|
|
return pos + 1;
|
2024-10-04 23:19:57 +08:00
|
|
|
} else if (isModules && name === "@property") {
|
2023-05-04 19:50:11 +08:00
|
|
|
let pos = end;
|
|
|
|
pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
|
|
|
|
if (pos === input.length) return pos;
|
|
|
|
const propertyNameStart = pos;
|
|
|
|
const [propertyNameEnd, propertyName] = eatText(
|
|
|
|
input,
|
|
|
|
pos,
|
|
|
|
eatKeyframes
|
|
|
|
);
|
|
|
|
if (propertyNameEnd === input.length) return propertyNameEnd;
|
|
|
|
if (!propertyName.startsWith("--")) return propertyNameEnd;
|
|
|
|
if (input.charCodeAt(propertyNameEnd) !== CC_LEFT_CURLY) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
|
|
|
`Unexpected '${input[propertyNameEnd]}' at ${propertyNameEnd} during parsing of @property (expected '{')`,
|
|
|
|
locConverter,
|
|
|
|
start,
|
|
|
|
end
|
|
|
|
);
|
|
|
|
|
|
|
|
return propertyNameEnd;
|
|
|
|
}
|
|
|
|
const name = propertyName.slice(2);
|
|
|
|
declaredCssVariables.add(name);
|
2024-04-20 11:29:06 +08:00
|
|
|
if (isLocalMode()) {
|
|
|
|
const { line: sl, column: sc } = locConverter.get(pos);
|
|
|
|
const { line: el, column: ec } = locConverter.get(propertyNameEnd);
|
|
|
|
const dep = new CssLocalIdentifierDependency(
|
|
|
|
name,
|
|
|
|
[propertyNameStart, propertyNameEnd],
|
|
|
|
"--"
|
|
|
|
);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
}
|
2023-05-04 19:50:11 +08:00
|
|
|
pos = propertyNameEnd;
|
|
|
|
return pos + 1;
|
2023-05-04 19:38:10 +08:00
|
|
|
} else if (
|
|
|
|
name === "@media" ||
|
|
|
|
name === "@supports" ||
|
2023-05-05 01:24:37 +08:00
|
|
|
name === "@layer" ||
|
|
|
|
name === "@container"
|
2023-05-04 19:38:10 +08:00
|
|
|
) {
|
2023-05-05 07:57:22 +08:00
|
|
|
modeData = isLocalMode() ? "local" : "global";
|
2023-05-05 09:28:48 +08:00
|
|
|
isNextRulePrelude = true;
|
2023-05-05 07:37:24 +08:00
|
|
|
return end;
|
2024-10-04 23:19:57 +08:00
|
|
|
} else if (isModules) {
|
2023-05-05 10:28:27 +08:00
|
|
|
modeData = "global";
|
2023-05-05 09:28:48 +08:00
|
|
|
isNextRulePrelude = false;
|
2022-04-14 23:33:00 +08:00
|
|
|
}
|
2021-12-01 20:27:00 +08:00
|
|
|
return end;
|
|
|
|
},
|
|
|
|
semicolon: (input, start, end) => {
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_IN_AT_IMPORT: {
|
|
|
|
const { start } = importData;
|
|
|
|
|
|
|
|
if (importData.url === undefined) {
|
2023-05-02 17:15:52 +08:00
|
|
|
this._emitWarning(
|
|
|
|
state,
|
2023-05-20 00:13:04 +08:00
|
|
|
`Expected URL in '${input.slice(start, end)}'`,
|
2023-05-02 17:15:52 +08:00
|
|
|
locConverter,
|
2023-05-20 00:05:14 +08:00
|
|
|
start,
|
2023-05-19 22:37:38 +08:00
|
|
|
end
|
2023-04-26 04:31:35 +08:00
|
|
|
);
|
2023-05-19 22:37:38 +08:00
|
|
|
importData = undefined;
|
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
if (
|
|
|
|
importData.urlStart > importData.layerStart ||
|
|
|
|
importData.urlStart > importData.supportsStart
|
|
|
|
) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
2023-05-20 00:13:04 +08:00
|
|
|
`An URL in '${input.slice(
|
2023-05-20 00:05:14 +08:00
|
|
|
start,
|
|
|
|
end
|
2023-05-20 00:13:04 +08:00
|
|
|
)}' should be before 'layer(...)' or 'supports(...)'`,
|
2023-05-19 22:37:38 +08:00
|
|
|
locConverter,
|
2023-05-20 00:05:14 +08:00
|
|
|
start,
|
2023-05-19 22:37:38 +08:00
|
|
|
end
|
2023-04-26 04:31:35 +08:00
|
|
|
);
|
2023-05-19 20:36:06 +08:00
|
|
|
importData = undefined;
|
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
2023-05-02 17:15:52 +08:00
|
|
|
return end;
|
2023-04-26 04:31:35 +08:00
|
|
|
}
|
2023-05-19 22:37:38 +08:00
|
|
|
if (importData.layerStart > importData.supportsStart) {
|
|
|
|
this._emitWarning(
|
|
|
|
state,
|
2023-05-20 00:13:04 +08:00
|
|
|
`The 'layer(...)' in '${input.slice(
|
2023-05-20 00:05:14 +08:00
|
|
|
start,
|
|
|
|
end
|
2023-05-20 00:13:04 +08:00
|
|
|
)}' should be before 'supports(...)'`,
|
2023-05-19 22:37:38 +08:00
|
|
|
locConverter,
|
2023-05-20 00:05:14 +08:00
|
|
|
start,
|
2023-05-19 22:37:38 +08:00
|
|
|
end
|
|
|
|
);
|
|
|
|
importData = undefined;
|
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
|
2023-04-25 09:17:51 +08:00
|
|
|
const semicolonPos = end;
|
2024-04-23 14:29:13 +08:00
|
|
|
end = walkCssTokens.eatWhiteLine(input, end);
|
2023-05-20 00:05:14 +08:00
|
|
|
const { line: sl, column: sc } = locConverter.get(start);
|
2021-12-03 02:29:55 +08:00
|
|
|
const { line: el, column: ec } = locConverter.get(end);
|
2023-05-19 22:37:38 +08:00
|
|
|
const lastEnd =
|
|
|
|
importData.supportsEnd ||
|
|
|
|
importData.layerEnd ||
|
|
|
|
importData.urlEnd ||
|
2023-05-20 00:05:14 +08:00
|
|
|
start;
|
2023-05-19 22:37:38 +08:00
|
|
|
const pos = walkCssTokens.eatWhitespaceAndComments(input, lastEnd);
|
2023-04-26 08:07:13 +08:00
|
|
|
// Prevent to consider comments as a part of media query
|
|
|
|
if (pos !== semicolonPos - 1) {
|
2023-05-20 00:13:04 +08:00
|
|
|
importData.media = input.slice(lastEnd, semicolonPos - 1).trim();
|
2023-04-26 08:07:13 +08:00
|
|
|
}
|
2023-05-19 19:44:13 +08:00
|
|
|
|
|
|
|
const url = importData.url.trim();
|
|
|
|
|
|
|
|
if (url.length === 0) {
|
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
} else {
|
|
|
|
const dep = new CssImportDependency(
|
|
|
|
url,
|
|
|
|
[start, end],
|
|
|
|
importData.layer,
|
|
|
|
importData.supports,
|
|
|
|
importData.media && importData.media.length > 0
|
|
|
|
? importData.media
|
|
|
|
: undefined
|
|
|
|
);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
}
|
|
|
|
|
2023-05-05 05:27:59 +08:00
|
|
|
importData = undefined;
|
2023-05-05 07:53:57 +08:00
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
2023-05-19 19:44:13 +08:00
|
|
|
|
2021-12-01 20:27:00 +08:00
|
|
|
break;
|
|
|
|
}
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_AT_IMPORT_INVALID:
|
|
|
|
case CSS_MODE_AT_NAMESPACE_INVALID: {
|
|
|
|
scope = CSS_MODE_TOP_LEVEL;
|
|
|
|
|
2021-12-01 20:27:00 +08:00
|
|
|
break;
|
|
|
|
}
|
2023-05-05 07:49:09 +08:00
|
|
|
case CSS_MODE_IN_BLOCK: {
|
2024-10-04 23:19:57 +08:00
|
|
|
if (isModules) {
|
2023-05-05 09:04:20 +08:00
|
|
|
processDeclarationValueDone(input);
|
|
|
|
inAnimationProperty = false;
|
2023-05-05 06:13:27 +08:00
|
|
|
}
|
2024-10-09 14:01:49 +08:00
|
|
|
|
|
|
|
isNextRulePrelude = isNextNestedSyntax(input, end);
|
2023-05-05 09:57:53 +08:00
|
|
|
break;
|
2021-12-17 03:42:44 +08:00
|
|
|
}
|
2021-12-01 20:27:00 +08:00
|
|
|
}
|
2021-11-30 19:55:51 +08:00
|
|
|
return end;
|
2021-12-14 23:02:26 +08:00
|
|
|
},
|
2021-12-17 03:42:44 +08:00
|
|
|
identifier: (input, start, end) => {
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-05 07:49:09 +08:00
|
|
|
case CSS_MODE_IN_BLOCK: {
|
|
|
|
if (isLocalMode()) {
|
|
|
|
// Handle only top level values and not inside functions
|
|
|
|
if (inAnimationProperty && balanced.length === 0) {
|
|
|
|
lastIdentifier = [start, end];
|
|
|
|
} else {
|
|
|
|
return processLocalDeclaration(input, start, end);
|
|
|
|
}
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
break;
|
2023-05-05 03:24:13 +08:00
|
|
|
}
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_IN_AT_IMPORT: {
|
2023-04-26 06:00:39 +08:00
|
|
|
if (input.slice(start, end).toLowerCase() === "layer") {
|
2023-05-05 05:27:59 +08:00
|
|
|
importData.layer = "";
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.layerStart = start;
|
|
|
|
importData.layerEnd = end;
|
2023-04-26 05:23:21 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
2021-12-15 15:34:31 +08:00
|
|
|
class: (input, start, end) => {
|
2023-05-05 06:52:08 +08:00
|
|
|
if (isLocalMode()) {
|
|
|
|
const name = input.slice(start + 1, end);
|
|
|
|
const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
|
|
|
|
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);
|
2021-12-15 15:34:31 +08:00
|
|
|
}
|
2023-05-05 06:52:08 +08:00
|
|
|
|
2021-12-15 15:34:31 +08:00
|
|
|
return end;
|
|
|
|
},
|
2024-10-09 14:21:00 +08:00
|
|
|
hash: (input, start, end, isID) => {
|
|
|
|
if (isLocalMode() && isNextRulePrelude && isID) {
|
2023-05-05 06:52:08 +08:00
|
|
|
const name = input.slice(start + 1, end);
|
2024-10-09 14:21:00 +08:00
|
|
|
console.log(name);
|
2023-05-05 06:52:08 +08:00
|
|
|
const dep = new CssLocalIdentifierDependency(name, [start + 1, end]);
|
|
|
|
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);
|
2023-05-05 02:26:32 +08:00
|
|
|
}
|
|
|
|
return end;
|
|
|
|
},
|
2023-04-25 09:17:51 +08:00
|
|
|
function: (input, start, end) => {
|
|
|
|
let name = input.slice(start, end - 1);
|
|
|
|
|
2023-04-26 08:45:15 +08:00
|
|
|
balanced.push([name, start, end]);
|
2023-04-25 09:17:51 +08:00
|
|
|
|
2023-05-20 00:05:14 +08:00
|
|
|
if (
|
|
|
|
scope === CSS_MODE_IN_AT_IMPORT &&
|
|
|
|
name.toLowerCase() === "supports"
|
|
|
|
) {
|
|
|
|
importData.inSupports = true;
|
|
|
|
}
|
|
|
|
|
2023-05-05 04:01:16 +08:00
|
|
|
if (isLocalMode()) {
|
|
|
|
name = name.toLowerCase();
|
|
|
|
|
2023-05-05 04:59:30 +08:00
|
|
|
// Don't rename animation name when we have `var()` function
|
|
|
|
if (inAnimationProperty && balanced.length === 1) {
|
|
|
|
lastIdentifier = undefined;
|
|
|
|
}
|
|
|
|
|
2023-05-05 04:01:16 +08:00
|
|
|
if (name === "var") {
|
2024-07-31 04:09:42 +08:00
|
|
|
const pos = walkCssTokens.eatWhitespaceAndComments(input, end);
|
2023-05-05 04:01:16 +08:00
|
|
|
if (pos === input.length) return pos;
|
|
|
|
const [newPos, name] = eatText(input, pos, eatNameInVar);
|
|
|
|
if (!name.startsWith("--")) return end;
|
|
|
|
const { line: sl, column: sc } = locConverter.get(pos);
|
|
|
|
const { line: el, column: ec } = locConverter.get(newPos);
|
|
|
|
const dep = new CssSelfLocalIdentifierDependency(
|
|
|
|
name.slice(2),
|
|
|
|
[pos, newPos],
|
|
|
|
"--",
|
|
|
|
declaredCssVariables
|
|
|
|
);
|
|
|
|
dep.setLoc(sl, sc, el, ec);
|
|
|
|
module.addDependency(dep);
|
|
|
|
return newPos;
|
2023-04-25 09:17:51 +08:00
|
|
|
}
|
|
|
|
}
|
2023-05-05 04:01:16 +08:00
|
|
|
|
2023-04-25 09:17:51 +08:00
|
|
|
return end;
|
|
|
|
},
|
2021-12-14 23:02:26 +08:00
|
|
|
leftParenthesis: (input, start, end) => {
|
2023-04-26 08:45:15 +08:00
|
|
|
balanced.push(["(", start, end]);
|
|
|
|
|
2021-12-14 23:02:26 +08:00
|
|
|
return end;
|
|
|
|
},
|
|
|
|
rightParenthesis: (input, start, end) => {
|
2023-04-26 08:52:17 +08:00
|
|
|
const last = balanced[balanced.length - 1];
|
2023-05-05 00:47:38 +08:00
|
|
|
const popped = balanced.pop();
|
2023-04-14 06:52:50 +08:00
|
|
|
|
2023-05-05 06:52:08 +08:00
|
|
|
if (
|
2024-10-04 23:19:57 +08:00
|
|
|
isModules &&
|
2023-05-05 07:20:26 +08:00
|
|
|
popped &&
|
2023-05-05 06:52:08 +08:00
|
|
|
(popped[0] === ":local" || popped[0] === ":global")
|
|
|
|
) {
|
|
|
|
modeData = balanced[balanced.length - 1]
|
|
|
|
? /** @type {"local" | "global"} */
|
2024-07-31 05:43:19 +08:00
|
|
|
(balanced[balanced.length - 1][0])
|
2023-05-05 06:52:08 +08:00
|
|
|
: undefined;
|
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
|
|
|
|
|
|
|
return end;
|
|
|
|
}
|
|
|
|
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-20 00:05:14 +08:00
|
|
|
case CSS_MODE_IN_AT_IMPORT: {
|
|
|
|
if (last && last[0] === "url" && !importData.inSupports) {
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.urlStart = last[1];
|
|
|
|
importData.urlEnd = end;
|
2023-05-20 00:13:04 +08:00
|
|
|
} else if (
|
|
|
|
last &&
|
|
|
|
last[0].toLowerCase() === "layer" &&
|
|
|
|
!importData.inSupports
|
|
|
|
) {
|
2023-05-05 05:27:59 +08:00
|
|
|
importData.layer = input.slice(last[2], end - 1).trim();
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.layerStart = last[1];
|
|
|
|
importData.layerEnd = end;
|
2023-04-26 08:52:17 +08:00
|
|
|
} else if (last && last[0].toLowerCase() === "supports") {
|
2023-05-05 05:27:59 +08:00
|
|
|
importData.supports = input.slice(last[2], end - 1).trim();
|
2023-05-19 22:37:38 +08:00
|
|
|
importData.supportsStart = last[1];
|
|
|
|
importData.supportsEnd = end;
|
2023-05-20 00:05:14 +08:00
|
|
|
importData.inSupports = false;
|
2023-04-25 09:17:51 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-12-15 16:03:06 +08:00
|
|
|
}
|
2023-04-14 04:25:46 +08:00
|
|
|
|
2021-12-14 23:02:26 +08:00
|
|
|
return end;
|
|
|
|
},
|
|
|
|
pseudoClass: (input, start, end) => {
|
2024-10-04 23:19:57 +08:00
|
|
|
if (isModules) {
|
2023-05-05 06:52:08 +08:00
|
|
|
const name = input.slice(start, end).toLowerCase();
|
|
|
|
|
|
|
|
if (name === ":global") {
|
|
|
|
modeData = "global";
|
2023-05-05 07:05:37 +08:00
|
|
|
// Eat extra whitespace and comments
|
|
|
|
end = walkCssTokens.eatWhitespace(input, end);
|
2023-05-05 06:52:08 +08:00
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
2023-05-05 07:05:37 +08:00
|
|
|
return end;
|
2023-05-05 06:52:08 +08:00
|
|
|
} else if (name === ":local") {
|
|
|
|
modeData = "local";
|
2023-05-05 07:05:37 +08:00
|
|
|
// Eat extra whitespace and comments
|
|
|
|
end = walkCssTokens.eatWhitespace(input, end);
|
2023-05-05 06:52:08 +08:00
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
2023-05-05 07:05:37 +08:00
|
|
|
return end;
|
2023-05-05 06:52:08 +08:00
|
|
|
}
|
|
|
|
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-04 23:21:57 +08:00
|
|
|
case CSS_MODE_TOP_LEVEL: {
|
2023-05-05 06:52:08 +08:00
|
|
|
if (name === ":export") {
|
2023-05-04 23:21:57 +08:00
|
|
|
const pos = parseExports(input, end);
|
|
|
|
const dep = new ConstDependency("", [start, pos]);
|
|
|
|
module.addPresentationalDependency(dep);
|
|
|
|
return pos;
|
|
|
|
}
|
|
|
|
break;
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2023-05-05 06:52:08 +08:00
|
|
|
|
2021-12-14 23:02:26 +08:00
|
|
|
return end;
|
|
|
|
},
|
2021-12-15 15:34:31 +08:00
|
|
|
pseudoFunction: (input, start, end) => {
|
2023-04-14 06:52:50 +08:00
|
|
|
let name = input.slice(start, end - 1);
|
|
|
|
|
2023-04-26 08:45:15 +08:00
|
|
|
balanced.push([name, start, end]);
|
2023-04-14 06:52:50 +08:00
|
|
|
|
2024-10-04 23:19:57 +08:00
|
|
|
if (isModules) {
|
2023-05-05 06:52:08 +08:00
|
|
|
name = name.toLowerCase();
|
2023-04-14 06:52:50 +08:00
|
|
|
|
2023-05-05 06:52:08 +08:00
|
|
|
if (name === ":global") {
|
|
|
|
modeData = "global";
|
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
|
|
|
} else if (name === ":local") {
|
|
|
|
modeData = "local";
|
|
|
|
const dep = new ConstDependency("", [start, end]);
|
|
|
|
module.addPresentationalDependency(dep);
|
2021-12-15 15:34:31 +08:00
|
|
|
}
|
|
|
|
}
|
2023-05-05 06:52:08 +08:00
|
|
|
|
2021-12-15 15:34:31 +08:00
|
|
|
return end;
|
|
|
|
},
|
2021-12-14 23:02:26 +08:00
|
|
|
comma: (input, start, end) => {
|
2024-10-04 23:19:57 +08:00
|
|
|
if (isModules) {
|
2023-05-05 10:13:13 +08:00
|
|
|
// Reset stack for `:global .class :local .class-other` selector after
|
|
|
|
modeData = undefined;
|
|
|
|
|
2023-05-05 07:53:57 +08:00
|
|
|
switch (scope) {
|
2023-05-05 07:49:09 +08:00
|
|
|
case CSS_MODE_IN_BLOCK: {
|
|
|
|
if (isLocalMode()) {
|
|
|
|
processDeclarationValueDone(input);
|
|
|
|
}
|
|
|
|
|
2023-05-05 00:47:38 +08:00
|
|
|
break;
|
2023-05-05 07:49:09 +08:00
|
|
|
}
|
2023-05-05 00:47:38 +08:00
|
|
|
}
|
2021-12-14 23:02:26 +08:00
|
|
|
}
|
|
|
|
return end;
|
2021-11-30 19:55:51 +08:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
2024-10-01 03:05:27 +08:00
|
|
|
/** @type {BuildInfo} */
|
|
|
|
(module.buildInfo).strict = true;
|
|
|
|
/** @type {BuildMeta} */
|
|
|
|
(module.buildMeta).exportsType = this.namedExports
|
|
|
|
? "namespace"
|
|
|
|
: "default";
|
2024-04-02 21:57:29 +08:00
|
|
|
|
|
|
|
if (!this.namedExports) {
|
2024-10-01 03:05:27 +08:00
|
|
|
/** @type {BuildMeta} */
|
|
|
|
(module.buildMeta).defaultObject = "redirect";
|
2024-04-02 21:57:29 +08:00
|
|
|
}
|
|
|
|
|
2021-12-01 16:50:13 +08:00
|
|
|
module.addDependency(new StaticExportsDependency([], true));
|
2021-11-30 19:55:51 +08:00
|
|
|
return state;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
module.exports = CssParser;
|