| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624 | /*	MIT License http://www.opensource.org/licenses/mit-license.php	Author Tobias Koppers @sokra*/"use strict";const vm = require("vm");const CommentCompilationWarning = require("../CommentCompilationWarning");const ModuleDependencyWarning = require("../ModuleDependencyWarning");const { CSS_MODULE_TYPE_AUTO } = require("../ModuleTypeConstants");const Parser = require("../Parser");const UnsupportedFeatureWarning = require("../UnsupportedFeatureWarning");const WebpackError = require("../WebpackError");const ConstDependency = require("../dependencies/ConstDependency");const CssIcssExportDependency = require("../dependencies/CssIcssExportDependency");const CssIcssImportDependency = require("../dependencies/CssIcssImportDependency");const CssIcssSymbolDependency = require("../dependencies/CssIcssSymbolDependency");const CssImportDependency = require("../dependencies/CssImportDependency");const CssLocalIdentifierDependency = require("../dependencies/CssLocalIdentifierDependency");const CssSelfLocalIdentifierDependency = require("../dependencies/CssSelfLocalIdentifierDependency");const CssUrlDependency = require("../dependencies/CssUrlDependency");const StaticExportsDependency = require("../dependencies/StaticExportsDependency");const binarySearchBounds = require("../util/binarySearchBounds");const { parseResource } = require("../util/identifier");const {	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 {[number, number]} Range *//** @typedef {{ line: number, column: number }} Position *//** @typedef {{ value: string, range: Range, loc: { start: Position, end: Position } }} Comment */const CC_COLON = ":".charCodeAt(0);const CC_SLASH = "/".charCodeAt(0);const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);const CC_RIGHT_PARENTHESIS = ")".charCodeAt(0);const CC_LOWER_F = "f".charCodeAt(0);const CC_UPPER_F = "F".charCodeAt(0);// https://www.w3.org/TR/css-syntax-3/#newline// We don't have `preprocessing` stage, so we need specify all of themconst STRING_MULTILINE = /\\[\n\r\f]/g;// https://www.w3.org/TR/css-syntax-3/#whitespaceconst TRIM_WHITE_SPACES = /(^[ \t\n\r\f]*|[ \t\n\r\f]*$)/g;const UNESCAPE = /\\([0-9a-fA-F]{1,6}[ \t\n\r\f]?|[\s\S])/g;const IMAGE_SET_FUNCTION = /^(-\w+-)?image-set$/i;const OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE = /^@(-\w+-)?keyframes$/;const OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY =	/^(-\w+-)?animation(-name)?$/i;const IS_MODULES = /\.module(s)?\.[^.]+$/i;const CSS_COMMENT = /\/\*((?!\*\/).*?)\*\//g;/** * @param {string} str url string * @param {boolean} isString is url wrapped in quotes * @returns {string} normalized url */const normalizeUrl = (str, isString) => {	// Remove extra spaces and newlines:	// `url("im\	// g.png")`	if (isString) {		str = str.replace(STRING_MULTILINE, "");	}	str = str		// Remove unnecessary spaces from `url("   img.png	 ")`		.replace(TRIM_WHITE_SPACES, "")		// Unescape		.replace(UNESCAPE, match => {			if (match.length > 2) {				return String.fromCharCode(Number.parseInt(match.slice(1).trim(), 16));			}			return match[1];		});	if (/^data:/i.test(str)) {		return str;	}	if (str.includes("%")) {		// Convert `url('%2E/img.png')` -> `url('./img.png')`		try {			str = decodeURIComponent(str);		} catch (_err) {			// Ignore		}	}	return str;};// eslint-disable-next-line no-useless-escapeconst 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;};class LocConverter {	/**	 * @param {string} input input	 */	constructor(input) {		this._input = input;		this.line = 1;		this.column = 0;		this.pos = 0;	}	/**	 * @param {number} pos position	 * @returns {LocConverter} location converter	 */	get(pos) {		if (this.pos !== pos) {			if (this.pos < pos) {				const str = this._input.slice(this.pos, pos);				let i = str.lastIndexOf("\n");				if (i === -1) {					this.column += str.length;				} else {					this.column = str.length - i - 1;					this.line++;					while (i > 0 && (i = str.lastIndexOf("\n", i - 1)) !== -1) {						this.line++;					}				}			} else {				let i = this._input.lastIndexOf("\n", this.pos);				while (i >= pos) {					this.line--;					i = i > 0 ? this._input.lastIndexOf("\n", i - 1) : -1;				}				this.column = pos - i;			}			this.pos = pos;		}		return this;	}}const EMPTY_COMMENT_OPTIONS = {	options: null,	errors: null};const CSS_MODE_TOP_LEVEL = 0;const CSS_MODE_IN_BLOCK = 1;const eatUntilSemi = walkCssTokens.eatUntil(";");const eatUntilLeftCurly = walkCssTokens.eatUntil("{");const eatSemi = walkCssTokens.eatUntil(";");/** * @typedef {object} CssParserOptions * @property {boolean=} importOption need handle `@import` * @property {boolean=} url need handle URLs * @property {("pure" | "global" | "local" | "auto")=} defaultMode default mode * @property {boolean=} namedExports is named exports */class CssParser extends Parser {	/**	 * @param {CssParserOptions=} options options	 */	constructor({		defaultMode = "pure",		importOption = true,		url = true,		namedExports = true	} = {}) {		super();		this.defaultMode = defaultMode;		this.import = importOption;		this.url = url;		this.namedExports = namedExports;		/** @type {Comment[] | undefined} */		this.comments = undefined;		this.magicCommentContext = createMagicCommentContext();	}	/**	 * @param {ParserState} state parser state	 * @param {string} message warning message	 * @param {LocConverter} locConverter location converter	 * @param {number} start start offset	 * @param {number} end end offset	 */	_emitWarning(state, message, locConverter, start, end) {		const { line: sl, column: sc } = locConverter.get(start);		const { line: el, column: ec } = locConverter.get(end);		state.current.addWarning(			new ModuleDependencyWarning(state.module, new WebpackError(message), {				start: { line: sl, column: sc },				end: { line: el, column: ec }			})		);	}	/**	 * @param {string | Buffer | PreparsedAst} source the source to parse	 * @param {ParserState} state the parser state	 * @returns {ParserState} the parser state	 */	parse(source, state) {		if (Buffer.isBuffer(source)) {			source = source.toString("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(				parseResource(module.matchResource || module.resource).path			)		) {			mode = "local";		}		const isModules = mode === "global" || mode === "local";		/** @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][] */		const balanced = [];		let lastTokenEndForComments = 0;		/** @type {boolean} */		let isNextRulePrelude = isModules;		/** @type {number} */		let blockNestingLevel = 0;		/** @type {"local" | "global" | undefined} */		let modeData;		/** @type {boolean} */		let inAnimationProperty = false;		/** @type {[number, number, boolean] | undefined} */		let lastIdentifier;		/** @type {Set<string>} */		const declaredCssVariables = new Set();		/** @typedef {{ path?: string, value: string }} 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);			if (input[pos] === "}") {				return false;			}			// According spec only identifier can be used as a property name			const isIdentifier = walkCssTokens.isIdentStartCodePoint(				input.charCodeAt(pos)			);			return !isIdentifier;		};		/**		 * @returns {boolean} true, when in local scope		 */		const isLocalMode = () =>			modeData === "local" || (mode === "local" && modeData === undefined);		/**		 * @param {string} input input		 * @param {number} pos start position		 * @param {(input: string, pos: number) => number} eater eater		 * @returns {[number,string]} new position and text		 */		const eatText = (input, pos, eater) => {			let text = "";			for (;;) {				if (input.charCodeAt(pos) === CC_SLASH) {					const newPos = walkCssTokens.eatComments(input, pos);					if (pos !== newPos) {						pos = newPos;						if (pos === input.length) break;					} else {						text += "/";						pos++;						if (pos === input.length) break;					}				}				const newPos = eater(input, pos);				if (pos !== newPos) {					text += input.slice(pos, newPos);					pos = newPos;				} else {					break;				}				if (pos === input.length) break;			}			return [pos, text.trimEnd()];		};		/**		 * @param {0 | 1} type import or export		 * @param {string} input input		 * @param {number} pos start position		 * @returns {number} position after parse		 */		const parseImportOrExport = (type, input, pos) => {			pos = walkCssTokens.eatWhitespaceAndComments(input, pos);			/** @type {string | undefined} */			let importPath;			if (type === 0) {				let cc = input.charCodeAt(pos);				if (cc !== CC_LEFT_PARENTHESIS) {					this._emitWarning(						state,						`Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected '(')`,						locConverter,						pos,						pos					);					return pos;				}				pos++;				const stringStart = pos;				const str = walkCssTokens.eatString(input, pos);				if (!str) {					this._emitWarning(						state,						`Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected string)`,						locConverter,						stringStart,						pos					);					return pos;				}				importPath = input.slice(str[0] + 1, str[1] - 1);				pos = str[1];				pos = walkCssTokens.eatWhitespaceAndComments(input, pos);				cc = input.charCodeAt(pos);				if (cc !== CC_RIGHT_PARENTHESIS) {					this._emitWarning(						state,						`Unexpected '${input[pos]}' at ${pos} during parsing of ':import' (expected ')')`,						locConverter,						pos,						pos					);					return pos;				}				pos++;				pos = walkCssTokens.eatWhitespaceAndComments(input, pos);			}			/**			 * @param {string} name name			 * @param {string} value value			 * @param {number} start start of position			 * @param {number} end end of position			 */			const createDep = (name, value, start, end) => {				if (type === 0) {					icssDefinitions.set(name, {						path: /** @type {string} */ (importPath),						value					});				} else if (type === 1) {					const dep = new CssIcssExportDependency(name, value);					const { line: sl, column: sc } = locConverter.get(start);					const { line: el, column: ec } = locConverter.get(end);					dep.setLoc(sl, sc, el, ec);					module.addDependency(dep);				}			};			let needTerminate = false;			let balanced = 0;			/** @type {undefined | 0 | 1 | 2} */			let scope;			/** @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;		};		const eatPropertyName = walkCssTokens.eatUntil(":{};");		/**		 * @param {string} input input		 * @param {number} pos name start position		 * @param {number} end name end position		 * @returns {number} position after handling		 */		const processLocalDeclaration = (input, pos, end) => {			modeData = undefined;			pos = walkCssTokens.eatWhitespaceAndComments(input, pos);			const propertyNameStart = pos;			const [propertyNameEnd, propertyName] = eatText(				input,				pos,				eatPropertyName			);			if (input.charCodeAt(propertyNameEnd) !== CC_COLON) return end;			pos = propertyNameEnd + 1;			if (propertyName.startsWith("--") && propertyName.length >= 3) {				// CSS Variable				const { line: sl, column: sc } = locConverter.get(propertyNameStart);				const { line: el, column: ec } = locConverter.get(propertyNameEnd);				const name = unescapeIdentifier(propertyName.slice(2));				const dep = new CssLocalIdentifierDependency(					name,					[propertyNameStart, propertyNameEnd],					"--"				);				dep.setLoc(sl, sc, el, ec);				module.addDependency(dep);				declaredCssVariables.add(name);			} else if (				OPTIONALLY_VENDOR_PREFIXED_ANIMATION_PROPERTY.test(propertyName)			) {				inAnimationProperty = true;			}			return pos;		};		/**		 * @param {string} input input		 */		const processDeclarationValueDone = input => {			if (inAnimationProperty && lastIdentifier) {				const { line: sl, column: sc } = locConverter.get(lastIdentifier[0]);				const { line: el, column: ec } = locConverter.get(lastIdentifier[1]);				const name = unescapeIdentifier(					lastIdentifier[2]						? input.slice(lastIdentifier[0], lastIdentifier[1])						: input.slice(lastIdentifier[0] + 1, lastIdentifier[1] - 1)				);				const dep = new CssSelfLocalIdentifierDependency(name, [					lastIdentifier[0],					lastIdentifier[1]				]);				dep.setLoc(sl, sc, el, ec);				module.addDependency(dep);				lastIdentifier = undefined;			}		};		/**		 * @param {string} input input		 * @param {number} start start		 * @param {number} end end		 * @returns {number} end		 */		const comment = (input, start, end) => {			if (!this.comments) this.comments = [];			const { line: sl, column: sc } = locConverter.get(start);			const { line: el, column: ec } = locConverter.get(end);			/** @type {Comment} */			const comment = {				value: input.slice(start + 2, end - 2),				range: [start, end],				loc: {					start: { line: sl, column: sc },					end: { line: el, column: ec }				}			};			this.comments.push(comment);			return end;		};		walkCssTokens(source, 0, {			comment,			leftCurlyBracket: (input, start, end) => {				switch (scope) {					case CSS_MODE_TOP_LEVEL: {						allowImportAtRule = false;						scope = CSS_MODE_IN_BLOCK;						if (isModules) {							blockNestingLevel = 1;							isNextRulePrelude = isNextNestedSyntax(input, end);						}						break;					}					case CSS_MODE_IN_BLOCK: {						if (isModules) {							blockNestingLevel++;							isNextRulePrelude = isNextNestedSyntax(input, end);						}						break;					}				}				return end;			},			rightCurlyBracket: (input, start, end) => {				switch (scope) {					case CSS_MODE_IN_BLOCK: {						if (--blockNestingLevel === 0) {							scope = CSS_MODE_TOP_LEVEL;							if (isModules) {								isNextRulePrelude = true;								modeData = undefined;							}						} else if (isModules) {							if (isLocalMode()) {								processDeclarationValueDone(input);								inAnimationProperty = false;							}							isNextRulePrelude = isNextNestedSyntax(input, end);						}						break;					}				}				return end;			},			url: (input, start, end, contentStart, contentEnd) => {				if (!this.url) {					return end;				}				const { options, errors: commentErrors } = this.parseCommentOptions([					lastTokenEndForComments,					end				]);				if (commentErrors) {					for (const e of commentErrors) {						const { comment } = e;						state.module.addWarning(							new CommentCompilationWarning(								`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,								comment.loc							)						);					}				}				if (options && options.webpackIgnore !== undefined) {					if (typeof options.webpackIgnore !== "boolean") {						const { line: sl, column: sc } = locConverter.get(							lastTokenEndForComments						);						const { line: el, column: ec } = locConverter.get(end);						state.module.addWarning(							new UnsupportedFeatureWarning(								`\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,								{									start: { line: sl, column: sc },									end: { line: el, column: ec }								}							)						);					} else if (options.webpackIgnore) {						return end;					}				}				const value = normalizeUrl(					input.slice(contentStart, contentEnd),					false				);				// Ignore `url()`, `url('')` and `url("")`, they are valid by spec				if (value.length === 0) return end;				const dep = new CssUrlDependency(value, [start, end], "url");				const { line: sl, column: sc } = locConverter.get(start);				const { line: el, column: ec } = locConverter.get(end);				dep.setLoc(sl, sc, el, ec);				module.addDependency(dep);				module.addCodeGenerationDependency(dep);				return end;			},			string: (_input, start, end) => {				switch (scope) {					case CSS_MODE_IN_BLOCK: {						if (inAnimationProperty && balanced.length === 0) {							lastIdentifier = [start, end, false];						}					}				}				return end;			},			atKeyword: (input, start, end) => {				const name = input.slice(start, end).toLowerCase();				switch (name) {					case "@namespace": {						this._emitWarning(							state,							"'@namespace' is not supported in bundled CSS",							locConverter,							start,							end						);						return eatUntilSemi(input, start);					}					case "@import": {						if (!this.import) {							return eatSemi(input, end);						}						if (!allowImportAtRule) {							this._emitWarning(								state,								"Any '@import' rules must precede all other rules",								locConverter,								start,								end							);							return end;						}						const tokens = walkCssTokens.eatImportTokens(input, end, {							comment						});						if (!tokens[3]) return end;						const semi = tokens[3][1];						if (!tokens[0]) {							this._emitWarning(								state,								`Expected URL in '${input.slice(start, semi)}'`,								locConverter,								start,								semi							);							return end;						}						const urlToken = tokens[0];						const url = normalizeUrl(							input.slice(urlToken[2], urlToken[3]),							true						);						const newline = walkCssTokens.eatWhiteLine(input, semi);						const { options, errors: commentErrors } = this.parseCommentOptions(							[end, urlToken[1]]						);						if (commentErrors) {							for (const e of commentErrors) {								const { comment } = e;								state.module.addWarning(									new CommentCompilationWarning(										`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,										comment.loc									)								);							}						}						if (options && options.webpackIgnore !== undefined) {							if (typeof options.webpackIgnore !== "boolean") {								const { line: sl, column: sc } = locConverter.get(start);								const { line: el, column: ec } = locConverter.get(newline);								state.module.addWarning(									new UnsupportedFeatureWarning(										`\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,										{											start: { line: sl, column: sc },											end: { line: el, column: ec }										}									)								);							} else if (options.webpackIgnore) {								return newline;							}						}						if (url.length === 0) {							const { line: sl, column: sc } = locConverter.get(start);							const { line: el, column: ec } = locConverter.get(newline);							const dep = new ConstDependency("", [start, newline]);							module.addPresentationalDependency(dep);							dep.setLoc(sl, sc, el, ec);							return newline;						}						let layer;						if (tokens[1]) {							layer = input.slice(tokens[1][0] + 6, tokens[1][1] - 1).trim();						}						let supports;						if (tokens[2]) {							supports = input.slice(tokens[2][0] + 9, tokens[2][1] - 1).trim();						}						const last = tokens[2] || tokens[1] || tokens[0];						const mediaStart = walkCssTokens.eatWhitespaceAndComments(							input,							last[1]						);						let media;						if (mediaStart !== semi - 1) {							media = input.slice(mediaStart, semi - 1).trim();						}						const { line: sl, column: sc } = locConverter.get(start);						const { line: el, column: ec } = locConverter.get(newline);						const dep = new CssImportDependency(							url,							[start, newline],							layer,							supports && supports.length > 0 ? supports : undefined,							media && media.length > 0 ? media : undefined						);						dep.setLoc(sl, sc, el, ec);						module.addDependency(dep);						return newline;					}					default: {						if (isModules) {							if (name === "@value") {								const semi = eatUntilSemi(input, end);								const atRuleEnd = semi + 1;								const params = input.slice(end, semi);								let [alias, from] = params.split(/\s*from\s*/);								if (from) {									const aliases = alias										.replace(CSS_COMMENT, " ")										.trim()										.replace(/^\(|\)$/g, "")										.split(/\s*,\s*/);									from = from.replace(CSS_COMMENT, "").trim();									const isExplicitImport = from[0] === "'" || from[0] === '"';									if (isExplicitImport) {										from = from.slice(1, -1);									}									for (const alias of aliases) {										const [name, aliasName] = alias.split(/\s*as\s*/);										icssDefinitions.set(aliasName || name, {											value: name,											path: from										});									}								} else {									const ident = walkCssTokens.eatIdentSequence(alias, 0);									if (!ident) {										this._emitWarning(											state,											`Broken '@value' at-rule: ${input.slice(												start,												atRuleEnd											)}'`,											locConverter,											start,											atRuleEnd										);										const dep = new ConstDependency("", [start, atRuleEnd]);										module.addPresentationalDependency(dep);										return atRuleEnd;									}									const pos = walkCssTokens.eatWhitespaceAndComments(										alias,										ident[1]									);									const name = alias.slice(ident[0], ident[1]);									let value =										alias.charCodeAt(pos) === CC_COLON											? alias.slice(pos + 1)											: alias.slice(ident[1]);									if (value && !/^\s+$/.test(value)) {										value = value.trim();									}									if (icssDefinitions.has(value)) {										const def =											/** @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;							} else if (								OPTIONALLY_VENDOR_PREFIXED_KEYFRAMES_AT_RULE.test(name) &&								isLocalMode()							) {								const ident = walkCssTokens.eatIdentSequenceOrString(									input,									end								);								if (!ident) return end;								const name = unescapeIdentifier(									ident[2] === true										? input.slice(ident[0], ident[1])										: input.slice(ident[0] + 1, ident[1] - 1)								);								const { line: sl, column: sc } = locConverter.get(ident[0]);								const { line: el, column: ec } = locConverter.get(ident[1]);								const dep = new CssLocalIdentifierDependency(name, [									ident[0],									ident[1]								]);								dep.setLoc(sl, sc, el, ec);								module.addDependency(dep);								return ident[1];							} else if (name === "@property" && isLocalMode()) {								const ident = walkCssTokens.eatIdentSequence(input, end);								if (!ident) return end;								let name = input.slice(ident[0], ident[1]);								if (!name.startsWith("--") || name.length < 3) return end;								name = unescapeIdentifier(name.slice(2));								declaredCssVariables.add(name);								const { line: sl, column: sc } = locConverter.get(ident[0]);								const { line: el, column: ec } = locConverter.get(ident[1]);								const dep = new CssLocalIdentifierDependency(									name,									[ident[0], ident[1]],									"--"								);								dep.setLoc(sl, sc, el, ec);								module.addDependency(dep);								return ident[1];							} else if (name === "@scope") {								isNextRulePrelude = true;								return end;							}							isNextRulePrelude = false;						}					}				}				return end;			},			semicolon: (input, start, end) => {				if (isModules && scope === CSS_MODE_IN_BLOCK) {					if (isLocalMode()) {						processDeclarationValueDone(input);						inAnimationProperty = false;					}					isNextRulePrelude = isNextNestedSyntax(input, end);				}				return end;			},			identifier: (input, start, end) => {				if (isModules) {					const name = input.slice(start, end);					if (icssDefinitions.has(name)) {						let { path, value } =							/** @type {IcssDefinition} */							(icssDefinitions.get(name));						if (path) {							if (icssDefinitions.has(path)) {								const definition =									/** @type {IcssDefinition} */									(icssDefinitions.get(path));								path = definition.value.slice(1, -1);							}							const dep = new CssIcssImportDependency(path, value, [								start,								end - 1							]);							const { line: sl, column: sc } = locConverter.get(start);							const { line: el, column: ec } = locConverter.get(end - 1);							dep.setLoc(sl, sc, el, ec);							module.addDependency(dep);						} else {							const { line: sl, column: sc } = locConverter.get(start);							const { line: el, column: ec } = locConverter.get(end);							const dep = new CssIcssSymbolDependency(name, value, [								start,								end							]);							dep.setLoc(sl, sc, el, ec);							module.addDependency(dep);						}						return end;					}					switch (scope) {						case CSS_MODE_IN_BLOCK: {							if (isLocalMode()) {								// Handle only top level values and not inside functions								if (inAnimationProperty && balanced.length === 0) {									lastIdentifier = [start, end, true];								} else {									return processLocalDeclaration(input, start, end);								}							}							break;						}					}				}				return end;			},			delim: (input, start, end) => {				if (isNextRulePrelude && isLocalMode()) {					const ident = walkCssTokens.skipCommentsAndEatIdentSequence(						input,						end					);					if (!ident) return end;					const name = unescapeIdentifier(input.slice(ident[0], ident[1]));					const dep = new CssLocalIdentifierDependency(name, [						ident[0],						ident[1]					]);					const { line: sl, column: sc } = locConverter.get(ident[0]);					const { line: el, column: ec } = locConverter.get(ident[1]);					dep.setLoc(sl, sc, el, ec);					module.addDependency(dep);					return ident[1];				}				return end;			},			hash: (input, start, end, isID) => {				if (isNextRulePrelude && isLocalMode() && isID) {					const valueStart = start + 1;					const name = unescapeIdentifier(input.slice(valueStart, end));					const dep = new CssLocalIdentifierDependency(name, [valueStart, end]);					const { line: sl, column: sc } = locConverter.get(start);					const { line: el, column: ec } = locConverter.get(end);					dep.setLoc(sl, sc, el, ec);					module.addDependency(dep);				}				return end;			},			colon: (input, start, end) => {				if (isModules) {					const ident = walkCssTokens.skipCommentsAndEatIdentSequence(						input,						end					);					if (!ident) return end;					const name = input.slice(ident[0], ident[1]).toLowerCase();					switch (scope) {						case CSS_MODE_TOP_LEVEL: {							if (name === "import") {								const pos = parseImportOrExport(0, input, ident[1]);								const dep = new ConstDependency("", [start, pos]);								module.addPresentationalDependency(dep);								return pos;							} else if (name === "export") {								const pos = parseImportOrExport(1, input, ident[1]);								const dep = new ConstDependency("", [start, pos]);								module.addPresentationalDependency(dep);								return pos;							}						}						// falls through						default: {							if (isNextRulePrelude) {								const isFn = input.charCodeAt(ident[1]) === CC_LEFT_PARENTHESIS;								if (isFn && name === "local") {									const end = ident[1] + 1;									modeData = "local";									const dep = new ConstDependency("", [start, end]);									module.addPresentationalDependency(dep);									balanced.push([":local", start, end]);									return end;								} else if (name === "local") {									modeData = "local";									// Eat extra whitespace									end = walkCssTokens.eatWhitespace(input, ident[1]);									if (ident[1] === end) {										this._emitWarning(											state,											`Missing whitespace after ':local' in '${input.slice(												start,												eatUntilLeftCurly(input, end) + 1											)}'`,											locConverter,											start,											end										);									}									const dep = new ConstDependency("", [start, end]);									module.addPresentationalDependency(dep);									return end;								} else if (isFn && name === "global") {									const end = ident[1] + 1;									modeData = "global";									const dep = new ConstDependency("", [start, end]);									module.addPresentationalDependency(dep);									balanced.push([":global", start, end]);									return end;								} else if (name === "global") {									modeData = "global";									// Eat extra whitespace									end = walkCssTokens.eatWhitespace(input, ident[1]);									if (ident[1] === end) {										this._emitWarning(											state,											`Missing whitespace after ':global' in '${input.slice(												start,												eatUntilLeftCurly(input, end) + 1											)}'`,											locConverter,											start,											end										);									}									const dep = new ConstDependency("", [start, end]);									module.addPresentationalDependency(dep);									return end;								}							}						}					}				}				lastTokenEndForComments = end;				return end;			},			function: (input, start, end) => {				const name = input					.slice(start, end - 1)					.replace(/\\/g, "")					.toLowerCase();				balanced.push([name, start, end]);				switch (name) {					case "src":					case "url": {						if (!this.url) {							return end;						}						const string = walkCssTokens.eatString(input, end);						if (!string) return end;						const { options, errors: commentErrors } = this.parseCommentOptions(							[lastTokenEndForComments, end]						);						if (commentErrors) {							for (const e of commentErrors) {								const { comment } = e;								state.module.addWarning(									new CommentCompilationWarning(										`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,										comment.loc									)								);							}						}						if (options && options.webpackIgnore !== undefined) {							if (typeof options.webpackIgnore !== "boolean") {								const { line: sl, column: sc } = locConverter.get(string[0]);								const { line: el, column: ec } = locConverter.get(string[1]);								state.module.addWarning(									new UnsupportedFeatureWarning(										`\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,										{											start: { line: sl, column: sc },											end: { line: el, column: ec }										}									)								);							} else if (options.webpackIgnore) {								return end;							}						}						const value = normalizeUrl(							input.slice(string[0] + 1, string[1] - 1),							true						);						// Ignore `url()`, `url('')` and `url("")`, they are valid by spec						if (value.length === 0) return end;						const isUrl = name === "url" || name === "src";						const dep = new CssUrlDependency(							value,							[string[0], string[1]],							isUrl ? "string" : "url"						);						const { line: sl, column: sc } = locConverter.get(string[0]);						const { line: el, column: ec } = locConverter.get(string[1]);						dep.setLoc(sl, sc, el, ec);						module.addDependency(dep);						module.addCodeGenerationDependency(dep);						return string[1];					}					default: {						if (this.url && IMAGE_SET_FUNCTION.test(name)) {							lastTokenEndForComments = end;							const values = walkCssTokens.eatImageSetStrings(input, end, {								comment							});							if (values.length === 0) return end;							for (const [index, string] of values.entries()) {								const value = normalizeUrl(									input.slice(string[0] + 1, string[1] - 1),									true								);								if (value.length === 0) return end;								const { options, errors: commentErrors } =									this.parseCommentOptions([										index === 0 ? start : values[index - 1][1],										string[1]									]);								if (commentErrors) {									for (const e of commentErrors) {										const { comment } = e;										state.module.addWarning(											new CommentCompilationWarning(												`Compilation error while processing magic comment(-s): /*${comment.value}*/: ${e.message}`,												comment.loc											)										);									}								}								if (options && options.webpackIgnore !== undefined) {									if (typeof options.webpackIgnore !== "boolean") {										const { line: sl, column: sc } = locConverter.get(											string[0]										);										const { line: el, column: ec } = locConverter.get(											string[1]										);										state.module.addWarning(											new UnsupportedFeatureWarning(												`\`webpackIgnore\` expected a boolean, but received: ${options.webpackIgnore}.`,												{													start: { line: sl, column: sc },													end: { line: el, column: ec }												}											)										);									} else if (options.webpackIgnore) {										continue;									}								}								const dep = new CssUrlDependency(									value,									[string[0], string[1]],									"url"								);								const { line: sl, column: sc } = locConverter.get(string[0]);								const { line: el, column: ec } = locConverter.get(string[1]);								dep.setLoc(sl, sc, el, ec);								module.addDependency(dep);								module.addCodeGenerationDependency(dep);							}							// Can contain `url()` inside, so let's return end to allow parse them							return end;						} else if (isLocalMode()) {							// Don't rename animation name when we have `var()` function							if (inAnimationProperty && balanced.length === 1) {								lastIdentifier = undefined;							}							if (name === "var") {								const customIdent = walkCssTokens.eatIdentSequence(input, end);								if (!customIdent) return end;								let name = input.slice(customIdent[0], customIdent[1]);								// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.								// The <custom-property-name> production corresponds to this:								// it’s defined as any <dashed-ident> (a valid identifier that starts with two dashes),								// except -- itself, which is reserved for future use by CSS.								if (!name.startsWith("--") || name.length < 3) return end;								name = unescapeIdentifier(									input.slice(customIdent[0] + 2, customIdent[1])								);								const afterCustomIdent = walkCssTokens.eatWhitespaceAndComments(									input,									customIdent[1]								);								if (									input.charCodeAt(afterCustomIdent) === CC_LOWER_F ||									input.charCodeAt(afterCustomIdent) === CC_UPPER_F								) {									const fromWord = walkCssTokens.eatIdentSequence(										input,										afterCustomIdent									);									if (										!fromWord ||										input.slice(fromWord[0], fromWord[1]).toLowerCase() !==											"from"									) {										return end;									}									const from = walkCssTokens.eatIdentSequenceOrString(										input,										walkCssTokens.eatWhitespaceAndComments(input, fromWord[1])									);									if (!from) {										return end;									}									const path = input.slice(from[0], from[1]);									if (from[2] === true && path === "global") {										const dep = new ConstDependency("", [											customIdent[1],											from[1]										]);										module.addPresentationalDependency(dep);										return end;									} else if (from[2] === false) {										const dep = new CssIcssImportDependency(											path.slice(1, -1),											name,											[customIdent[0], from[1] - 1]										);										const { line: sl, column: sc } = locConverter.get(											customIdent[0]										);										const { line: el, column: ec } = locConverter.get(											from[1] - 1										);										dep.setLoc(sl, sc, el, ec);										module.addDependency(dep);									}								} else {									const { line: sl, column: sc } = locConverter.get(										customIdent[0]									);									const { line: el, column: ec } = locConverter.get(										customIdent[1]									);									const dep = new CssSelfLocalIdentifierDependency(										name,										[customIdent[0], customIdent[1]],										"--",										declaredCssVariables									);									dep.setLoc(sl, sc, el, ec);									module.addDependency(dep);									return end;								}							}						}					}				}				return end;			},			leftParenthesis: (input, start, end) => {				balanced.push(["(", start, end]);				return end;			},			rightParenthesis: (input, start, end) => {				const popped = balanced.pop();				if (					isModules &&					popped &&					(popped[0] === ":local" || popped[0] === ":global")				) {					modeData = balanced[balanced.length - 1]						? /** @type {"local" | "global"} */							(balanced[balanced.length - 1][0])						: undefined;					const dep = new ConstDependency("", [start, end]);					module.addPresentationalDependency(dep);				}				return end;			},			comma: (input, start, end) => {				if (isModules) {					// Reset stack for `:global .class :local .class-other` selector after					modeData = undefined;					if (scope === CSS_MODE_IN_BLOCK && isLocalMode()) {						processDeclarationValueDone(input);					}				}				lastTokenEndForComments = start;				return end;			}		});		/** @type {BuildInfo} */		(module.buildInfo).strict = true;		/** @type {BuildMeta} */		(module.buildMeta).exportsType = this.namedExports			? "namespace"			: "default";		if (!this.namedExports) {			/** @type {BuildMeta} */			(module.buildMeta).defaultObject = "redirect";		}		module.addDependency(new StaticExportsDependency([], true));		return state;	}	/**	 * @param {Range} range range	 * @returns {Comment[]} comments in the range	 */	getComments(range) {		if (!this.comments) return [];		const [rangeStart, rangeEnd] = range;		/**		 * @param {Comment} comment comment		 * @param {number} needle needle		 * @returns {number} compared		 */		const compare = (comment, needle) =>			/** @type {Range} */ (comment.range)[0] - needle;		const comments = /** @type {Comment[]} */ (this.comments);		let idx = binarySearchBounds.ge(comments, rangeStart, compare);		/** @type {Comment[]} */		const commentsInRange = [];		while (			comments[idx] &&			/** @type {Range} */ (comments[idx].range)[1] <= rangeEnd		) {			commentsInRange.push(comments[idx]);			idx++;		}		return commentsInRange;	}	/**	 * @param {Range} range range of the comment	 * @returns {{ options: Record<string, 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;
 |