| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618 |
- /*
- 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-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 COMPOSES_PROPERTY = /^(composes|compose-with)$/i;
- const IS_MODULES = /\.module(s)?\.[^.]+$/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 = [];
- 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;
- };
- // 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;
- // eslint-disable-next-line no-control-regex
- 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;
- };
- /**
- * 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;
- }
- 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]
- )[0];
- 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;
|