mirror of https://github.com/webpack/webpack.git
				
				
				
			
		
			
				
	
	
		
			791 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			791 lines
		
	
	
		
			20 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
/*
 | 
						|
	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
						|
	Author Tobias Koppers @sokra
 | 
						|
*/
 | 
						|
 | 
						|
"use strict";
 | 
						|
 | 
						|
/**
 | 
						|
 * @typedef {Object} CssTokenCallbacks
 | 
						|
 * @property {function(string, number): boolean=} isSelector
 | 
						|
 * @property {function(string, number, number, number, number): number=} url
 | 
						|
 * @property {function(string, number, number): number=} string
 | 
						|
 * @property {function(string, number, number): number=} leftParenthesis
 | 
						|
 * @property {function(string, number, number): number=} rightParenthesis
 | 
						|
 * @property {function(string, number, number): number=} pseudoFunction
 | 
						|
 * @property {function(string, number, number): number=} function
 | 
						|
 * @property {function(string, number, number): number=} pseudoClass
 | 
						|
 * @property {function(string, number, number): number=} atKeyword
 | 
						|
 * @property {function(string, number, number): number=} class
 | 
						|
 * @property {function(string, number, number): number=} identifier
 | 
						|
 * @property {function(string, number, number): number=} id
 | 
						|
 * @property {function(string, number, number): number=} leftCurlyBracket
 | 
						|
 * @property {function(string, number, number): number=} rightCurlyBracket
 | 
						|
 * @property {function(string, number, number): number=} semicolon
 | 
						|
 * @property {function(string, number, number): number=} comma
 | 
						|
 */
 | 
						|
 | 
						|
/** @typedef {function(string, number, CssTokenCallbacks): number} CharHandler */
 | 
						|
 | 
						|
// spec: https://drafts.csswg.org/css-syntax/
 | 
						|
 | 
						|
const CC_LINE_FEED = "\n".charCodeAt(0);
 | 
						|
const CC_CARRIAGE_RETURN = "\r".charCodeAt(0);
 | 
						|
const CC_FORM_FEED = "\f".charCodeAt(0);
 | 
						|
 | 
						|
const CC_TAB = "\t".charCodeAt(0);
 | 
						|
const CC_SPACE = " ".charCodeAt(0);
 | 
						|
 | 
						|
const CC_SOLIDUS = "/".charCodeAt(0);
 | 
						|
const CC_REVERSE_SOLIDUS = "\\".charCodeAt(0);
 | 
						|
const CC_ASTERISK = "*".charCodeAt(0);
 | 
						|
 | 
						|
const CC_LEFT_PARENTHESIS = "(".charCodeAt(0);
 | 
						|
const CC_RIGHT_PARENTHESIS = ")".charCodeAt(0);
 | 
						|
const CC_LEFT_CURLY = "{".charCodeAt(0);
 | 
						|
const CC_RIGHT_CURLY = "}".charCodeAt(0);
 | 
						|
const CC_LEFT_SQUARE = "[".charCodeAt(0);
 | 
						|
const CC_RIGHT_SQUARE = "]".charCodeAt(0);
 | 
						|
 | 
						|
const CC_QUOTATION_MARK = '"'.charCodeAt(0);
 | 
						|
const CC_APOSTROPHE = "'".charCodeAt(0);
 | 
						|
 | 
						|
const CC_FULL_STOP = ".".charCodeAt(0);
 | 
						|
const CC_COLON = ":".charCodeAt(0);
 | 
						|
const CC_SEMICOLON = ";".charCodeAt(0);
 | 
						|
const CC_COMMA = ",".charCodeAt(0);
 | 
						|
const CC_PERCENTAGE = "%".charCodeAt(0);
 | 
						|
const CC_AT_SIGN = "@".charCodeAt(0);
 | 
						|
 | 
						|
const CC_LOW_LINE = "_".charCodeAt(0);
 | 
						|
const CC_LOWER_A = "a".charCodeAt(0);
 | 
						|
const CC_LOWER_U = "u".charCodeAt(0);
 | 
						|
const CC_LOWER_E = "e".charCodeAt(0);
 | 
						|
const CC_LOWER_Z = "z".charCodeAt(0);
 | 
						|
const CC_UPPER_A = "A".charCodeAt(0);
 | 
						|
const CC_UPPER_E = "E".charCodeAt(0);
 | 
						|
const CC_UPPER_U = "U".charCodeAt(0);
 | 
						|
const CC_UPPER_Z = "Z".charCodeAt(0);
 | 
						|
const CC_0 = "0".charCodeAt(0);
 | 
						|
const CC_9 = "9".charCodeAt(0);
 | 
						|
 | 
						|
const CC_NUMBER_SIGN = "#".charCodeAt(0);
 | 
						|
const CC_PLUS_SIGN = "+".charCodeAt(0);
 | 
						|
const CC_HYPHEN_MINUS = "-".charCodeAt(0);
 | 
						|
 | 
						|
const CC_LESS_THAN_SIGN = "<".charCodeAt(0);
 | 
						|
const CC_GREATER_THAN_SIGN = ">".charCodeAt(0);
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} true, if cc is a newline
 | 
						|
 */
 | 
						|
const _isNewLine = cc => {
 | 
						|
	return (
 | 
						|
		cc === CC_LINE_FEED || cc === CC_CARRIAGE_RETURN || cc === CC_FORM_FEED
 | 
						|
	);
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeSpace = (input, pos, callbacks) => {
 | 
						|
	/** @type {number} */
 | 
						|
	let cc;
 | 
						|
	do {
 | 
						|
		pos++;
 | 
						|
		cc = input.charCodeAt(pos);
 | 
						|
	} while (_isWhiteSpace(cc));
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} true, if cc is a newline
 | 
						|
 */
 | 
						|
const _isNewline = cc => {
 | 
						|
	return (
 | 
						|
		cc === CC_LINE_FEED || cc === CC_CARRIAGE_RETURN || cc === CC_FORM_FEED
 | 
						|
	);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} true, if cc is a space (U+0009 CHARACTER TABULATION or U+0020 SPACE)
 | 
						|
 */
 | 
						|
const _isSpace = cc => {
 | 
						|
	return cc === CC_TAB || cc === CC_SPACE;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} true, if cc is a whitespace
 | 
						|
 */
 | 
						|
const _isWhiteSpace = cc => {
 | 
						|
	return _isNewline(cc) || _isSpace(cc);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * ident-start code point
 | 
						|
 *
 | 
						|
 * A letter, a non-ASCII code point, or U+005F LOW LINE (_).
 | 
						|
 *
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} true, if cc is a start code point of an identifier
 | 
						|
 */
 | 
						|
const isIdentStartCodePoint = cc => {
 | 
						|
	return (
 | 
						|
		(cc >= CC_LOWER_A && cc <= CC_LOWER_Z) ||
 | 
						|
		(cc >= CC_UPPER_A && cc <= CC_UPPER_Z) ||
 | 
						|
		cc === CC_LOW_LINE ||
 | 
						|
		cc >= 0x80
 | 
						|
	);
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeDelimToken = (input, pos, callbacks) => {
 | 
						|
	return pos + 1;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeComments = (input, pos, callbacks) => {
 | 
						|
	// If the next two input code point are U+002F SOLIDUS (/) followed by a U+002A
 | 
						|
	// ASTERISK (*), consume them and all following code points up to and including
 | 
						|
	// the first U+002A ASTERISK (*) followed by a U+002F SOLIDUS (/), or up to an
 | 
						|
	// EOF code point. Return to the start of this step.
 | 
						|
	//
 | 
						|
	// If the preceding paragraph ended by consuming an EOF code point, this is a parse error.
 | 
						|
	// But we are silent on errors.
 | 
						|
	if (
 | 
						|
		input.charCodeAt(pos) === CC_SOLIDUS &&
 | 
						|
		input.charCodeAt(pos + 1) === CC_ASTERISK
 | 
						|
	) {
 | 
						|
		pos += 1;
 | 
						|
		while (pos < input.length) {
 | 
						|
			if (
 | 
						|
				input.charCodeAt(pos) === CC_ASTERISK &&
 | 
						|
				input.charCodeAt(pos + 1) === CC_SOLIDUS
 | 
						|
			) {
 | 
						|
				pos += 2;
 | 
						|
				break;
 | 
						|
			}
 | 
						|
			pos++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {function(number): CharHandler} */
 | 
						|
const consumeString = quote_cc => (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos = _consumeString(input, pos, quote_cc);
 | 
						|
	if (callbacks.string !== undefined) {
 | 
						|
		pos = callbacks.string(input, start, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @param {number} quote_cc quote char code
 | 
						|
 * @returns {number} new position
 | 
						|
 */
 | 
						|
const _consumeString = (input, pos, quote_cc) => {
 | 
						|
	pos++;
 | 
						|
	for (;;) {
 | 
						|
		if (pos === input.length) return pos;
 | 
						|
		const cc = input.charCodeAt(pos);
 | 
						|
		if (cc === quote_cc) return pos + 1;
 | 
						|
		if (_isNewLine(cc)) {
 | 
						|
			// bad string
 | 
						|
			return pos;
 | 
						|
		}
 | 
						|
		if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
			// we don't need to fully parse the escaped code point
 | 
						|
			// just skip over a potential new line
 | 
						|
			pos++;
 | 
						|
			if (pos === input.length) return pos;
 | 
						|
			pos++;
 | 
						|
		} else {
 | 
						|
			pos++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} is identifier start code
 | 
						|
 */
 | 
						|
const _isIdentifierStartCode = cc => {
 | 
						|
	return (
 | 
						|
		cc === CC_LOW_LINE ||
 | 
						|
		(cc >= CC_LOWER_A && cc <= CC_LOWER_Z) ||
 | 
						|
		(cc >= CC_UPPER_A && cc <= CC_UPPER_Z) ||
 | 
						|
		cc > 0x80
 | 
						|
	);
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} first first code point
 | 
						|
 * @param {number} second second code point
 | 
						|
 * @returns {boolean} true if two code points are a valid escape
 | 
						|
 */
 | 
						|
const _isTwoCodePointsAreValidEscape = (first, second) => {
 | 
						|
	if (first !== CC_REVERSE_SOLIDUS) return false;
 | 
						|
	if (_isNewLine(second)) return false;
 | 
						|
	return true;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {number} cc char code
 | 
						|
 * @returns {boolean} is digit
 | 
						|
 */
 | 
						|
const _isDigit = cc => {
 | 
						|
	return cc >= CC_0 && cc <= CC_9;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @returns {boolean} true, if input at pos starts an identifier
 | 
						|
 */
 | 
						|
const _startsIdentifier = (input, pos) => {
 | 
						|
	const cc = input.charCodeAt(pos);
 | 
						|
	if (cc === CC_HYPHEN_MINUS) {
 | 
						|
		if (pos === input.length) return false;
 | 
						|
		const cc = input.charCodeAt(pos + 1);
 | 
						|
		if (cc === CC_HYPHEN_MINUS) return true;
 | 
						|
		if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
			const cc = input.charCodeAt(pos + 2);
 | 
						|
			return !_isNewLine(cc);
 | 
						|
		}
 | 
						|
		return _isIdentifierStartCode(cc);
 | 
						|
	}
 | 
						|
	if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
		const cc = input.charCodeAt(pos + 1);
 | 
						|
		return !_isNewLine(cc);
 | 
						|
	}
 | 
						|
	return _isIdentifierStartCode(cc);
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeNumberSign = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	if (callbacks.isSelector(input, pos) && _startsIdentifier(input, pos)) {
 | 
						|
		pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
		if (callbacks.id !== undefined) {
 | 
						|
			return callbacks.id(input, start, pos);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeMinus = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	const cc = input.charCodeAt(pos);
 | 
						|
	// If the input stream starts with a number, reconsume the current input code point, consume a numeric token, and return it.
 | 
						|
	if (cc === CC_FULL_STOP || _isDigit(cc)) {
 | 
						|
		return consumeNumericToken(input, pos, callbacks);
 | 
						|
	} else if (cc === CC_HYPHEN_MINUS) {
 | 
						|
		pos++;
 | 
						|
		if (pos === input.length) return pos;
 | 
						|
		const cc = input.charCodeAt(pos);
 | 
						|
		if (cc === CC_GREATER_THAN_SIGN) {
 | 
						|
			return pos + 1;
 | 
						|
		} else {
 | 
						|
			pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
			if (callbacks.identifier !== undefined) {
 | 
						|
				return callbacks.identifier(input, start, pos);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
		if (pos + 1 === input.length) return pos;
 | 
						|
		const cc = input.charCodeAt(pos + 1);
 | 
						|
		if (_isNewLine(cc)) return pos;
 | 
						|
		pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
		if (callbacks.identifier !== undefined) {
 | 
						|
			return callbacks.identifier(input, start, pos);
 | 
						|
		}
 | 
						|
	} else if (_isIdentifierStartCode(cc)) {
 | 
						|
		pos = consumeOtherIdentifier(input, pos - 1, callbacks);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeDot = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	const cc = input.charCodeAt(pos);
 | 
						|
	if (_isDigit(cc)) return consumeNumericToken(input, pos - 2, callbacks);
 | 
						|
	if (!callbacks.isSelector(input, pos) || !_startsIdentifier(input, pos))
 | 
						|
		return pos;
 | 
						|
	pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
	if (callbacks.class !== undefined) return callbacks.class(input, start, pos);
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeNumericToken = (input, pos, callbacks) => {
 | 
						|
	pos = _consumeNumber(input, pos, callbacks);
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	if (_startsIdentifier(input, pos))
 | 
						|
		return _consumeIdentifier(input, pos, callbacks);
 | 
						|
	const cc = input.charCodeAt(pos);
 | 
						|
	if (cc === CC_PERCENTAGE) return pos + 1;
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeOtherIdentifier = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
	if (pos !== input.length && input.charCodeAt(pos) === CC_LEFT_PARENTHESIS) {
 | 
						|
		pos++;
 | 
						|
		if (callbacks.function !== undefined) {
 | 
						|
			return callbacks.function(input, start, pos);
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (callbacks.identifier !== undefined) {
 | 
						|
			return callbacks.identifier(input, start, pos);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumePotentialUrl = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
	const nextPos = pos + 1;
 | 
						|
	if (
 | 
						|
		pos === start + 3 &&
 | 
						|
		input.slice(start, nextPos).toLowerCase() === "url("
 | 
						|
	) {
 | 
						|
		pos++;
 | 
						|
		let cc = input.charCodeAt(pos);
 | 
						|
		while (_isWhiteSpace(cc)) {
 | 
						|
			pos++;
 | 
						|
			if (pos === input.length) return pos;
 | 
						|
			cc = input.charCodeAt(pos);
 | 
						|
		}
 | 
						|
		if (cc === CC_QUOTATION_MARK || cc === CC_APOSTROPHE) {
 | 
						|
			if (callbacks.function !== undefined) {
 | 
						|
				return callbacks.function(input, start, nextPos);
 | 
						|
			}
 | 
						|
			return nextPos;
 | 
						|
		} else {
 | 
						|
			const contentStart = pos;
 | 
						|
			/** @type {number} */
 | 
						|
			let contentEnd;
 | 
						|
			for (;;) {
 | 
						|
				if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
					pos++;
 | 
						|
					if (pos === input.length) return pos;
 | 
						|
					pos++;
 | 
						|
				} else if (_isWhiteSpace(cc)) {
 | 
						|
					contentEnd = pos;
 | 
						|
					do {
 | 
						|
						pos++;
 | 
						|
						if (pos === input.length) return pos;
 | 
						|
						cc = input.charCodeAt(pos);
 | 
						|
					} while (_isWhiteSpace(cc));
 | 
						|
					if (cc !== CC_RIGHT_PARENTHESIS) return pos;
 | 
						|
					pos++;
 | 
						|
					if (callbacks.url !== undefined) {
 | 
						|
						return callbacks.url(input, start, pos, contentStart, contentEnd);
 | 
						|
					}
 | 
						|
					return pos;
 | 
						|
				} else if (cc === CC_RIGHT_PARENTHESIS) {
 | 
						|
					contentEnd = pos;
 | 
						|
					pos++;
 | 
						|
					if (callbacks.url !== undefined) {
 | 
						|
						return callbacks.url(input, start, pos, contentStart, contentEnd);
 | 
						|
					}
 | 
						|
					return pos;
 | 
						|
				} else if (cc === CC_LEFT_PARENTHESIS) {
 | 
						|
					return pos;
 | 
						|
				} else {
 | 
						|
					pos++;
 | 
						|
				}
 | 
						|
				if (pos === input.length) return pos;
 | 
						|
				cc = input.charCodeAt(pos);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		if (callbacks.identifier !== undefined) {
 | 
						|
			return callbacks.identifier(input, start, pos);
 | 
						|
		}
 | 
						|
		return pos;
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumePotentialPseudo = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (!callbacks.isSelector(input, pos) || !_startsIdentifier(input, pos))
 | 
						|
		return pos;
 | 
						|
	pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
	let cc = input.charCodeAt(pos);
 | 
						|
	if (cc === CC_LEFT_PARENTHESIS) {
 | 
						|
		pos++;
 | 
						|
		if (callbacks.pseudoFunction !== undefined) {
 | 
						|
			return callbacks.pseudoFunction(input, start, pos);
 | 
						|
		}
 | 
						|
		return pos;
 | 
						|
	}
 | 
						|
	if (callbacks.pseudoClass !== undefined) {
 | 
						|
		return callbacks.pseudoClass(input, start, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeLeftParenthesis = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.leftParenthesis !== undefined) {
 | 
						|
		return callbacks.leftParenthesis(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeRightParenthesis = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.rightParenthesis !== undefined) {
 | 
						|
		return callbacks.rightParenthesis(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeLeftCurlyBracket = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.leftCurlyBracket !== undefined) {
 | 
						|
		return callbacks.leftCurlyBracket(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeRightCurlyBracket = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.rightCurlyBracket !== undefined) {
 | 
						|
		return callbacks.rightCurlyBracket(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeSemicolon = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.semicolon !== undefined) {
 | 
						|
		return callbacks.semicolon(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeComma = (input, pos, callbacks) => {
 | 
						|
	pos++;
 | 
						|
	if (callbacks.comma !== undefined) {
 | 
						|
		return callbacks.comma(input, pos - 1, pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const _consumeIdentifier = (input, pos) => {
 | 
						|
	for (;;) {
 | 
						|
		const cc = input.charCodeAt(pos);
 | 
						|
		if (cc === CC_REVERSE_SOLIDUS) {
 | 
						|
			pos++;
 | 
						|
			if (pos === input.length) return pos;
 | 
						|
			pos++;
 | 
						|
		} else if (
 | 
						|
			_isIdentifierStartCode(cc) ||
 | 
						|
			_isDigit(cc) ||
 | 
						|
			cc === CC_HYPHEN_MINUS
 | 
						|
		) {
 | 
						|
			pos++;
 | 
						|
		} else {
 | 
						|
			return pos;
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const _consumeNumber = (input, pos) => {
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	let cc = input.charCodeAt(pos);
 | 
						|
	while (_isDigit(cc)) {
 | 
						|
		pos++;
 | 
						|
		if (pos === input.length) return pos;
 | 
						|
		cc = input.charCodeAt(pos);
 | 
						|
	}
 | 
						|
	if (cc === CC_FULL_STOP && pos + 1 !== input.length) {
 | 
						|
		const next = input.charCodeAt(pos + 1);
 | 
						|
		if (_isDigit(next)) {
 | 
						|
			pos += 2;
 | 
						|
			cc = input.charCodeAt(pos);
 | 
						|
			while (_isDigit(cc)) {
 | 
						|
				pos++;
 | 
						|
				if (pos === input.length) return pos;
 | 
						|
				cc = input.charCodeAt(pos);
 | 
						|
			}
 | 
						|
		}
 | 
						|
	}
 | 
						|
	if (cc === CC_LOWER_E || cc === CC_UPPER_E) {
 | 
						|
		if (pos + 1 !== input.length) {
 | 
						|
			const next = input.charCodeAt(pos + 2);
 | 
						|
			if (_isDigit(next)) {
 | 
						|
				pos += 2;
 | 
						|
			} else if (
 | 
						|
				(next === CC_HYPHEN_MINUS || next === CC_PLUS_SIGN) &&
 | 
						|
				pos + 2 !== input.length
 | 
						|
			) {
 | 
						|
				const next = input.charCodeAt(pos + 2);
 | 
						|
				if (_isDigit(next)) {
 | 
						|
					pos += 3;
 | 
						|
				} else {
 | 
						|
					return pos;
 | 
						|
				}
 | 
						|
			} else {
 | 
						|
				return pos;
 | 
						|
			}
 | 
						|
		}
 | 
						|
	} else {
 | 
						|
		return pos;
 | 
						|
	}
 | 
						|
	cc = input.charCodeAt(pos);
 | 
						|
	while (_isDigit(cc)) {
 | 
						|
		pos++;
 | 
						|
		if (pos === input.length) return pos;
 | 
						|
		cc = input.charCodeAt(pos);
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeLessThan = (input, pos, callbacks) => {
 | 
						|
	if (input.slice(pos + 1, pos + 4) === "!--") return pos + 4;
 | 
						|
	return pos + 1;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeAt = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	if (_startsIdentifier(input, pos)) {
 | 
						|
		pos = _consumeIdentifier(input, pos, callbacks);
 | 
						|
		if (callbacks.atKeyword !== undefined) {
 | 
						|
			pos = callbacks.atKeyword(input, start, pos);
 | 
						|
		}
 | 
						|
	}
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/** @type {CharHandler} */
 | 
						|
const consumeReverseSolidus = (input, pos, callbacks) => {
 | 
						|
	const start = pos;
 | 
						|
	pos++;
 | 
						|
	if (pos === input.length) return pos;
 | 
						|
	// If the input stream starts with a valid escape, reconsume the current input code point, consume an ident-like token, and return it.
 | 
						|
	if (
 | 
						|
		_isTwoCodePointsAreValidEscape(
 | 
						|
			input.charCodeAt(start),
 | 
						|
			input.charCodeAt(pos)
 | 
						|
		)
 | 
						|
	) {
 | 
						|
		return consumeOtherIdentifier(input, pos - 1, callbacks);
 | 
						|
	}
 | 
						|
	// Otherwise, this is a parse error. Return a <delim-token> with its value set to the current input code point.
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
const CHAR_MAP = Array.from({ length: 0x80 }, (_, cc) => {
 | 
						|
	// https://drafts.csswg.org/css-syntax/#consume-token
 | 
						|
	switch (cc) {
 | 
						|
		// whitespace
 | 
						|
		case CC_LINE_FEED:
 | 
						|
		case CC_CARRIAGE_RETURN:
 | 
						|
		case CC_FORM_FEED:
 | 
						|
		case CC_TAB:
 | 
						|
		case CC_SPACE:
 | 
						|
			return consumeSpace;
 | 
						|
		// U+0022 QUOTATION MARK (")
 | 
						|
		case CC_QUOTATION_MARK:
 | 
						|
			return consumeString(cc);
 | 
						|
		// U+0023 NUMBER SIGN (#)
 | 
						|
		case CC_NUMBER_SIGN:
 | 
						|
			return consumeNumberSign;
 | 
						|
		// U+0027 APOSTROPHE (')
 | 
						|
		case CC_APOSTROPHE:
 | 
						|
			return consumeString(cc);
 | 
						|
		// U+0028 LEFT PARENTHESIS (()
 | 
						|
		case CC_LEFT_PARENTHESIS:
 | 
						|
			return consumeLeftParenthesis;
 | 
						|
		// U+0029 RIGHT PARENTHESIS ())
 | 
						|
		case CC_RIGHT_PARENTHESIS:
 | 
						|
			return consumeRightParenthesis;
 | 
						|
		// U+002B PLUS SIGN (+)
 | 
						|
		case CC_PLUS_SIGN:
 | 
						|
			return consumeNumericToken;
 | 
						|
		// U+002C COMMA (,)
 | 
						|
		case CC_COMMA:
 | 
						|
			return consumeComma;
 | 
						|
		// U+002D HYPHEN-MINUS (-)
 | 
						|
		case CC_HYPHEN_MINUS:
 | 
						|
			return consumeMinus;
 | 
						|
		// U+002E FULL STOP (.)
 | 
						|
		case CC_FULL_STOP:
 | 
						|
			return consumeDot;
 | 
						|
		// U+003A COLON (:)
 | 
						|
		case CC_COLON:
 | 
						|
			return consumePotentialPseudo;
 | 
						|
		// U+003B SEMICOLON (;)
 | 
						|
		case CC_SEMICOLON:
 | 
						|
			return consumeSemicolon;
 | 
						|
		// U+003C LESS-THAN SIGN (<)
 | 
						|
		case CC_LESS_THAN_SIGN:
 | 
						|
			return consumeLessThan;
 | 
						|
		// U+0040 COMMERCIAL AT (@)
 | 
						|
		case CC_AT_SIGN:
 | 
						|
			return consumeAt;
 | 
						|
		// U+005B LEFT SQUARE BRACKET ([)
 | 
						|
		case CC_LEFT_SQUARE:
 | 
						|
			return consumeDelimToken;
 | 
						|
		// U+005C REVERSE SOLIDUS (\)
 | 
						|
		case CC_REVERSE_SOLIDUS:
 | 
						|
			return consumeReverseSolidus;
 | 
						|
		// U+005D RIGHT SQUARE BRACKET (])
 | 
						|
		case CC_RIGHT_SQUARE:
 | 
						|
			return consumeDelimToken;
 | 
						|
		// U+007B LEFT CURLY BRACKET ({)
 | 
						|
		case CC_LEFT_CURLY:
 | 
						|
			return consumeLeftCurlyBracket;
 | 
						|
		// U+007D RIGHT CURLY BRACKET (})
 | 
						|
		case CC_RIGHT_CURLY:
 | 
						|
			return consumeRightCurlyBracket;
 | 
						|
		// Optimization
 | 
						|
		case CC_LOWER_U:
 | 
						|
		case CC_UPPER_U:
 | 
						|
			return consumePotentialUrl;
 | 
						|
		default:
 | 
						|
			// digit
 | 
						|
			if (_isDigit(cc)) return consumeNumericToken;
 | 
						|
			// ident-start code point
 | 
						|
			if (isIdentStartCodePoint(cc)) {
 | 
						|
				return consumeOtherIdentifier;
 | 
						|
			}
 | 
						|
			// EOF, but we don't have it
 | 
						|
			// anything else
 | 
						|
			return consumeDelimToken;
 | 
						|
	}
 | 
						|
});
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input css
 | 
						|
 * @param {CssTokenCallbacks} callbacks callbacks
 | 
						|
 * @returns {void}
 | 
						|
 */
 | 
						|
module.exports = (input, callbacks) => {
 | 
						|
	// This section describes how to consume a token from a stream of code points. It will return a single token of any type.
 | 
						|
	let pos = 0;
 | 
						|
	while (pos < input.length) {
 | 
						|
		// Consume comments.
 | 
						|
		pos = consumeComments(input, pos, callbacks);
 | 
						|
 | 
						|
		const cc = input.charCodeAt(pos);
 | 
						|
 | 
						|
		// Consume the next input code point.
 | 
						|
		if (cc < 0x80) {
 | 
						|
			pos = CHAR_MAP[cc](input, pos, callbacks);
 | 
						|
		} else {
 | 
						|
			pos++;
 | 
						|
		}
 | 
						|
	}
 | 
						|
};
 | 
						|
 | 
						|
module.exports.isIdentStartCodePoint = isIdentStartCodePoint;
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @returns {number} position after comments
 | 
						|
 */
 | 
						|
module.exports.eatComments = (input, pos) => {
 | 
						|
	for (;;) {
 | 
						|
		let originalPos = pos;
 | 
						|
		pos = consumeComments(input, pos, {});
 | 
						|
		if (originalPos === pos) {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @returns {number} position after whitespace
 | 
						|
 */
 | 
						|
module.exports.eatWhitespace = (input, pos) => {
 | 
						|
	while (_isWhiteSpace(input.charCodeAt(pos))) {
 | 
						|
		pos++;
 | 
						|
	}
 | 
						|
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @returns {number} position after whitespace and comments
 | 
						|
 */
 | 
						|
module.exports.eatWhitespaceAndComments = (input, pos) => {
 | 
						|
	for (;;) {
 | 
						|
		let originalPos = pos;
 | 
						|
		pos = consumeComments(input, pos, {});
 | 
						|
		while (_isWhiteSpace(input.charCodeAt(pos))) {
 | 
						|
			pos++;
 | 
						|
		}
 | 
						|
		if (originalPos === pos) {
 | 
						|
			break;
 | 
						|
		}
 | 
						|
	}
 | 
						|
 | 
						|
	return pos;
 | 
						|
};
 | 
						|
 | 
						|
/**
 | 
						|
 * @param {string} input input
 | 
						|
 * @param {number} pos position
 | 
						|
 * @returns {number} position after whitespace
 | 
						|
 */
 | 
						|
module.exports.eatWhiteLine = (input, pos) => {
 | 
						|
	for (;;) {
 | 
						|
		const cc = input.charCodeAt(pos);
 | 
						|
		if (_isSpace(cc)) {
 | 
						|
			pos++;
 | 
						|
			continue;
 | 
						|
		}
 | 
						|
		if (_isNewLine(cc)) pos++;
 | 
						|
		// For `\r\n`
 | 
						|
		if (cc === CC_CARRIAGE_RETURN && input.charCodeAt(pos + 1) === CC_LINE_FEED)
 | 
						|
			pos++;
 | 
						|
		break;
 | 
						|
	}
 | 
						|
 | 
						|
	return pos;
 | 
						|
};
 |