123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602 |
- /*
- MIT License http://www.opensource.org/licenses/mit-license.php
- Author Tobias Koppers @sokra
- */
- "use strict";
- const vm = require("vm");
- const CommentCompilationWarning = require("../CommentCompilationWarning");
- const ModuleDependencyWarning = require("../ModuleDependencyWarning");
- const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");
- const Parser = require("../Parser");
- const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");
- const WebpackError = require("../WebpackError");
- const ConstDependency = require("../dependencies/ConstDependency");
- const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");
- const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");
- const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");
- const CssImportDependency = require("../dependencies/CssImportDependency");
- const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");
- const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");
- const CssUrlDependency = require("../dependencies/CssUrlDependency");
- const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
- const binarySearchBounds = require("../util/binarySearchBounds");
- const { parseResource } = require("../util/identifier");
- const {
- webpackCommentRegExp,
- createMagicCommentContext
- } = require("../util/magicComment");
- const walkCssTokens = require("./walkCssTokens");
- /** @typedef {import("../Module").BuildInfo} BuildInfo */
- /** @typedef {import("../Module").BuildMeta} BuildMeta */
- /** @typedef {import("../Parser").ParserState} ParserState */
- /** @typedef {import("../Parser").PreparsedAst} PreparsedAst */
- /** @typedef {import("./walkCssTokens").CssTokenCallbacks} CssTokenCallbacks */
- /** @typedef {[number, number]} Range */
- /** @typedef {{ line: number, column: number }} Position */
- /** @typedef {{ value: string, range: Range, loc: { start: Position, end: Position } }} Comment */
- const CC_COLON = ":".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);
- // 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 IS_MODULES = /\.module(s)?\.[^.]+$/i;
- const CSS_COMMENT = /\/\*((?!\*\/).*?)\*\//g;
- /**
- * @param {string} str url string
- * @param {boolean} isString is url wrapped in quotes
- * @returns {string} normalized url
- */
- const normalizeUrl = (str, isString) => {
- // Remove extra spaces and newlines:
- // `url("im\
- // g.png")`
- if (isString) {
- str = str.replace(STRING_MULTILINE, "");
- }
- str = str
- // Remove unnecessary spaces from `url(" img.png ")`
- .replace(TRIM_WHITE_SPACES, "")
- // Unescape
- .replace(UNESCAPE, match => {
- if (match.length > 2) {
- return String.fromCharCode(Number.parseInt(match.slice(1).trim(), 16));
- }
- return match[1];
- });
- if (/^data:/i.test(str)) {
- return str;
- }
- if (str.includes("%")) {
- // Convert `url('%2E/img.png')` -> `url('./img.png')`
- try {
- str = decodeURIComponent(str);
- } catch (_err) {
- // Ignore
- }
- }
- return str;
- };
- // eslint-disable-next-line no-useless-escape
- const regexSingleEscape = /[ -,.\/:-@[\]\^`{-~]/;
- const regexExcessiveSpaces =
- /(^|\\+)?(\\[A-F0-9]{1,6})\u0020(?![a-fA-F0-9\u0020])/g;
- /**
- * @param {string} str string
- * @returns {string} escaped identifier
- */
- const escapeIdentifier = str => {
- let output = "";
- let counter = 0;
- while (counter < str.length) {
- const character = str.charAt(counter++);
- let value;
- if (/[\t\n\f\r\u000B]/.test(character)) {
- const codePoint = character.charCodeAt(0);
- value = `\\${codePoint.toString(16).toUpperCase()} `;
- } else if (character === "\\" || regexSingleEscape.test(character)) {
- value = `\\${character}`;
- } else {
- value = character;
- }
- output += value;
- }
- const firstChar = str.charAt(0);
- if (/^-[-\d]/.test(output)) {
- output = `\\-${output.slice(1)}`;
- } else if (/\d/.test(firstChar)) {
- output = `\\3${firstChar} ${output.slice(1)}`;
- }
- // Remove spaces after `\HEX` escapes that are not followed by a hex digit,
- // since they’re redundant. Note that this is only possible if the escape
- // sequence isn’t preceded by an odd number of backslashes.
- output = output.replace(regexExcessiveSpaces, ($0, $1, $2) => {
- if ($1 && $1.length % 2) {
- // It’s not safe to remove the space, so don’t.
- return $0;
- }
- // Strip the space.
- return ($1 || "") + $2;
- });
- return output;
- };
- const CONTAINS_ESCAPE = /\\/;
- /**
- * @param {string} str string
- * @returns {[string, number] | undefined} hex
- */
- const gobbleHex = str => {
- const lower = str.toLowerCase();
- let hex = "";
- let spaceTerminated = false;
- for (let i = 0; i < 6 && lower[i] !== undefined; i++) {
- const code = lower.charCodeAt(i);
- // check to see if we are dealing with a valid hex char [a-f|0-9]
- const valid = (code >= 97 && code <= 102) || (code >= 48 && code <= 57);
- // https://drafts.csswg.org/css-syntax/#consume-escaped-code-point
- spaceTerminated = code === 32;
- if (!valid) break;
- hex += lower[i];
- }
- if (hex.length === 0) return undefined;
- const codePoint = Number.parseInt(hex, 16);
- const isSurrogate = codePoint >= 0xd800 && codePoint <= 0xdfff;
- // Add special case for
- // "If this number is zero, or is for a surrogate, or is greater than the maximum allowed code point"
- // https://drafts.csswg.org/css-syntax/#maximum-allowed-code-point
- if (isSurrogate || codePoint === 0x0000 || codePoint > 0x10ffff) {
- return ["\uFFFD", hex.length + (spaceTerminated ? 1 : 0)];
- }
- return [
- String.fromCodePoint(codePoint),
- hex.length + (spaceTerminated ? 1 : 0)
- ];
- };
- /**
- * @param {string} str string
- * @returns {string} unescaped string
- */
- const unescapeIdentifier = str => {
- const needToProcess = CONTAINS_ESCAPE.test(str);
- if (!needToProcess) return str;
- let ret = "";
- for (let i = 0; i < str.length; i++) {
- if (str[i] === "\\") {
- const gobbled = gobbleHex(str.slice(i + 1, i + 7));
- if (gobbled !== undefined) {
- ret += gobbled[0];
- i += gobbled[1];
- continue;
- }
- // Retain a pair of \\ if double escaped `\\\\`
- // https://github.com/postcss/postcss-selector-parser/commit/268c9a7656fb53f543dc620aa5b73a30ec3ff20e
- if (str[i + 1] === "\\") {
- ret += "\\";
- i += 1;
- continue;
- }
- // if \\ is at the end of the string retain it
- // https://github.com/postcss/postcss-selector-parser/commit/01a6b346e3612ce1ab20219acc26abdc259ccefb
- if (str.length === i + 1) {
- ret += str[i];
- }
- continue;
- }
- ret += str[i];
- }
- return ret;
- };
- class LocConverter {
- /**
- * @param {string} input input
- */
- constructor(input) {
- this._input = input;
- this.line = 1;
- this.column = 0;
- this.pos = 0;
- }
- /**
- * @param {number} pos position
- * @returns {LocConverter} location converter
- */
- 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++;
- while (i > 0 && (i = str.lastIndexOf("\n", i - 1)) !== -1)
- this.line++;
- }
- } else {
- let i = this._input.lastIndexOf("\n", this.pos);
- while (i >= pos) {
- this.line--;
- i = i > 0 ? this._input.lastIndexOf("\n", i - 1) : -1;
- }
- this.column = pos - i;
- }
- this.pos = pos;
- }
- return this;
- }
- }
- const EMPTY_COMMENT_OPTIONS = {
- options: null,
- errors: null
- };
- const CSS_MODE_TOP_LEVEL = 0;
- const CSS_MODE_IN_BLOCK = 1;
- const eatUntilSemi = walkCssTokens.eatUntil(";");
- const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
- const eatSemi = walkCssTokens.eatUntil(";");
- class CssParser extends Parser {
- /**
- * @param {object} options options
- * @param {boolean=} options.importOption need handle `@import`
- * @param {boolean=} options.url need handle URLs
- * @param {("pure" | "global" | "local" | "auto")=} options.defaultMode default mode
- * @param {boolean=} options.namedExports is named exports
- */
- constructor({
- defaultMode = "pure",
- importOption = true,
- url = true,
- namedExports = true
- } = {}) {
- super();
- this.defaultMode = defaultMode;
- this.import = importOption;
- this.url = url;
- this.namedExports = namedExports;
- /** @type {Comment[] | undefined} */
- this.comments = undefined;
- this.magicCommentContext = createMagicCommentContext();
- }
- /**
- * @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 }
- })
- );
- }
- /**
- * @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");
- }
- if (source[0] === "\uFEFF") {
- source = source.slice(1);
- }
- let mode = this.defaultMode;
- const module = state.module;
- if (
- mode === "auto" &&
- module.type === CSS_MODULE_TYPE_AUTO &&
- IS_MODULES.test(
- parseResource(module.matchResource || module.resource).path
- )
- ) {
- mode = "local";
- }
- const isModules = mode === "global" || mode === "local";
- const locConverter = new LocConverter(source);
- /** @type {number} */
- let scope = CSS_MODE_TOP_LEVEL;
- /** @type {boolean} */
- let allowImportAtRule = true;
- /** @type [string, number, number][] */
- const balanced = [];
- let lastTokenEndForComments = 0;
- /** @type {boolean} */
- let isNextRulePrelude = isModules;
- /** @type {number} */
- let blockNestingLevel = 0;
- /** @type {"local" | "global" | undefined} */
- let modeData;
- /** @type {boolean} */
- let inAnimationProperty = false;
- /** @type {[number, number, boolean] | undefined} */
- let lastIdentifier;
- /** @type {Set<string>} */
- const declaredCssVariables = new Set();
- /** @type {Map<string, { path?: string, value: string }>} */
- const icssDefinitions = new Map();
- /**
- * @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;
- };
- /**
- * @returns {boolean} true, when in local scope
- */
- const isLocalMode = () =>
- modeData === "local" || (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()];
- };
- /**
- * @param {0 | 1} type import or export
- * @param {string} input input
- * @param {number} pos start position
- * @returns {number} position after parse
- */
- const parseImportOrExport = (type, input, pos) => {
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
- let importPath;
- if (type === 0) {
- let cc = input.charCodeAt(pos);
- if (cc !== CC_LEFT_PARENTHESIS) {
- this._emitWarning(
- state,
- `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected '(')`,
- locConverter,
- pos,
- pos
- );
- return pos;
- }
- pos++;
- const stringStart = pos;
- const str = walkCssTokens.eatString(input, pos);
- if (!str) {
- this._emitWarning(
- state,
- `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected string)`,
- locConverter,
- stringStart,
- pos
- );
- return pos;
- }
- importPath = input.slice(str[0] + 1, str[1] - 1);
- pos = str[1];
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
- cc = input.charCodeAt(pos);
- if (cc !== CC_RIGHT_PARENTHESIS) {
- this._emitWarning(
- state,
- `Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected ')')`,
- locConverter,
- pos,
- pos
- );
- return pos;
- }
- pos++;
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos);
- }
- /**
- * @param {string} name name
- * @param {string} value value
- * @param {number} start start of position
- * @param {number} end end of position
- */
- const createDep = (name, value, start, end) => {
- if (type === 0) {
- icssDefinitions.set(name, {
- path: /** @type {string} */ (importPath),
- value
- });
- } else if (type === 1) {
- 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);
- }
- };
- let needTerminate = false;
- let balanced = 0;
- /** @type {undefined | 0 | 1 | 2} */
- let scope;
- /** @type {[number, number] | undefined} */
- let name;
- /** @type {number | undefined} */
- let value;
- /** @type {CssTokenCallbacks} */
- const callbacks = {
- leftCurlyBracket: (_input, _start, end) => {
- balanced++;
- if (scope === undefined) {
- scope = 0;
- }
- return end;
- },
- rightCurlyBracket: (_input, _start, end) => {
- balanced--;
- if (scope === 2) {
- createDep(
- input.slice(name[0], name[1]),
- input.slice(value, end - 1).trim(),
- name[1],
- end - 1
- );
- scope = 0;
- }
- if (balanced === 0 && scope === 0) {
- needTerminate = true;
- }
- return end;
- },
- identifier: (_input, start, end) => {
- if (scope === 0) {
- name = [start, end];
- scope = 1;
- }
- return end;
- },
- colon: (_input, _start, end) => {
- if (scope === 1) {
- scope = 2;
- value = walkCssTokens.eatWhitespace(input, end);
- return value;
- }
- return end;
- },
- semicolon: (input, _start, end) => {
- if (scope === 2) {
- createDep(
- input.slice(name[0], name[1]),
- input.slice(value, end - 1),
- name[1],
- end - 1
- );
- scope = 0;
- }
- return end;
- },
- needTerminate: () => needTerminate
- };
- pos = walkCssTokens(input, pos, callbacks);
- pos = walkCssTokens.eatWhiteLine(input, pos);
- return pos;
- };
- const eatPropertyName = walkCssTokens.eatUntil(":{};");
- /**
- * @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 CssLocalIdentifierDependency(
- name,
- [propertyNameStart, propertyNameEnd],
- "--"
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- declaredCssVariables.add(name);
- } else if (
- OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)
- ) {
- inAnimationProperty = true;
- }
- return pos;
- };
- /**
- * @param {string} input input
- */
- const processDeclarationValueDone = input => {
- if (inAnimationProperty && lastIdentifier) {
- const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);
- const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);
- const name = unescapeIdentifier(
- lastIdentifier[2]
- ? input.slice(lastIdentifier[0], lastIdentifier[1])
- : input.slice(lastIdentifier[0] + 1, lastIdentifier[1] - 1)
- );
- const dep = new CssSelfLocalIdentifierDependency(name, [
- lastIdentifier[0],
- lastIdentifier[1]
- ]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- lastIdentifier = undefined;
- }
- };
- /**
- * @param {string} input input
- * @param {number} start start
- * @param {number} end end
- * @returns {number} end
- */
- const comment = (input, start, end) => {
- if (!this.comments) this.comments = [];
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- /** @type {Comment} */
- const comment = {
- value: input.slice(start + 2, end - 2),
- range: [start, end],
- loc: {
- start: { line: sl, column: sc },
- end: { line: el, column: ec }
- }
- };
- this.comments.push(comment);
- return end;
- };
- walkCssTokens(source, 0, {
- comment,
- leftCurlyBracket: (input, start, end) => {
- switch (scope) {
- case CSS_MODE_TOP_LEVEL: {
- allowImportAtRule = false;
- scope = CSS_MODE_IN_BLOCK;
- if (isModules) {
- blockNestingLevel = 1;
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- break;
- }
- case CSS_MODE_IN_BLOCK: {
- if (isModules) {
- blockNestingLevel++;
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- break;
- }
- }
- return end;
- },
- rightCurlyBracket: (input, start, end) => {
- switch (scope) {
- case CSS_MODE_IN_BLOCK: {
- if (--blockNestingLevel === 0) {
- scope = CSS_MODE_TOP_LEVEL;
- if (isModules) {
- isNextRulePrelude = true;
- modeData = undefined;
- }
- } else if (isModules) {
- if (isLocalMode()) {
- processDeclarationValueDone(input);
- inAnimationProperty = false;
- }
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- break;
- }
- }
- return end;
- },
- url: (input, start, end, contentStart, contentEnd) => {
- if (!this.url) {
- return end;
- }
- const { options, errors: commentErrors } = this.parseCommentOptions([
- lastTokenEndForComments,
- end
- ]);
- if (commentErrors) {
- for (const e of commentErrors) {
- const { comment } = e;
- state.module.addWarning(
- new CommentCompilationWarning(
- `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
- comment.loc
- )
- );
- }
- }
- if (options && options.webpackIgnore !== undefined) {
- if (typeof options.webpackIgnore !== "boolean") {
- const { line: sl, column: sc } = locConverter.get(
- lastTokenEndForComments
- );
- const { line: el, column: ec } = locConverter.get(end);
- state.module.addWarning(
- new UnsupportedFeatureWarning(
- `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
- {
- start: { line: sl, column: sc },
- end: { line: el, column: ec }
- }
- )
- );
- } else if (options.webpackIgnore) {
- return end;
- }
- }
- const value = normalizeUrl(
- input.slice(contentStart, contentEnd),
- false
- );
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
- if (value.length === 0) return end;
- const dep = new CssUrlDependency(value, [start, end], "url");
- 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);
- return end;
- },
- string: (_input, start, end) => {
- switch (scope) {
- case CSS_MODE_IN_BLOCK: {
- if (inAnimationProperty && balanced.length === 0) {
- lastIdentifier = [start, end, false];
- }
- }
- }
- return end;
- },
- atKeyword: (input, start, end) => {
- const name = input.slice(start, end).toLowerCase();
- switch (name) {
- case "@namespace": {
- this._emitWarning(
- state,
- "'@namespace' is not supported in bundled CSS",
- locConverter,
- start,
- end
- );
- return eatUntilSemi(input, start);
- }
- case "@import": {
- if (!this.import) {
- return eatSemi(input, end);
- }
- if (!allowImportAtRule) {
- this._emitWarning(
- state,
- "Any '@import' rules must precede all other rules",
- locConverter,
- start,
- end
- );
- return end;
- }
- const tokens = walkCssTokens.eatImportTokens(input, end, {
- comment
- });
- if (!tokens[3]) return end;
- const semi = tokens[3][1];
- if (!tokens[0]) {
- this._emitWarning(
- state,
- `Expected URL in '${input.slice(start, semi)}'`,
- locConverter,
- start,
- semi
- );
- return end;
- }
- const urlToken = tokens[0];
- const url = normalizeUrl(
- input.slice(urlToken[2], urlToken[3]),
- true
- );
- const newline = walkCssTokens.eatWhiteLine(input, semi);
- const { options, errors: commentErrors } = this.parseCommentOptions(
- [end, urlToken[1]]
- );
- if (commentErrors) {
- for (const e of commentErrors) {
- const { comment } = e;
- state.module.addWarning(
- new CommentCompilationWarning(
- `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
- comment.loc
- )
- );
- }
- }
- if (options && options.webpackIgnore !== undefined) {
- if (typeof options.webpackIgnore !== "boolean") {
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(newline);
- state.module.addWarning(
- new UnsupportedFeatureWarning(
- `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
- {
- start: { line: sl, column: sc },
- end: { line: el, column: ec }
- }
- )
- );
- } else if (options.webpackIgnore) {
- return newline;
- }
- }
- if (url.length === 0) {
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(newline);
- const dep = new ConstDependency("", [start, newline]);
- module.addPresentationalDependency(dep);
- dep.setLoc(sl, sc, el, ec);
- return newline;
- }
- let layer;
- if (tokens[1]) {
- layer = input.slice(tokens[1][0] + 6, tokens[1][1] - 1).trim();
- }
- let supports;
- if (tokens[2]) {
- supports = input.slice(tokens[2][0] + 9, tokens[2][1] - 1).trim();
- }
- const last = tokens[2] || tokens[1] || tokens[0];
- const mediaStart = walkCssTokens.eatWhitespaceAndComments(
- input,
- last[1]
- );
- let media;
- if (mediaStart !== semi - 1) {
- media = input.slice(mediaStart, semi - 1).trim();
- }
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(newline);
- const dep = new CssImportDependency(
- url,
- [start, newline],
- layer,
- supports && supports.length > 0 ? supports : undefined,
- media && media.length > 0 ? media : undefined
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return newline;
- }
- default: {
- if (isModules) {
- if (name === "@value") {
- const semi = eatUntilSemi(input, end);
- const atRuleEnd = semi + 1;
- const params = input.slice(end, semi);
- let [alias, from] = params.split(/\s*from\s*/);
- if (from) {
- const aliases = alias
- .replace(CSS_COMMENT, " ")
- .trim()
- .replace(/^\(|\)$/g, "")
- .split(/\s*,\s*/);
- from = from.replace(CSS_COMMENT, "").trim();
- const isExplicitImport = from[0] === "'" || from[0] === '"';
- if (isExplicitImport) {
- from = from.slice(1, -1);
- }
- for (const alias of aliases) {
- const [name, aliasName] = alias.split(/\s*as\s*/);
- icssDefinitions.set(aliasName || name, {
- value: name,
- path: from
- });
- }
- } else {
- const ident = walkCssTokens.eatIdentSequence(alias, 0);
- if (!ident) {
- 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 pos = walkCssTokens.eatWhitespaceAndComments(
- alias,
- ident[1]
- );
- const name = alias.slice(ident[0], ident[1]);
- let value =
- alias.charCodeAt(pos) === CC_COLON
- ? alias.slice(pos + 1)
- : alias.slice(ident[1]);
- if (value && !/^\s+$/.test(value)) {
- value = value.trim();
- }
- if (icssDefinitions.has(value)) {
- const def = icssDefinitions.get(value);
- value = def.value;
- }
- 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]);
- module.addPresentationalDependency(dep);
- return atRuleEnd;
- } else if (
- OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) &&
- isLocalMode()
- ) {
- const ident = walkCssTokens.eatIdentSequenceOrString(
- input,
- end
- );
- if (!ident) return end;
- const name = unescapeIdentifier(
- ident[2] === true
- ? input.slice(ident[0], ident[1])
- : input.slice(ident[0] + 1, ident[1] - 1)
- );
- const { line: sl, column: sc } = locConverter.get(ident[0]);
- const { line: el, column: ec } = locConverter.get(ident[1]);
- const dep = new CssLocalIdentifierDependency(name, [
- ident[0],
- ident[1]
- ]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return ident[1];
- } else if (name === "@property" && isLocalMode()) {
- const ident = walkCssTokens.eatIdentSequence(input, end);
- if (!ident) return end;
- let name = input.slice(ident[0], ident[1]);
- if (!name.startsWith("--") || name.length < 3) return end;
- name = unescapeIdentifier(name.slice(2));
- declaredCssVariables.add(name);
- const { line: sl, column: sc } = locConverter.get(ident[0]);
- const { line: el, column: ec } = locConverter.get(ident[1]);
- const dep = new CssLocalIdentifierDependency(
- name,
- [ident[0], ident[1]],
- "--"
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return ident[1];
- } else if (name === "@scope") {
- isNextRulePrelude = true;
- return end;
- }
- isNextRulePrelude = false;
- }
- }
- }
- return end;
- },
- semicolon: (input, start, end) => {
- if (isModules && scope === CSS_MODE_IN_BLOCK) {
- if (isLocalMode()) {
- processDeclarationValueDone(input);
- inAnimationProperty = false;
- }
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- return end;
- },
- identifier: (input, start, end) => {
- if (isModules) {
- if (icssDefinitions.has(input.slice(start, end))) {
- const name = input.slice(start, end);
- let { path, value } = icssDefinitions.get(name);
- if (path) {
- if (icssDefinitions.has(path)) {
- const definition = icssDefinitions.get(path);
- path = definition.value.slice(1, -1);
- }
- const dep = new CssIcssImportDependency(path, value, [
- start,
- end - 1
- ]);
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end - 1);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- } else {
- const { line: sl, column: sc } = locConverter.get(start);
- const { line: el, column: ec } = locConverter.get(end);
- const dep = new CssIcssSymbolDependency(name, value, [
- start,
- end
- ]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- }
- return end;
- }
- switch (scope) {
- case CSS_MODE_IN_BLOCK: {
- if (isLocalMode()) {
- // Handle only top level values and not inside functions
- if (inAnimationProperty && balanced.length === 0) {
- lastIdentifier = [start, end, true];
- } else {
- return processLocalDeclaration(input, start, end);
- }
- }
- break;
- }
- }
- }
- 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]));
- const dep = new CssLocalIdentifierDependency(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];
- }
- return end;
- },
- hash: (input, start, end, isID) => {
- if (isNextRulePrelude && isLocalMode() && isID) {
- const valueStart = start + 1;
- const name = unescapeIdentifier(input.slice(valueStart, end));
- const dep = new CssLocalIdentifierDependency(name, [valueStart, 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);
- }
- return end;
- },
- colon: (input, start, end) => {
- if (isModules) {
- const ident = walkCssTokens.skipCommentsAndEatIdentSequence(
- input,
- end
- );
- if (!ident) return end;
- const name = input.slice(ident[0], ident[1]).toLowerCase();
- switch (scope) {
- case CSS_MODE_TOP_LEVEL: {
- if (name === "import") {
- const pos = parseImportOrExport(0, input, ident[1]);
- const dep = new ConstDependency("", [start, pos]);
- module.addPresentationalDependency(dep);
- return pos;
- } else if (name === "export") {
- const pos = parseImportOrExport(1, input, ident[1]);
- const dep = new ConstDependency("", [start, pos]);
- module.addPresentationalDependency(dep);
- return pos;
- }
- }
- // falls through
- default: {
- if (isNextRulePrelude) {
- const isFn = input.charCodeAt(ident[1]) === CC_LEFT_PARENTHESIS;
- if (isFn && name === "local") {
- const end = ident[1] + 1;
- modeData = "local";
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
- balanced.push([":local", start, end]);
- return end;
- } else if (name === "local") {
- modeData = "local";
- // Eat extra whitespace
- end = walkCssTokens.eatWhitespace(input, ident[1]);
- if (ident[1] === end) {
- this._emitWarning(
- state,
- `Missing whitespace after ':local' in '${input.slice(
- start,
- eatUntilLeftCurly(input, end) + 1
- )}'`,
- locConverter,
- start,
- end
- );
- }
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
- return end;
- } else if (isFn && name === "global") {
- const end = ident[1] + 1;
- modeData = "global";
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
- balanced.push([":global", start, end]);
- return end;
- } else if (name === "global") {
- modeData = "global";
- // Eat extra whitespace
- end = walkCssTokens.eatWhitespace(input, ident[1]);
- if (ident[1] === end) {
- this._emitWarning(
- state,
- `Missing whitespace after ':global' in '${input.slice(
- start,
- eatUntilLeftCurly(input, end) + 1
- )}'`,
- locConverter,
- start,
- end
- );
- }
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
- return end;
- }
- }
- }
- }
- }
- lastTokenEndForComments = end;
- return end;
- },
- function: (input, start, end) => {
- const name = input
- .slice(start, end - 1)
- .replace(/\\/g, "")
- .toLowerCase();
- balanced.push([name, start, end]);
- switch (name) {
- case "src":
- case "url": {
- if (!this.url) {
- return end;
- }
- const string = walkCssTokens.eatString(input, end);
- if (!string) return end;
- const { options, errors: commentErrors } = this.parseCommentOptions(
- [lastTokenEndForComments, end]
- );
- if (commentErrors) {
- for (const e of commentErrors) {
- const { comment } = e;
- state.module.addWarning(
- new CommentCompilationWarning(
- `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
- comment.loc
- )
- );
- }
- }
- if (options && options.webpackIgnore !== undefined) {
- if (typeof options.webpackIgnore !== "boolean") {
- const { line: sl, column: sc } = locConverter.get(string[0]);
- const { line: el, column: ec } = locConverter.get(string[1]);
- state.module.addWarning(
- new UnsupportedFeatureWarning(
- `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
- {
- start: { line: sl, column: sc },
- end: { line: el, column: ec }
- }
- )
- );
- } else if (options.webpackIgnore) {
- return end;
- }
- }
- const value = normalizeUrl(
- input.slice(string[0] + 1, string[1] - 1),
- true
- );
- // Ignore `url()`, `url('')` and `url("")`, they are valid by spec
- if (value.length === 0) return end;
- const isUrl = name === "url" || name === "src";
- const dep = new CssUrlDependency(
- value,
- [string[0], string[1]],
- isUrl ? "string" : "url"
- );
- const { line: sl, column: sc } = locConverter.get(string[0]);
- const { line: el, column: ec } = locConverter.get(string[1]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- module.addCodeGenerationDependency(dep);
- return string[1];
- }
- default: {
- if (this.url && IMAGE_SET_FUNCTION.test(name)) {
- lastTokenEndForComments = end;
- const values = walkCssTokens.eatImageSetStrings(input, end, {
- comment
- });
- if (values.length === 0) return end;
- for (const [index, string] of values.entries()) {
- const value = normalizeUrl(
- input.slice(string[0] + 1, string[1] - 1),
- true
- );
- if (value.length === 0) return end;
- const { options, errors: commentErrors } =
- this.parseCommentOptions([
- index === 0 ? start : values[index - 1][1],
- string[1]
- ]);
- if (commentErrors) {
- for (const e of commentErrors) {
- const { comment } = e;
- state.module.addWarning(
- new CommentCompilationWarning(
- `Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,
- comment.loc
- )
- );
- }
- }
- if (options && options.webpackIgnore !== undefined) {
- if (typeof options.webpackIgnore !== "boolean") {
- const { line: sl, column: sc } = locConverter.get(
- string[0]
- );
- const { line: el, column: ec } = locConverter.get(
- string[1]
- );
- state.module.addWarning(
- new UnsupportedFeatureWarning(
- `\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,
- {
- start: { line: sl, column: sc },
- end: { line: el, column: ec }
- }
- )
- );
- } else if (options.webpackIgnore) {
- continue;
- }
- }
- const dep = new CssUrlDependency(
- value,
- [string[0], string[1]],
- "url"
- );
- const { line: sl, column: sc } = locConverter.get(string[0]);
- const { line: el, column: ec } = locConverter.get(string[1]);
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- module.addCodeGenerationDependency(dep);
- }
- // Can contain `url()` inside, so let's return end to allow parse them
- return end;
- } else if (isLocalMode()) {
- // Don't rename animation name when we have `var()` function
- if (inAnimationProperty && balanced.length === 1) {
- lastIdentifier = undefined;
- }
- if (name === "var") {
- const customIdent = walkCssTokens.eatIdentSequence(input, end);
- 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’s 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(
- input.slice(customIdent[0] + 2, customIdent[1])
- );
- const afterCustomIdent = walkCssTokens.eatWhitespaceAndComments(
- input,
- customIdent[1]
- );
- if (
- input.charCodeAt(afterCustomIdent) === CC_LOWER_F ||
- input.charCodeAt(afterCustomIdent) === CC_UPPER_F
- ) {
- const fromWord = walkCssTokens.eatIdentSequence(
- input,
- afterCustomIdent
- );
- if (
- !fromWord ||
- input.slice(fromWord[0], fromWord[1]).toLowerCase() !==
- "from"
- ) {
- return end;
- }
- const from = walkCssTokens.eatIdentSequenceOrString(
- input,
- walkCssTokens.eatWhitespaceAndComments(input, fromWord[1])
- );
- if (!from) {
- return end;
- }
- const path = input.slice(from[0], from[1]);
- if (from[2] === true && path === "global") {
- const dep = new ConstDependency("", [
- customIdent[1],
- from[1]
- ]);
- module.addPresentationalDependency(dep);
- return end;
- } else if (from[2] === false) {
- const dep = new CssIcssImportDependency(
- path.slice(1, -1),
- name,
- [customIdent[0], from[1] - 1]
- );
- const { line: sl, column: sc } = locConverter.get(
- customIdent[0]
- );
- const { line: el, column: ec } = locConverter.get(
- from[1] - 1
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- }
- } else {
- const { line: sl, column: sc } = locConverter.get(
- customIdent[0]
- );
- const { line: el, column: ec } = locConverter.get(
- customIdent[1]
- );
- const dep = new CssSelfLocalIdentifierDependency(
- name,
- [customIdent[0], customIdent[1]],
- "--",
- declaredCssVariables
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return end;
- }
- }
- }
- }
- }
- return end;
- },
- leftParenthesis: (input, start, end) => {
- balanced.push(["(", start, end]);
- return end;
- },
- 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);
- }
- return end;
- },
- comma: (input, start, end) => {
- if (isModules) {
- // Reset stack for `:global .class :local .class-other` selector after
- modeData = undefined;
- if (scope === CSS_MODE_IN_BLOCK && isLocalMode()) {
- processDeclarationValueDone(input);
- }
- }
- lastTokenEndForComments = start;
- return end;
- }
- });
- /** @type {BuildInfo} */
- (module.buildInfo).strict = true;
- /** @type {BuildMeta} */
- (module.buildMeta).exportsType = this.namedExports
- ? "namespace"
- : "default";
- if (!this.namedExports) {
- /** @type {BuildMeta} */
- (module.buildMeta).defaultObject = "redirect";
- }
- module.addDependency(new StaticExportsDependency([], true));
- return state;
- }
- /**
- * @param {Range} range range
- * @returns {Comment[]} comments in the range
- */
- getComments(range) {
- if (!this.comments) return [];
- const [rangeStart, rangeEnd] = range;
- /**
- * @param {Comment} comment comment
- * @param {number} needle needle
- * @returns {number} compared
- */
- const compare = (comment, needle) =>
- /** @type {Range} */ (comment.range)[0] - needle;
- const comments = /** @type {Comment[]} */ (this.comments);
- let idx = binarySearchBounds.ge(comments, rangeStart, compare);
- /** @type {Comment[]} */
- const commentsInRange = [];
- while (
- comments[idx] &&
- /** @type {Range} */ (comments[idx].range)[1] <= rangeEnd
- ) {
- commentsInRange.push(comments[idx]);
- idx++;
- }
- return commentsInRange;
- }
- /**
- * @param {Range} range range of the comment
- * @returns {{ options: Record<string, any> | null, errors: (Error & { comment: Comment })[] | null }} result
- */
- parseCommentOptions(range) {
- const comments = this.getComments(range);
- if (comments.length === 0) {
- return EMPTY_COMMENT_OPTIONS;
- }
- /** @type {Record<string, EXPECTED_ANY> } */
- const options = {};
- /** @type {(Error & { comment: Comment })[]} */
- const errors = [];
- for (const comment of comments) {
- const { value } = comment;
- if (value && webpackCommentRegExp.test(value)) {
- // try compile only if webpack options comment is present
- try {
- for (let [key, val] of Object.entries(
- vm.runInContext(
- `(function(){return {${value}};})()`,
- this.magicCommentContext
- )
- )) {
- if (typeof val === "object" && val !== null) {
- val =
- val.constructor.name === "RegExp"
- ? new RegExp(val)
- : JSON.parse(JSON.stringify(val));
- }
- options[key] = val;
- }
- } catch (err) {
- const newErr = new Error(String(/** @type {Error} */ (err).message));
- newErr.stack = String(/** @type {Error} */ (err).stack);
- Object.assign(newErr, { comment });
- errors.push(/** @type (Error & { comment: Comment }) */ (newErr));
- }
- }
- }
- return { options, errors };
- }
- }
- module.exports = CssParser;
- module.exports.escapeIdentifier = escapeIdentifier;
- module.exports.unescapeIdentifier = unescapeIdentifier;
|