| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145214621472148214921502151215221532154215521562157215821592160216121622163216421652166216721682169217021712172217321742175217621772178217921802181218221832184218521862187218821892190219121922193219421952196219721982199220022012202220322042205220622072208220922102211221222132214221522162217221822192220222122222223222422252226222722282229223022312232223322342235223622372238223922402241224222432244224522462247224822492250225122522253225422552256225722582259226022612262226322642265226622672268226922702271227222732274227522762277227822792280228122822283228422852286228722882289229022912292229322942295229622972298229923002301230223032304230523062307230823092310231123122313231423152316231723182319232023212322232323242325232623272328232923302331233223332334233523362337233823392340234123422343234423452346234723482349235023512352235323542355235623572358235923602361236223632364236523662367236823692370237123722373237423752376237723782379238023812382238323842385238623872388238923902391239223932394239523962397239823992400240124022403240424052406240724082409241024112412241324142415241624172418241924202421242224232424242524262427242824292430243124322433243424352436243724382439244024412442244324442445244624472448244924502451245224532454245524562457245824592460246124622463246424652466246724682469247024712472247324742475247624772478247924802481248224832484248524862487248824892490249124922493249424952496249724982499250025012502250325042505250625072508250925102511251225132514251525162517251825192520252125222523252425252526252725282529253025312532253325342535253625372538253925402541254225432544254525462547254825492550255125522553255425552556255725582559256025612562256325642565256625672568256925702571257225732574257525762577257825792580258125822583258425852586258725882589259025912592259325942595259625972598259926002601260226032604260526062607260826092610261126122613261426152616261726182619262026212622 |
- /*
- 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 CssModule = require("../CssModule");
- 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 CssUrlDependency = require("../dependencies/CssUrlDependency");
- const StaticExportsDependency = require("../dependencies/StaticExportsDependency");
- const binarySearchBounds = require("../util/binarySearchBounds");
- const { parseResource } = require("../util/identifier");
- const {
- createMagicCommentContext,
- webpackCommentRegExp
- } = 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 {import("../../declarations/WebpackOptions").CssModuleParserOptions} CssModuleParserOptions */
- /** @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_SEMICOLON = ";".charCodeAt(0);
- const CC_COMMA = ",".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);
- // 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-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 = /\/\*((?!\*\/).*?)\*\//g;
- /**
- * @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;
- };
- /**
- * @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;
- };
- 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++);
- /** @type {string} */
- let value;
- if (/[\t\n\f\r\v]/.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;
- };
- /**
- * 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.
- * @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 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,
- unset: Infinity,
- revert: Infinity,
- "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_ARES = {
- // 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_ARES,
- ...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_ARES,
- ...GRID_TEMPLATE_COLUMNS_OR_ROWS
- };
- /**
- * @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-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_ARES);
- knownProperties.set("grid-template-columns", GRID_TEMPLATE_COLUMNS_OR_ROWS);
- knownProperties.set("grid-template-rows", GRID_TEMPLATE_COLUMNS_OR_ROWS);
- }
- return knownProperties;
- };
- 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 LOCAL_MODE = 0;
- const GLOBAL_MODE = 1;
- const eatUntilSemi = walkCssTokens.eatUntil(";");
- const eatUntilLeftCurly = walkCssTokens.eatUntil("{");
- /**
- * @typedef {object} CssParserOwnOptions
- * @property {("pure" | "global" | "local" | "auto")=} defaultMode default mode
- */
- /** @typedef {CssModuleParserOptions & CssParserOwnOptions} CssParserOptions */
- class CssParser extends Parser {
- /**
- * @param {CssParserOptions=} options options
- */
- constructor(options = {}) {
- super();
- 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();
- }
- /**
- * @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("utf8");
- } 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(
- // TODO matchResource
- parseResource(/** @type {string} */ (module.getResource())).path
- )
- ) {
- mode = "local";
- }
- 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;
- const locConverter = new LocConverter(source);
- /** @type {number} */
- let scope = CSS_MODE_TOP_LEVEL;
- /** @type {boolean} */
- let allowImportAtRule = true;
- /** @type {[string, number, number, boolean?][]} */
- const balanced = [];
- let lastTokenEndForComments = 0;
- /** @type {boolean} */
- let isNextRulePrelude = isModules;
- /** @type {number} */
- let blockNestingLevel = 0;
- /** @type {0 | 1 | undefined} */
- let modeData;
- /** @type {string[]} */
- let lastLocalIdentifiers = [];
- /** @typedef {{ value: string, isReference?: boolean }} IcssDefinition */
- /** @type {Map<string, IcssDefinition>} */
- 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)[0];
- if (
- input.charCodeAt(pos) === CC_RIGHT_CURLY ||
- (input.charCodeAt(pos) === CC_HYPHEN_MINUS &&
- input.charCodeAt(pos + 1) === CC_HYPHEN_MINUS)
- ) {
- return false;
- }
- const identifier = walkCssTokens.eatIdentSequence(input, pos);
- 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;
- };
- /**
- * @returns {boolean} true, when in local scope
- */
- const isLocalMode = () =>
- modeData === LOCAL_MODE || (mode === "local" && modeData === 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;
- };
- // Vanilla CSS stuff
- /**
- * @param {string} input input
- * @param {number} start name start position
- * @param {number} end name end position
- * @returns {number} position after handling
- */
- const processAtImport = (input, start, 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;
- }
- /** @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]) {
- 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]
- )[0];
- /** @type {undefined | string} */
- 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],
- mode === "local" || mode === "global" ? mode : undefined,
- layer,
- supports && supports.length > 0 ? supports : undefined,
- media && media.length > 0 ? media : undefined
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return newline;
- };
- /**
- * @param {string} input input
- * @param {number} end end position
- * @param {string} name the name of function
- * @returns {number} position after handling
- */
- const processURLFunction = (input, end, name) => {
- 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];
- };
- /**
- * @param {string} input input
- * @param {number} start start position
- * @param {number} end end position
- * @param {number} contentStart start position
- * @param {number} contentEnd end position
- * @returns {number} position after handling
- */
- const processOldURLFunction = (
- input,
- start,
- end,
- contentStart,
- contentEnd
- ) => {
- 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;
- };
- /**
- * @param {string} input input
- * @param {number} start start position
- * @param {number} end end position
- * @returns {number} position after handling
- */
- const processImageSetFunction = (input, start, end) => {
- 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;
- };
- // CSS modules stuff
- /**
- * @param {string} value value to resolve
- * @returns {string | [string, string, boolean]} resolved reexport
- */
- const getReexport = (value) => {
- const reexport = icssDefinitions.get(value);
- if (reexport) {
- if (reexport.isReference) {
- return [value, reexport.value, true];
- }
- return [value, reexport.value, false];
- }
- return value;
- };
- /**
- * @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)[0];
- /** @type {string | undefined} */
- let request;
- 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 '${type ? ":import" : ":export"}' (expected string)`,
- locConverter,
- stringStart,
- pos
- );
- return pos;
- }
- request = input.slice(str[0] + 1, str[1] - 1);
- pos = str[1];
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
- 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)[0];
- }
- /**
- * @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) {
- const dep = new CssIcssImportDependency(
- /** @type {string} */
- (request),
- [0, 0],
- /** @type {"local" | "global"} */
- (mode),
- 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);
- icssDefinitions.set(name, { value, isReference: true });
- } else if (type === 1) {
- 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);
- module.addDependency(dep);
- }
- };
- let needTerminate = false;
- let balanced = 0;
- /** @type {undefined | 0 | 1 | 2} */
- let scope;
- /** @typedef {[number, number]} Name */
- /** @type {Name | 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) {
- const [nameStart, nameEnd] = /** @type {Name} */ (name);
- createDep(
- input.slice(nameStart, nameEnd),
- input.slice(value, end - 1).trim(),
- nameEnd,
- 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) {
- const [nameStart, nameEnd] = /** @type {Name} */ (name);
- createDep(
- input.slice(nameStart, nameEnd),
- input.slice(value, end - 1),
- nameEnd,
- end - 1
- );
- scope = 0;
- }
- return end;
- },
- needTerminate: () => needTerminate
- };
- pos = walkCssTokens(input, pos, callbacks);
- pos = walkCssTokens.eatWhiteLine(input, pos);
- return pos;
- };
- /**
- * @param {string} input input
- * @param {number} start name start position
- * @param {number} end name end position
- * @returns {number} position after handling
- */
- const processAtValue = (input, start, end) => {
- const semi = eatUntilSemi(input, end);
- const atRuleEnd = semi + 1;
- const params = input.slice(end, semi);
- let [alias, request] = params.split(/\s*from\s*/);
- 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
- });
- }
- {
- const dep = new CssIcssExportDependency(
- aliasName || name,
- getReexport(aliasName || name),
- 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 {
- 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])[0];
- 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.replace(CSS_COMMENT, ""))) {
- value = value.trim();
- }
- if (icssDefinitions.has(value)) {
- const def =
- /** @type {IcssDefinition} */
- (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;
- };
- /**
- * @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 } =
- /** @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,
- [start, end],
- isReference
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return end;
- };
- /**
- * @param {string} input input
- * @param {1 | 2} type type of function
- * @param {number} start start position
- * @param {number} end end position
- * @returns {number} position after handling
- */
- const processLocalOrGlobalFunction = (input, type, start, end) => {
- // Replace `local(`/` or `global(` (handle legacy `:local(` or `:global(` too)
- {
- const isColon = input.charCodeAt(start - 1) === CC_COLON;
- const dep = new ConstDependency("", [isColon ? start - 1 : start, end]);
- module.addPresentationalDependency(dep);
- }
- end = walkCssTokens.consumeUntil(
- input,
- start,
- {
- 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);
- 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 }
- );
- {
- // Replace the last `)`
- const dep = new ConstDependency("", [end, end + 1]);
- module.addPresentationalDependency(dep);
- }
- return end;
- };
- /**
- * @param {string} input input
- * @param {number} end name end position
- * @param {{ string?: boolean, identifier?: boolean | RegExp }} options types which allowed to handle
- * @returns {number} position after handling
- */
- const processLocalAtRule = (input, end, options) => {
- let found = false;
- 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;
- }
- return end;
- },
- 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) => {
- // No need to handle `:` (COLON), because it's always a function
- const name = input
- .slice(start, end - 1)
- .replace(/\\/g, "")
- .toLowerCase();
- const type =
- name === "local" ? 1 : name === "global" ? 2 : undefined;
- if (!found && type) {
- found = true;
- 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 }
- );
- };
- /**
- * @param {string} input input
- * @param {number} start start position
- * @param {number} end end position
- * @returns {number} position after handling
- */
- const processDashedIdent = (input, start, end) => {
- const customIdent = walkCssTokens.eatIdentSequence(input, start);
- if (!customIdent) return end;
- 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
- ) {
- 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])[0]
- );
- 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 { line: sl, column: sc } = locConverter.get(customIdent[0]);
- const { line: el, column: ec } = locConverter.get(from[1] - 1);
- const dep = new CssIcssImportDependency(
- path.slice(1, -1),
- [customIdent[0], from[1] - 1],
- /** @type {"local" | "global"} */
- (mode),
- identifier,
- identifier,
- CssIcssExportDependency.EXPORT_MODE.NONE,
- CssIcssExportDependency.EXPORT_TYPE.CUSTOM_VARIABLE
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- {
- const dep = new ConstDependency("", [fromWord[0], from[1]]);
- module.addPresentationalDependency(dep);
- return end;
- }
- }
- } else {
- const { line: sl, column: sc } = locConverter.get(customIdent[0]);
- const { line: el, column: ec } = locConverter.get(customIdent[1]);
- const dep = new CssIcssExportDependency(
- identifier,
- getReexport(identifier),
- [customIdent[0], customIdent[1]],
- true,
- CssIcssExportDependency.EXPORT_MODE.ONCE,
- CssIcssExportDependency.EXPORT_TYPE.CUSTOM_VARIABLE
- );
- dep.setLoc(sl, sc, el, ec);
- module.addDependency(dep);
- return end;
- }
- return end;
- };
- /**
- * @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) => {
- 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 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;
- const end = walkCssTokens.consumeUntil(
- input,
- pos,
- {
- 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) {
- 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) {
- if (isGridTemplate) {
- 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 (
- keywords[keyword] &&
- parsedKeywords[keyword] < keywords[keyword]
- ) {
- return end;
- }
- values.push([start, end]);
- return end;
- },
- comma(_input, _start, end) {
- parsedKeywords = {};
- return end;
- }
- },
- {
- function: (input, start, end) => {
- const name = input
- .slice(start, end - 1)
- .replace(/\\/g, "")
- .toLowerCase();
- const type =
- name === "local" ? 1 : name === "global" ? 2 : undefined;
- if (type) {
- 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: !isGridTemplate,
- declarationValue: true
- }
- );
- 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 CssIcssExportDependency(
- name,
- 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);
- }
- }
- return end;
- } else if (COMPOSES_PROPERTY.test(propertyName)) {
- if (lastLocalIdentifiers.length > 1) {
- const end = eatUntilSemi(input, pos);
- this._emitWarning(
- state,
- `Composition is only allowed when selector is single local class name not in "${lastLocalIdentifiers.join('", "')}"`,
- locConverter,
- pos,
- end
- );
- return end;
- }
- if (lastLocalIdentifiers.length !== 1) return pos;
- const lastLocalIdentifier = lastLocalIdentifiers[0];
- let end = pos;
- /** @type {Set<[number, number]>} */
- const classNames = new Set();
- while (true) {
- pos = walkCssTokens.eatWhitespaceAndComments(input, pos)[0];
- let className = walkCssTokens.eatIdentSequence(input, pos);
- const ifFunction =
- className && input.charCodeAt(className[1]) === CC_LEFT_PARENTHESIS;
- let isGlobalFunction = false;
- if (className && ifFunction) {
- const name = input
- .slice(className[0], className[1])
- .replace(/\\/g, "")
- .toLowerCase();
- isGlobalFunction = name === "global";
- pos = walkCssTokens.eatWhitespaceAndComments(
- input,
- className[1] + 1
- )[0];
- className = walkCssTokens.eatIdentSequence(input, pos);
- if (className) {
- pos = walkCssTokens.eatWhitespaceAndComments(
- input,
- className[1]
- )[0];
- pos += 1;
- }
- } else if (className) {
- pos = walkCssTokens.eatWhitespaceAndComments(
- input,
- className[1]
- )[0];
- pos = className[1];
- }
- // True when we have multiple values
- const isComma = input.charCodeAt(pos) === CC_COMMA;
- const isSemicolon = input.charCodeAt(pos) === CC_SEMICOLON;
- const isRightCurly = input.charCodeAt(pos) === CC_RIGHT_CURLY;
- if (isComma || isSemicolon || isRightCurly) {
- if (className) {
- classNames.add(className);
- }
- for (const className of classNames) {
- const [start, end] = className;
- const identifier = unescapeIdentifier(input.slice(start, end));
- const resolvedClassName = getReexport(identifier);
- const dep = new CssIcssExportDependency(
- lastLocalIdentifier,
- resolvedClassName,
- [start, end],
- isGlobalFunction ? false : !Array.isArray(resolvedClassName),
- isGlobalFunction
- ? CssIcssExportDependency.EXPORT_MODE.APPEND
- : CssIcssExportDependency.EXPORT_MODE.SELF_REFERENCE
- );
- 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);
- }
- classNames.clear();
- if (isSemicolon || isRightCurly) {
- end = isSemicolon
- ? walkCssTokens.eatWhitespace(input, pos + 1)
- : pos;
- break;
- }
- pos += 1;
- } else if (
- classNames.size > 0 &&
- className &&
- input.slice(className[0], className[1]).toLowerCase() === "from"
- ) {
- let from = walkCssTokens.eatString(input, pos);
- if (from) {
- const request = input.slice(from[0] + 1, from[1] - 1);
- for (const className of classNames) {
- const [start, end] = className;
- const identifier = unescapeIdentifier(input.slice(start, end));
- const dep = new CssIcssImportDependency(
- request,
- [start, end],
- /** @type {"local" | "global"} */
- (mode),
- identifier,
- /** @type {string} */
- (lastLocalIdentifier),
- CssIcssExportDependency.EXPORT_MODE.APPEND
- );
- 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);
- }
- classNames.clear();
- pos = from[1];
- } else {
- from = walkCssTokens.eatIdentSequence(input, pos);
- if (from && input.slice(from[0], from[1]) === "global") {
- for (const className of classNames) {
- const [start, end] = className;
- const identifier = unescapeIdentifier(
- input.slice(start, end)
- );
- const dep = new CssIcssExportDependency(
- /** @type {string} */
- (lastLocalIdentifier),
- getReexport(identifier),
- [start, end],
- false,
- CssIcssExportDependency.EXPORT_MODE.APPEND
- );
- 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);
- }
- classNames.clear();
- pos = from[1];
- } else {
- const end = eatUntilSemi(input, pos);
- this._emitWarning(
- state,
- "Incorrect composition, expected global keyword or string value",
- locConverter,
- pos,
- end
- );
- return end;
- }
- }
- } else if (className) {
- classNames.add(className);
- } else {
- const end = eatUntilSemi(input, pos);
- this._emitWarning(
- state,
- "Incorrect composition, expected class named",
- locConverter,
- pos,
- end
- );
- return end;
- }
- }
- // Remove `composes` from source code
- const dep = new ConstDependency("", [propertyNameStart, end]);
- module.addPresentationalDependency(dep);
- }
- return pos;
- };
- /**
- * @param {string} input input
- * @param {number} start start position
- * @param {number} end end position
- * @returns {number} position after handling
- */
- const processIdSelector = (input, start, end) => {
- const valueStart = start + 1;
- const name = unescapeIdentifier(input.slice(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;
- };
- /**
- * @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];
- };
- /**
- * @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, {
- 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;
- lastLocalIdentifiers = [];
- }
- } else if (isModules) {
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- break;
- }
- }
- return end;
- },
- url: (input, start, end, contentStart, contentEnd) => {
- if (!this.options.url) {
- return end;
- }
- return processOldURLFunction(
- input,
- start,
- end,
- contentStart,
- contentEnd
- );
- },
- 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.options.import) {
- return eatUntilSemi(input, end);
- }
- if (!allowImportAtRule) {
- this._emitWarning(
- state,
- "Any '@import' rules must precede all other rules",
- locConverter,
- start,
- end
- );
- return end;
- }
- return processAtImport(input, start, end);
- }
- default: {
- if (isModules) {
- if (name === "@value") {
- return processAtValue(input, start, end);
- } else if (
- this.options.animation &&
- OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) &&
- isLocalMode()
- ) {
- return processLocalAtRule(input, end, {
- string: true,
- identifier: true
- });
- } else if (
- this.options.customIdents &&
- name === "@counter-style" &&
- isLocalMode()
- ) {
- return processLocalAtRule(input, end, {
- 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;
- return end;
- }
- isNextRulePrelude = false;
- }
- }
- }
- return end;
- },
- semicolon: (input, start, end) => {
- if (isModules && scope === CSS_MODE_IN_BLOCK) {
- isNextRulePrelude = isNextNestedSyntax(input, end);
- }
- return end;
- },
- identifier: (input, start, end) => {
- if (isModules) {
- const identifier = input.slice(start, end);
- if (icssDefinitions.has(identifier)) {
- return processICSSSymbol(identifier, start, end);
- }
- if (
- this.options.dashedIdents &&
- isLocalMode() &&
- isDashedIdentifier(identifier)
- ) {
- return processDashedIdent(input, start, end);
- }
- switch (scope) {
- case CSS_MODE_IN_BLOCK: {
- if (isModules && !isNextRulePrelude) {
- // Handle only top level values and not inside functions
- return processLocalDeclaration(input, start, end);
- }
- break;
- }
- }
- }
- return end;
- },
- delim: (input, start, end) => {
- if (isNextRulePrelude && isLocalMode()) {
- return processClassSelector(input, start, end);
- }
- return end;
- },
- hash: (input, start, end, isID) => {
- if (isNextRulePrelude && isLocalMode() && isID) {
- return processIdSelector(input, start, end);
- }
- 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 = processImportOrExport(0, input, ident[1]);
- const dep = new ConstDependency("", [start, pos]);
- module.addPresentationalDependency(dep);
- return pos;
- } else if (name === "export") {
- const pos = processImportOrExport(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") {
- // Eat extra whitespace
- 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, true]);
- return end;
- } else if (name === "local") {
- modeData = LOCAL_MODE;
- const found = walkCssTokens.eatWhitespaceAndComments(
- input,
- ident[1]
- );
- if (!found[1]) {
- this._emitWarning(
- state,
- `Missing whitespace after ':local' in '${input.slice(
- start,
- eatUntilLeftCurly(input, end) + 1
- )}'`,
- locConverter,
- start,
- end
- );
- }
- 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.eatWhitespaceAndComments(
- input,
- ident[1] + 1
- )[0];
- modeData = GLOBAL_MODE;
- const dep = new ConstDependency("", [start, end]);
- module.addPresentationalDependency(dep);
- balanced.push([":global", start, end, true]);
- return end;
- } else if (name === "global") {
- modeData = GLOBAL_MODE;
- // Eat extra whitespace
- const found = walkCssTokens.eatWhitespaceAndComments(
- input,
- ident[1]
- );
- if (!found[1]) {
- this._emitWarning(
- state,
- `Missing whitespace after ':global' in '${input.slice(
- start,
- eatUntilLeftCurly(input, end) + 1
- )}'`,
- locConverter,
- start,
- end
- );
- }
- end = walkCssTokens.eatWhitespace(input, ident[1]);
- 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.options.url) {
- return end;
- }
- return processURLFunction(input, end, name);
- }
- default: {
- if (this.options.url && IMAGE_SET_FUNCTION.test(name)) {
- return processImageSetFunction(input, start, 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) => {
- balanced.push(["(", start, end]);
- return end;
- },
- rightParenthesis: (input, start, end) => {
- const popped = balanced.pop();
- 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;
- }
- }
- lastTokenEndForComments = start;
- return end;
- }
- });
- /** @type {BuildInfo} */
- (module.buildInfo).strict = true;
- const buildMeta = /** @type {BuildMeta} */ (state.module.buildMeta);
- buildMeta.exportsType = this.options.namedExports ? "namespace" : "default";
- buildMeta.defaultObject = this.options.namedExports
- ? false
- : "redirect-warn";
- buildMeta.exportType = this.options.exportType;
- 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;
- }
- }
- if (!buildMeta.exportType) {
- buildMeta.exportType = "link";
- }
- // TODO this.namedExports?
- if (
- buildMeta.exportType === "text" ||
- buildMeta.exportType === "css-style-sheet"
- ) {
- module.addDependency(new StaticExportsDependency(["default"], true));
- } else {
- 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, EXPECTED_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;
|