| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @typedef {Object} CssTokenCallbacks | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  |  * @property {function(string, number): boolean=} isSelector | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  |  * @property {function(string, number, number, number, number): number=} url | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  |  * @property {function(string, number, number): number=} string | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  |  * @property {function(string, number, number): number=} leftParenthesis | 
					
						
							|  |  |  |  * @property {function(string, number, number): number=} rightParenthesis | 
					
						
							|  |  |  |  * @property {function(string, number, number): number=} pseudoFunction | 
					
						
							| 
									
										
										
										
											2021-12-17 03:42:44 +08:00
										 |  |  |  * @property {function(string, number, number): number=} function | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  |  * @property {function(string, number, number): number=} pseudoClass | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  |  * @property {function(string, number, number): number=} atKeyword | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  |  * @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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 08:31:58 +08:00
										 |  |  | const CC_SOLIDUS = "/".charCodeAt(0); | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | const CC_REVERSE_SOLIDUS = "\\".charCodeAt(0); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 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); | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | const CC_LEFT_SQUARE = "[".charCodeAt(0); | 
					
						
							|  |  |  | const CC_RIGHT_SQUARE = "]".charCodeAt(0); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 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); | 
					
						
							| 
									
										
										
										
											2023-04-06 03:58:23 +08:00
										 |  |  | const CC_UPPER_U = "U".charCodeAt(0); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 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); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {number} cc char code | 
					
						
							|  |  |  |  * @returns {boolean} true, if cc is a newline | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | const _isNewLine = cc => { | 
					
						
							|  |  |  | 	return ( | 
					
						
							|  |  |  | 		cc === CC_LINE_FEED || cc === CC_CARRIAGE_RETURN || cc === CC_FORM_FEED | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {CharHandler} */ | 
					
						
							|  |  |  | const consumeSpace = (input, pos, callbacks) => { | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	/** @type {number} */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	let cc; | 
					
						
							|  |  |  | 	do { | 
					
						
							|  |  |  | 		pos++; | 
					
						
							|  |  |  | 		cc = input.charCodeAt(pos); | 
					
						
							|  |  |  | 	} while (_isWhiteSpace(cc)); | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {number} cc char code | 
					
						
							| 
									
										
										
										
											2023-05-01 22:46:47 +08:00
										 |  |  |  * @returns {boolean} true, if cc is a newline | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-05-01 22:46:47 +08:00
										 |  |  | const _isNewline = cc => { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	return ( | 
					
						
							| 
									
										
										
										
											2023-05-01 22:46:47 +08:00
										 |  |  | 		cc === CC_LINE_FEED || cc === CC_CARRIAGE_RETURN || cc === CC_FORM_FEED | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-01 22:46:47 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							| 
									
										
										
										
											2023-05-05 06:13:27 +08:00
										 |  |  |  * ident-start code point | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  * A letter, a non-ASCII code point, or U+005F LOW LINE (_). | 
					
						
							|  |  |  |  * | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  |  * @param {number} cc char code | 
					
						
							|  |  |  |  * @returns {boolean} true, if cc is a start code point of an identifier | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-05-05 06:13:27 +08:00
										 |  |  | const isIdentStartCodePoint = cc => { | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 	return ( | 
					
						
							|  |  |  | 		(cc >= CC_LOWER_A && cc <= CC_LOWER_Z) || | 
					
						
							|  |  |  | 		(cc >= CC_UPPER_A && cc <= CC_UPPER_Z) || | 
					
						
							|  |  |  | 		cc === CC_LOW_LINE || | 
					
						
							|  |  |  | 		cc >= 0x80 | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | /** @type {CharHandler} */ | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | const consumeDelimToken = (input, pos, callbacks) => { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	return pos + 1; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {CharHandler} */ | 
					
						
							| 
									
										
										
										
											2023-04-14 08:31:58 +08:00
										 |  |  | 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 ( | 
					
						
							| 
									
										
										
										
											2023-04-14 22:15:43 +08:00
										 |  |  | 		input.charCodeAt(pos) === CC_SOLIDUS && | 
					
						
							| 
									
										
										
										
											2023-04-14 08:31:58 +08:00
										 |  |  | 		input.charCodeAt(pos + 1) === CC_ASTERISK | 
					
						
							|  |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2023-04-14 22:57:18 +08:00
										 |  |  | 		pos += 1; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:31:58 +08:00
										 |  |  | 		while (pos < input.length) { | 
					
						
							|  |  |  | 			if ( | 
					
						
							|  |  |  | 				input.charCodeAt(pos) === CC_ASTERISK && | 
					
						
							|  |  |  | 				input.charCodeAt(pos + 1) === CC_SOLIDUS | 
					
						
							|  |  |  | 			) { | 
					
						
							|  |  |  | 				pos += 2; | 
					
						
							|  |  |  | 				break; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			pos++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-14 08:31:58 +08:00
										 |  |  | 	return pos; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {function(number): CharHandler} */ | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | const consumeString = quote_cc => (input, pos, callbacks) => { | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  | 	const start = pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeString(input, pos, quote_cc); | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  | 	if (callbacks.string !== undefined) { | 
					
						
							|  |  |  | 		pos = callbacks.string(input, start, pos); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return pos; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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) => { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	pos++; | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		if (pos === input.length) return pos; | 
					
						
							|  |  |  | 		const cc = input.charCodeAt(pos); | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 		if (cc === quote_cc) return pos + 1; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		if (_isNewLine(cc)) { | 
					
						
							|  |  |  | 			// bad string
 | 
					
						
							|  |  |  | 			return pos; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 		if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			// 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++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {number} cc char code | 
					
						
							|  |  |  |  * @returns {boolean} is identifier start code | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 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 | 
					
						
							|  |  |  | 	); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {number} first first code point | 
					
						
							|  |  |  |  * @param {number} second second code point | 
					
						
							|  |  |  |  * @returns {boolean} true if two code points are a valid escape | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | const _isTwoCodePointsAreValidEscape = (first, second) => { | 
					
						
							|  |  |  | 	if (first !== CC_REVERSE_SOLIDUS) return false; | 
					
						
							|  |  |  | 	if (_isNewLine(second)) return false; | 
					
						
							|  |  |  | 	return true; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {number} cc char code | 
					
						
							|  |  |  |  * @returns {boolean} is digit | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | const _isDigit = cc => { | 
					
						
							|  |  |  | 	return cc >= CC_0 && cc <= CC_9; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} input input | 
					
						
							|  |  |  |  * @param {number} pos position | 
					
						
							|  |  |  |  * @returns {boolean} true, if input at pos starts an identifier | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 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; | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 		if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			const cc = input.charCodeAt(pos + 2); | 
					
						
							|  |  |  | 			return !_isNewLine(cc); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return _isIdentifierStartCode(cc); | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 	if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		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; | 
					
						
							| 
									
										
										
										
											2021-12-17 03:42:44 +08:00
										 |  |  | 	if (callbacks.isSelector(input, pos) && _startsIdentifier(input, pos)) { | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 		pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		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); | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 	// If the input stream starts with a number, reconsume the current input code point, consume a numeric token, and return it.
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	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 { | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 			pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			if (callbacks.identifier !== undefined) { | 
					
						
							|  |  |  | 				return callbacks.identifier(input, start, pos); | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 	} else if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		if (pos + 1 === input.length) return pos; | 
					
						
							|  |  |  | 		const cc = input.charCodeAt(pos + 1); | 
					
						
							|  |  |  | 		if (_isNewLine(cc)) return pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 		pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		if (callbacks.identifier !== undefined) { | 
					
						
							|  |  |  | 			return callbacks.identifier(input, start, pos); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else if (_isIdentifierStartCode(cc)) { | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 		pos = consumeOtherIdentifier(input, pos - 1, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	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); | 
					
						
							| 
									
										
										
										
											2021-12-17 03:42:44 +08:00
										 |  |  | 	if (!callbacks.isSelector(input, pos) || !_startsIdentifier(input, pos)) | 
					
						
							|  |  |  | 		return pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	if (callbacks.class !== undefined) return callbacks.class(input, start, pos); | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {CharHandler} */ | 
					
						
							|  |  |  | const consumeNumericToken = (input, pos, callbacks) => { | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeNumber(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	if (pos === input.length) return pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	if (_startsIdentifier(input, pos)) | 
					
						
							|  |  |  | 		return _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	const cc = input.charCodeAt(pos); | 
					
						
							|  |  |  | 	if (cc === CC_PERCENTAGE) return pos + 1; | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {CharHandler} */ | 
					
						
							|  |  |  | const consumeOtherIdentifier = (input, pos, callbacks) => { | 
					
						
							|  |  |  | 	const start = pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2023-05-04 22:34:48 +08:00
										 |  |  | 	if (pos !== input.length && input.charCodeAt(pos) === CC_LEFT_PARENTHESIS) { | 
					
						
							| 
									
										
										
										
											2021-12-17 03:42:44 +08:00
										 |  |  | 		pos++; | 
					
						
							|  |  |  | 		if (callbacks.function !== undefined) { | 
					
						
							|  |  |  | 			return callbacks.function(input, start, pos); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		if (callbacks.identifier !== undefined) { | 
					
						
							|  |  |  | 			return callbacks.identifier(input, start, pos); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** @type {CharHandler} */ | 
					
						
							|  |  |  | const consumePotentialUrl = (input, pos, callbacks) => { | 
					
						
							|  |  |  | 	const start = pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 	const nextPos = pos + 1; | 
					
						
							| 
									
										
										
										
											2023-04-06 03:58:23 +08:00
										 |  |  | 	if ( | 
					
						
							|  |  |  | 		pos === start + 3 && | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 		input.slice(start, nextPos).toLowerCase() === "url(" | 
					
						
							| 
									
										
										
										
											2023-04-06 03:58:23 +08:00
										 |  |  | 	) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		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) { | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 			if (callbacks.function !== undefined) { | 
					
						
							|  |  |  | 				return callbacks.function(input, start, nextPos); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 			return nextPos; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		} else { | 
					
						
							|  |  |  | 			const contentStart = pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 			/** @type {number} */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			let contentEnd; | 
					
						
							|  |  |  | 			for (;;) { | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 				if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 					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) { | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 						return callbacks.url(input, start, pos, contentStart, contentEnd); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					return pos; | 
					
						
							|  |  |  | 				} else if (cc === CC_RIGHT_PARENTHESIS) { | 
					
						
							| 
									
										
										
										
											2021-12-03 23:23:09 +08:00
										 |  |  | 					contentEnd = pos; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 					pos++; | 
					
						
							|  |  |  | 					if (callbacks.url !== undefined) { | 
					
						
							| 
									
										
										
										
											2023-04-14 06:52:50 +08:00
										 |  |  | 						return callbacks.url(input, start, pos, contentStart, contentEnd); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 					} | 
					
						
							|  |  |  | 					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++; | 
					
						
							| 
									
										
										
										
											2021-12-17 03:42:44 +08:00
										 |  |  | 	if (!callbacks.isSelector(input, pos) || !_startsIdentifier(input, pos)) | 
					
						
							|  |  |  | 		return pos; | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 	pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** @type {CharHandler} */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | const _consumeIdentifier = (input, pos) => { | 
					
						
							|  |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		const cc = input.charCodeAt(pos); | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 		if (cc === CC_REVERSE_SOLIDUS) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			pos++; | 
					
						
							|  |  |  | 			if (pos === input.length) return pos; | 
					
						
							|  |  |  | 			pos++; | 
					
						
							|  |  |  | 		} else if ( | 
					
						
							|  |  |  | 			_isIdentifierStartCode(cc) || | 
					
						
							|  |  |  | 			_isDigit(cc) || | 
					
						
							|  |  |  | 			cc === CC_HYPHEN_MINUS | 
					
						
							|  |  |  | 		) { | 
					
						
							|  |  |  | 			pos++; | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			return pos; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** @type {CharHandler} */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | /** @type {CharHandler} */ | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | const consumeAt = (input, pos, callbacks) => { | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  | 	const start = pos; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	pos++; | 
					
						
							|  |  |  | 	if (pos === input.length) return pos; | 
					
						
							|  |  |  | 	if (_startsIdentifier(input, pos)) { | 
					
						
							| 
									
										
										
										
											2023-04-29 02:25:27 +08:00
										 |  |  | 		pos = _consumeIdentifier(input, pos, callbacks); | 
					
						
							| 
									
										
										
										
											2021-12-01 20:27:00 +08:00
										 |  |  | 		if (callbacks.atKeyword !== undefined) { | 
					
						
							|  |  |  | 			pos = callbacks.atKeyword(input, start, pos); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	return pos; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | /** @type {CharHandler} */ | 
					
						
							|  |  |  | const consumeReverseSolidus = (input, pos, callbacks) => { | 
					
						
							|  |  |  | 	const start = pos; | 
					
						
							|  |  |  | 	pos++; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 	if (pos === input.length) return pos; | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 	// 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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | const CHAR_MAP = Array.from({ length: 0x80 }, (_, cc) => { | 
					
						
							|  |  |  | 	// https://drafts.csswg.org/css-syntax/#consume-token
 | 
					
						
							|  |  |  | 	switch (cc) { | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// whitespace
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_LINE_FEED: | 
					
						
							|  |  |  | 		case CC_CARRIAGE_RETURN: | 
					
						
							|  |  |  | 		case CC_FORM_FEED: | 
					
						
							|  |  |  | 		case CC_TAB: | 
					
						
							|  |  |  | 		case CC_SPACE: | 
					
						
							|  |  |  | 			return consumeSpace; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+0022 QUOTATION MARK (")
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_QUOTATION_MARK: | 
					
						
							|  |  |  | 			return consumeString(cc); | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+0023 NUMBER SIGN (#)
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_NUMBER_SIGN: | 
					
						
							|  |  |  | 			return consumeNumberSign; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+0027 APOSTROPHE (')
 | 
					
						
							|  |  |  | 		case CC_APOSTROPHE: | 
					
						
							|  |  |  | 			return consumeString(cc); | 
					
						
							|  |  |  | 		// U+0028 LEFT PARENTHESIS (()
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_LEFT_PARENTHESIS: | 
					
						
							|  |  |  | 			return consumeLeftParenthesis; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+0029 RIGHT PARENTHESIS ())
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_RIGHT_PARENTHESIS: | 
					
						
							|  |  |  | 			return consumeRightParenthesis; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+002B PLUS SIGN (+)
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_PLUS_SIGN: | 
					
						
							|  |  |  | 			return consumeNumericToken; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+002C COMMA (,)
 | 
					
						
							|  |  |  | 		case CC_COMMA: | 
					
						
							|  |  |  | 			return consumeComma; | 
					
						
							|  |  |  | 		// U+002D HYPHEN-MINUS (-)
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_HYPHEN_MINUS: | 
					
						
							|  |  |  | 			return consumeMinus; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// 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 (<)
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_LESS_THAN_SIGN: | 
					
						
							|  |  |  | 			return consumeLessThan; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+0040 COMMERCIAL AT (@)
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_AT_SIGN: | 
					
						
							|  |  |  | 			return consumeAt; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// U+005B LEFT SQUARE BRACKET ([)
 | 
					
						
							|  |  |  | 		case CC_LEFT_SQUARE: | 
					
						
							|  |  |  | 			return consumeDelimToken; | 
					
						
							|  |  |  | 		// U+005C REVERSE SOLIDUS (\)
 | 
					
						
							| 
									
										
										
										
											2023-04-14 07:35:53 +08:00
										 |  |  | 		case CC_REVERSE_SOLIDUS: | 
					
						
							|  |  |  | 			return consumeReverseSolidus; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 		// 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
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		case CC_LOWER_U: | 
					
						
							| 
									
										
										
										
											2023-04-06 03:58:23 +08:00
										 |  |  | 		case CC_UPPER_U: | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			return consumePotentialUrl; | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 			// digit
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 			if (_isDigit(cc)) return consumeNumericToken; | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 			// ident-start code point
 | 
					
						
							| 
									
										
										
										
											2023-05-05 06:13:27 +08:00
										 |  |  | 			if (isIdentStartCodePoint(cc)) { | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 				return consumeOtherIdentifier; | 
					
						
							|  |  |  | 			} | 
					
						
							| 
									
										
										
										
											2023-04-14 08:13:47 +08:00
										 |  |  | 			// EOF, but we don't have it
 | 
					
						
							|  |  |  | 			// anything else
 | 
					
						
							|  |  |  | 			return consumeDelimToken; | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | }); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @param {string} input input css | 
					
						
							|  |  |  |  * @param {CssTokenCallbacks} callbacks callbacks | 
					
						
							|  |  |  |  * @returns {void} | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | module.exports = (input, callbacks) => { | 
					
						
							| 
									
										
										
										
											2023-04-14 22:15:43 +08:00
										 |  |  | 	// This section describes how to consume a token from a stream of code points. It will return a single token of any type.
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 	let pos = 0; | 
					
						
							|  |  |  | 	while (pos < input.length) { | 
					
						
							| 
									
										
										
										
											2023-04-14 22:15:43 +08:00
										 |  |  | 		// Consume comments.
 | 
					
						
							|  |  |  | 		pos = consumeComments(input, pos, callbacks); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 22:57:18 +08:00
										 |  |  | 		const cc = input.charCodeAt(pos); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-14 22:15:43 +08:00
										 |  |  | 		// Consume the next input code point.
 | 
					
						
							| 
									
										
										
										
											2021-09-07 15:08:58 +08:00
										 |  |  | 		if (cc < 0x80) { | 
					
						
							|  |  |  | 			pos = CHAR_MAP[cc](input, pos, callbacks); | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			pos++; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | }; | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 06:13:27 +08:00
										 |  |  | module.exports.isIdentStartCodePoint = isIdentStartCodePoint; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-26 08:07:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} input input | 
					
						
							|  |  |  |  * @param {number} pos position | 
					
						
							|  |  |  |  * @returns {number} position after comments | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | module.exports.eatComments = (input, pos) => { | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		let originalPos = pos; | 
					
						
							|  |  |  | 		pos = consumeComments(input, pos, {}); | 
					
						
							|  |  |  | 		if (originalPos === pos) { | 
					
						
							|  |  |  | 			break; | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return pos; | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-05-05 07:05:37 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @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; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-04-26 08:07:13 +08:00
										 |  |  | /** | 
					
						
							|  |  |  |  * @param {string} input input | 
					
						
							|  |  |  |  * @param {number} pos position | 
					
						
							|  |  |  |  * @returns {number} position after whitespace and comments | 
					
						
							|  |  |  |  */ | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | module.exports.eatWhitespaceAndComments = (input, pos) => { | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  | 	for (;;) { | 
					
						
							|  |  |  | 		let originalPos = pos; | 
					
						
							|  |  |  | 		pos = consumeComments(input, pos, {}); | 
					
						
							|  |  |  | 		while (_isWhiteSpace(input.charCodeAt(pos))) { | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | 			pos++; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  | 		if (originalPos === pos) { | 
					
						
							|  |  |  | 			break; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2023-04-26 08:36:44 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	return pos; | 
					
						
							| 
									
										
										
										
											2021-12-14 23:02:26 +08:00
										 |  |  | }; | 
					
						
							| 
									
										
										
										
											2023-05-01 22:46:47 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | /** | 
					
						
							|  |  |  |  * @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; | 
					
						
							|  |  |  | }; |