From 831b7862f29371ccab435ecef450d42fff7214ab Mon Sep 17 00:00:00 2001 From: Romain Menke Date: Thu, 17 Sep 2026 19:56:32 +0200 Subject: [PATCH 1/2] css-tokenizer: fix handling of astral code points --- package-lock.json | 8 ++++---- packages/css-tokenizer/CHANGELOG.md | 4 ++++ packages/css-tokenizer/dist/index.mjs | 2 +- packages/css-tokenizer/package.json | 2 +- packages/css-tokenizer/src/consume/url-token.ts | 8 ++++---- packages/css-tokenizer/src/reader.ts | 2 +- 6 files changed, 15 insertions(+), 11 deletions(-) diff --git a/package-lock.json b/package-lock.json index 9f3b890e07..667f0c5545 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2694,9 +2694,9 @@ "license": "MIT" }, "node_modules/@rmenke/css-tokenizer-tests": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/@rmenke/css-tokenizer-tests/-/css-tokenizer-tests-1.2.0.tgz", - "integrity": "sha512-XfdeXzW5QGc3inl69eid2FTLGY/514xs+VXQWlEzdUVm1QdU6MicU5S2hcEbHoC9WMzIMALTzxiZb49w+xJk0Q==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/@rmenke/css-tokenizer-tests/-/css-tokenizer-tests-1.3.1.tgz", + "integrity": "sha512-iLcijthn5fFF4NBt2VhAaf2mv6RRoeQbHqsbMY9wqUGsWucasO0RHn8jTYqRPH07Zjipob5WIz0AuYJ65NXY/A==", "dev": true, "license": "MIT" }, @@ -8299,7 +8299,7 @@ ], "license": "MIT", "devDependencies": { - "@rmenke/css-tokenizer-tests": "^1.2.0", + "@rmenke/css-tokenizer-tests": "^1.3.1", "postcss": "^8.5.10", "postcss-parser-tests": "^8.10.0" }, diff --git a/packages/css-tokenizer/CHANGELOG.md b/packages/css-tokenizer/CHANGELOG.md index c6d7842a98..6dc611e065 100644 --- a/packages/css-tokenizer/CHANGELOG.md +++ b/packages/css-tokenizer/CHANGELOG.md @@ -1,5 +1,9 @@ # Changes to CSS Tokenizer +### Unreleased (patch) + +- Fix handling of astral code points in `string-token` and `url-token` values. + ### 4.0.0 _January 14, 2026_ diff --git a/packages/css-tokenizer/dist/index.mjs b/packages/css-tokenizer/dist/index.mjs index e0237c0b7e..b536aaf74d 100644 --- a/packages/css-tokenizer/dist/index.mjs +++ b/packages/css-tokenizer/dist/index.mjs @@ -1 +1 @@ -class ParseError extends Error{sourceStart;sourceEnd;parserState;constructor(e,n,t,o){super(e),this.name="ParseError",this.sourceStart=n,this.sourceEnd=t,this.parserState=o}}class ParseErrorWithToken extends ParseError{token;constructor(e,n,t,o,r){super(e,n,t,o),this.token=r}}const e={UnexpectedNewLineInString:"Unexpected newline while consuming a string token.",UnexpectedEOFInString:"Unexpected EOF while consuming a string token.",UnexpectedEOFInComment:"Unexpected EOF while consuming a comment.",UnexpectedEOFInURL:"Unexpected EOF while consuming a url token.",UnexpectedEOFInEscapedCodePoint:"Unexpected EOF while consuming an escaped code point.",UnexpectedCharacterInURL:"Unexpected character while consuming a url token.",InvalidEscapeSequenceInURL:"Invalid escape sequence while consuming a url token.",InvalidEscapeSequenceAfterBackslash:'Invalid escape sequence after "\\"'},n="undefined"!=typeof globalThis&&"structuredClone"in globalThis;function cloneTokens(e){return n?structuredClone(e):JSON.parse(JSON.stringify(e))}function stringify(...e){let n="";for(let t=0;t=48&&e<=57}function isUppercaseLetterCodePoint(e){return e>=65&&e<=90}function isLowercaseLetterCodePoint(e){return e>=97&&e<=122}function isHexDigitCodePoint(e){return e>=48&&e<=57||e>=97&&e<=102||e>=65&&e<=70}function isLetterCodePoint(e){return isLowercaseLetterCodePoint(e)||isUppercaseLetterCodePoint(e)}function isIdentStartCodePoint(e){return isLetterCodePoint(e)||isNonASCII_IdentCodePoint(e)||95===e}function isIdentCodePoint(e){return isIdentStartCodePoint(e)||isDigitCodePoint(e)||e===o}function isNonASCII_IdentCodePoint(e){return 183===e||8204===e||8205===e||8255===e||8256===e||8204===e||(192<=e&&e<=214||216<=e&&e<=246||248<=e&&e<=893||895<=e&&e<=8191||8304<=e&&e<=8591||11264<=e&&e<=12271||12289<=e&&e<=55295||63744<=e&&e<=64975||65008<=e&&e<=65533||(0===e||(!!isSurrogate(e)||e>=65536)))}function isNonPrintableCodePoint(e){return 11===e||127===e||0<=e&&e<=8||14<=e&&e<=31}function isNewLine(e){return e===r||e===t||12===e}function isWhitespace(e){return 32===e||e===r||9===e||e===t||12===e}function isSurrogate(e){return e>=55296&&e<=57343}function checkIfTwoCodePointsAreAValidEscape(e){return 92===e.source.codePointAt(e.cursor)&&!isNewLine(e.source.codePointAt(e.cursor+1)??-1)}function checkIfThreeCodePointsWouldStartAnIdentSequence(e,n){return n.source.codePointAt(n.cursor)===o?n.source.codePointAt(n.cursor+1)===o||(!!isIdentStartCodePoint(n.source.codePointAt(n.cursor+1)??-1)||92===n.source.codePointAt(n.cursor+1)&&!isNewLine(n.source.codePointAt(n.cursor+2)??-1)):!!isIdentStartCodePoint(n.source.codePointAt(n.cursor)??-1)||checkIfTwoCodePointsAreAValidEscape(n)}function checkIfThreeCodePointsWouldStartANumber(e){return e.source.codePointAt(e.cursor)===i||e.source.codePointAt(e.cursor)===o?!!isDigitCodePoint(e.source.codePointAt(e.cursor+1)??-1)||46===e.source.codePointAt(e.cursor+1)&&isDigitCodePoint(e.source.codePointAt(e.cursor+2)??-1):46===e.source.codePointAt(e.cursor)?isDigitCodePoint(e.source.codePointAt(e.cursor+1)??-1):isDigitCodePoint(e.source.codePointAt(e.cursor)??-1)}function checkIfTwoCodePointsStartAComment(e){return 47===e.source.codePointAt(e.cursor)&&42===e.source.codePointAt(e.cursor+1)}function checkIfThreeCodePointsWouldStartCDC(e){return e.source.codePointAt(e.cursor)===o&&e.source.codePointAt(e.cursor+1)===o&&62===e.source.codePointAt(e.cursor+2)}var c,a,u;function mirrorVariantType(e){switch(e){case c.OpenParen:return c.CloseParen;case c.CloseParen:return c.OpenParen;case c.OpenCurly:return c.CloseCurly;case c.CloseCurly:return c.OpenCurly;case c.OpenSquare:return c.CloseSquare;case c.CloseSquare:return c.OpenSquare;default:return null}}function mirrorVariant(e){switch(e[0]){case c.OpenParen:return[c.CloseParen,")",-1,-1,void 0];case c.CloseParen:return[c.OpenParen,"(",-1,-1,void 0];case c.OpenCurly:return[c.CloseCurly,"}",-1,-1,void 0];case c.CloseCurly:return[c.OpenCurly,"{",-1,-1,void 0];case c.OpenSquare:return[c.CloseSquare,"]",-1,-1,void 0];case c.CloseSquare:return[c.OpenSquare,"[",-1,-1,void 0];default:return null}}function consumeComment(n,t){for(t.advanceCodePoint(2);;){const o=t.readCodePoint();if(void 0===o){const o=[c.Comment,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInComment,t.representationStart,t.representationEnd,["4.3.2. Consume comments","Unexpected EOF"],o)),o}if(42===o&&(void 0!==t.source.codePointAt(t.cursor)&&47===t.source.codePointAt(t.cursor))){t.advanceCodePoint();break}}return[c.Comment,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0]}function consumeEscapedCodePoint(n,o){const i=o.readCodePoint();if(void 0===i)return n.onParseError(new ParseError(e.UnexpectedEOFInEscapedCodePoint,o.representationStart,o.representationEnd,["4.3.7. Consume an escaped code point","Unexpected EOF"])),s;if(isHexDigitCodePoint(i)){const e=[i];let n;for(;void 0!==(n=o.source.codePointAt(o.cursor))&&isHexDigitCodePoint(n)&&e.length<6;)e.push(n),o.advanceCodePoint();isWhitespace(o.source.codePointAt(o.cursor)??-1)&&(o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r&&o.advanceCodePoint(),o.advanceCodePoint());const c=parseInt(String.fromCodePoint(...e),16);return 0===c||isSurrogate(c)||c>1114111?s:c}return 0===i||isSurrogate(i)?s:i}function consumeIdentSequence(e,n){const t=[];for(;;){const o=n.source.codePointAt(n.cursor)??-1;if(0===o||isSurrogate(o))t.push(s),n.advanceCodePoint(+(o>65535)+1);else if(isIdentCodePoint(o))t.push(o),n.advanceCodePoint(+(o>65535)+1);else{if(!checkIfTwoCodePointsAreAValidEscape(n))return t;n.advanceCodePoint(),t.push(consumeEscapedCodePoint(e,n))}}}function consumeHashToken(e,n){n.advanceCodePoint();const t=n.source.codePointAt(n.cursor);if(void 0!==t&&(isIdentCodePoint(t)||checkIfTwoCodePointsAreAValidEscape(n))){let t=u.Unrestricted;checkIfThreeCodePointsWouldStartAnIdentSequence(0,n)&&(t=u.ID);const o=consumeIdentSequence(e,n);return[c.Hash,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...o),type:t}]}return[c.Delim,"#",n.representationStart,n.representationEnd,{value:"#"}]}function consumeNumber(e,n){let t=a.Integer;for(n.source.codePointAt(n.cursor)!==i&&n.source.codePointAt(n.cursor)!==o||n.advanceCodePoint();isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint();if(46===n.source.codePointAt(n.cursor)&&isDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))for(n.advanceCodePoint(2),t=a.Number;isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint();if(101===n.source.codePointAt(n.cursor)||69===n.source.codePointAt(n.cursor)){if(isDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))n.advanceCodePoint(2);else{if(n.source.codePointAt(n.cursor+1)!==o&&n.source.codePointAt(n.cursor+1)!==i||!isDigitCodePoint(n.source.codePointAt(n.cursor+2)??-1))return t;n.advanceCodePoint(3)}for(t=a.Number;isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint()}return t}function consumeNumericToken(e,n){let t;{const e=n.source.codePointAt(n.cursor);e===o?t="-":e===i&&(t="+")}const r=consumeNumber(0,n),s=parseFloat(n.source.slice(n.representationStart,n.representationEnd+1));if(checkIfThreeCodePointsWouldStartAnIdentSequence(0,n)){const o=consumeIdentSequence(e,n);return[c.Dimension,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t,type:r,unit:String.fromCodePoint(...o)}]}return 37===n.source.codePointAt(n.cursor)?(n.advanceCodePoint(),[c.Percentage,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t}]):[c.Number,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t,type:r}]}function consumeWhiteSpace(e){for(;isWhitespace(e.source.codePointAt(e.cursor)??-1);)e.advanceCodePoint();return[c.Whitespace,e.source.slice(e.representationStart,e.representationEnd+1),e.representationStart,e.representationEnd,void 0]}!function(e){e.Comment="comment",e.AtKeyword="at-keyword-token",e.BadString="bad-string-token",e.BadURL="bad-url-token",e.CDC="CDC-token",e.CDO="CDO-token",e.Colon="colon-token",e.Comma="comma-token",e.Delim="delim-token",e.Dimension="dimension-token",e.EOF="EOF-token",e.Function="function-token",e.Hash="hash-token",e.Ident="ident-token",e.Number="number-token",e.Percentage="percentage-token",e.Semicolon="semicolon-token",e.String="string-token",e.URL="url-token",e.Whitespace="whitespace-token",e.OpenParen="(-token",e.CloseParen=")-token",e.OpenSquare="[-token",e.CloseSquare="]-token",e.OpenCurly="{-token",e.CloseCurly="}-token",e.UnicodeRange="unicode-range-token"}(c||(c={})),function(e){e.Integer="integer",e.Number="number"}(a||(a={})),function(e){e.Unrestricted="unrestricted",e.ID="id"}(u||(u={}));class Reader{cursor=0;source="";representationStart=0;representationEnd=-1;constructor(e){this.source=e}advanceCodePoint(e=1){this.cursor=this.cursor+e,this.representationEnd=this.cursor-1}readCodePoint(){const e=this.source.codePointAt(this.cursor);if(void 0!==e)return this.cursor=this.cursor+1,this.representationEnd=this.cursor-1,e}unreadCodePoint(e=1){this.cursor=this.cursor-e,this.representationEnd=this.cursor-1}resetRepresentation(){this.representationStart=this.cursor,this.representationEnd=-1}}function consumeStringToken(n,o){let i="";const a=o.readCodePoint();for(;;){const u=o.readCodePoint();if(void 0===u){const t=[c.String,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,{value:i}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInString,o.representationStart,o.representationEnd,["4.3.5. Consume a string token","Unexpected EOF"],t)),t}if(isNewLine(u)){o.unreadCodePoint();const i=[c.BadString,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedNewLineInString,o.representationStart,o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r?o.representationEnd+2:o.representationEnd+1,["4.3.5. Consume a string token","Unexpected newline"],i)),i}if(u===a)return[c.String,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,{value:i}];if(92!==u)0===u||isSurrogate(u)?i+=String.fromCodePoint(s):i+=String.fromCodePoint(u);else{if(void 0===o.source.codePointAt(o.cursor))continue;if(isNewLine(o.source.codePointAt(o.cursor)??-1)){o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r&&o.advanceCodePoint(),o.advanceCodePoint();continue}i+=String.fromCodePoint(consumeEscapedCodePoint(n,o))}}}function checkIfCodePointsMatchURLIdent(e){return!(3!==e.length||117!==e[0]&&85!==e[0]||114!==e[1]&&82!==e[1]||108!==e[2]&&76!==e[2])}function consumeBadURL(e,n){for(;;){const t=n.source.codePointAt(n.cursor);if(void 0===t)return;if(41===t)return void n.advanceCodePoint();checkIfTwoCodePointsAreAValidEscape(n)?(n.advanceCodePoint(),consumeEscapedCodePoint(e,n)):n.advanceCodePoint()}}function consumeUrlToken(n,t){for(;isWhitespace(t.source.codePointAt(t.cursor)??-1);)t.advanceCodePoint();let o="";for(;;){if(void 0===t.source.codePointAt(t.cursor)){const r=[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Unexpected EOF"],r)),r}if(41===t.source.codePointAt(t.cursor))return t.advanceCodePoint(),[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];if(isWhitespace(t.source.codePointAt(t.cursor)??-1)){for(t.advanceCodePoint();isWhitespace(t.source.codePointAt(t.cursor)??-1);)t.advanceCodePoint();if(void 0===t.source.codePointAt(t.cursor)){const r=[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Consume as much whitespace as possible","Unexpected EOF"],r)),r}return 41===t.source.codePointAt(t.cursor)?(t.advanceCodePoint(),[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}]):(consumeBadURL(n,t),[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0])}const r=t.source.codePointAt(t.cursor);if(34===r||39===r||40===r||isNonPrintableCodePoint(r??-1)){consumeBadURL(n,t);const o=[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedCharacterInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Unexpected U+0022 QUOTATION MARK (\"), U+0027 APOSTROPHE ('), U+0028 LEFT PARENTHESIS (() or non-printable code point"],o)),o}if(92===r){if(checkIfTwoCodePointsAreAValidEscape(t)){t.advanceCodePoint(),o+=String.fromCodePoint(consumeEscapedCodePoint(n,t));continue}consumeBadURL(n,t);const r=[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.InvalidEscapeSequenceInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","U+005C REVERSE SOLIDUS (\\)","The input stream does not start with a valid escape sequence"],r)),r}0===t.source.codePointAt(t.cursor)||isSurrogate(t.source.codePointAt(t.cursor)??-1)?(o+=String.fromCodePoint(s),t.advanceCodePoint()):(o+=t.source[t.cursor],t.advanceCodePoint())}}function consumeIdentLikeToken(e,n){const t=consumeIdentSequence(e,n);if(40!==n.source.codePointAt(n.cursor))return[c.Ident,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}];if(checkIfCodePointsMatchURLIdent(t)){n.advanceCodePoint();let o=0;for(;;){const e=isWhitespace(n.source.codePointAt(n.cursor)??-1),r=isWhitespace(n.source.codePointAt(n.cursor+1)??-1);if(e&&r){o+=1,n.advanceCodePoint(1);continue}const i=e?n.source.codePointAt(n.cursor+1):n.source.codePointAt(n.cursor);if(34===i||39===i)return o>0&&n.unreadCodePoint(o),[c.Function,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}];break}return consumeUrlToken(e,n)}return n.advanceCodePoint(),[c.Function,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}]}function checkIfThreeCodePointsWouldStartAUnicodeRange(e){return!(117!==e.source.codePointAt(e.cursor)&&85!==e.source.codePointAt(e.cursor)||e.source.codePointAt(e.cursor+1)!==i||63!==e.source.codePointAt(e.cursor+2)&&!isHexDigitCodePoint(e.source.codePointAt(e.cursor+2)??-1))}function consumeUnicodeRangeToken(e,n){n.advanceCodePoint(2);const t=[],r=[];let i;for(;void 0!==(i=n.source.codePointAt(n.cursor))&&t.length<6&&isHexDigitCodePoint(i);)t.push(i),n.advanceCodePoint();for(;void 0!==(i=n.source.codePointAt(n.cursor))&&t.length<6&&63===i;)0===r.length&&r.push(...t),t.push(48),r.push(70),n.advanceCodePoint();if(!r.length&&n.source.codePointAt(n.cursor)===o&&isHexDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))for(n.advanceCodePoint();void 0!==(i=n.source.codePointAt(n.cursor))&&r.length<6&&isHexDigitCodePoint(i);)r.push(i),n.advanceCodePoint();if(!r.length){const e=parseInt(String.fromCodePoint(...t),16);return[c.UnicodeRange,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{startOfRange:e,endOfRange:e}]}const s=parseInt(String.fromCodePoint(...t),16),a=parseInt(String.fromCodePoint(...r),16);return[c.UnicodeRange,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{startOfRange:s,endOfRange:a}]}function tokenize(e,n){const t=tokenizer(e,n),o=[];for(;!t.endOfFile();)o.push(t.nextToken());return o.push(t.nextToken()),o}function tokenizer(n,s){const a=n.css.valueOf(),u=n.unicodeRangesAllowed??!1,d=new Reader(a),p={onParseError:s?.onParseError??noop};return{nextToken:function nextToken(){d.resetRepresentation();const n=d.source.codePointAt(d.cursor);if(void 0===n)return[c.EOF,"",-1,-1,void 0];if(47===n&&checkIfTwoCodePointsStartAComment(d))return consumeComment(p,d);if(u&&(117===n||85===n)&&checkIfThreeCodePointsWouldStartAUnicodeRange(d))return consumeUnicodeRangeToken(0,d);if(isIdentStartCodePoint(n))return consumeIdentLikeToken(p,d);if(isDigitCodePoint(n))return consumeNumericToken(p,d);switch(n){case 44:return d.advanceCodePoint(),[c.Comma,",",d.representationStart,d.representationEnd,void 0];case 58:return d.advanceCodePoint(),[c.Colon,":",d.representationStart,d.representationEnd,void 0];case 59:return d.advanceCodePoint(),[c.Semicolon,";",d.representationStart,d.representationEnd,void 0];case 40:return d.advanceCodePoint(),[c.OpenParen,"(",d.representationStart,d.representationEnd,void 0];case 41:return d.advanceCodePoint(),[c.CloseParen,")",d.representationStart,d.representationEnd,void 0];case 91:return d.advanceCodePoint(),[c.OpenSquare,"[",d.representationStart,d.representationEnd,void 0];case 93:return d.advanceCodePoint(),[c.CloseSquare,"]",d.representationStart,d.representationEnd,void 0];case 123:return d.advanceCodePoint(),[c.OpenCurly,"{",d.representationStart,d.representationEnd,void 0];case 125:return d.advanceCodePoint(),[c.CloseCurly,"}",d.representationStart,d.representationEnd,void 0];case 39:case 34:return consumeStringToken(p,d);case 35:return consumeHashToken(p,d);case i:case 46:return checkIfThreeCodePointsWouldStartANumber(d)?consumeNumericToken(p,d):(d.advanceCodePoint(),[c.Delim,d.source[d.representationStart],d.representationStart,d.representationEnd,{value:d.source[d.representationStart]}]);case r:case t:case 12:case 9:case 32:return consumeWhiteSpace(d);case o:return checkIfThreeCodePointsWouldStartANumber(d)?consumeNumericToken(p,d):checkIfThreeCodePointsWouldStartCDC(d)?(d.advanceCodePoint(3),[c.CDC,"--\x3e",d.representationStart,d.representationEnd,void 0]):checkIfThreeCodePointsWouldStartAnIdentSequence(0,d)?consumeIdentLikeToken(p,d):(d.advanceCodePoint(),[c.Delim,"-",d.representationStart,d.representationEnd,{value:"-"}]);case 60:return checkIfFourCodePointsWouldStartCDO(d)?(d.advanceCodePoint(4),[c.CDO,"\x3c!--",d.representationStart,d.representationEnd,void 0]):(d.advanceCodePoint(),[c.Delim,"<",d.representationStart,d.representationEnd,{value:"<"}]);case 64:if(d.advanceCodePoint(),checkIfThreeCodePointsWouldStartAnIdentSequence(0,d)){const e=consumeIdentSequence(p,d);return[c.AtKeyword,d.source.slice(d.representationStart,d.representationEnd+1),d.representationStart,d.representationEnd,{value:String.fromCodePoint(...e)}]}return[c.Delim,"@",d.representationStart,d.representationEnd,{value:"@"}];case 92:{if(checkIfTwoCodePointsAreAValidEscape(d))return consumeIdentLikeToken(p,d);d.advanceCodePoint();const n=[c.Delim,"\\",d.representationStart,d.representationEnd,{value:"\\"}];return p.onParseError(new ParseErrorWithToken(e.InvalidEscapeSequenceAfterBackslash,d.representationStart,d.representationEnd,["4.3.1. Consume a token","U+005C REVERSE SOLIDUS (\\)","The input stream does not start with a valid escape sequence"],n)),n}}return d.advanceCodePoint(),[c.Delim,d.source[d.representationStart],d.representationStart,d.representationEnd,{value:d.source[d.representationStart]}]},endOfFile:function endOfFile(){return void 0===d.source.codePointAt(d.cursor)}}}function noop(){}function mutateIdent(e,n){const t=[];for(const e of n)t.push(e.codePointAt(0));const o=String.fromCodePoint(...serializeIdent(t));e[1]=o,e[4].value=n}function mutateUnit(e,n){const t=[];for(const e of n)t.push(e.codePointAt(0));const o=serializeIdent(t);101===o[0]&&insertEscapedCodePoint(o,0,o[0]);const r=String.fromCodePoint(...o),i="+"===e[4].signCharacter?e[4].signCharacter:"",s=e[4].value.toString();e[1]=`${i}${s}${r}`,e[4].unit=n}function serializeIdent(e){let n;if(0===e[0])e.splice(0,1,s),n=1;else if(e[0]===o&&e[1]===o)n=2;else if(e[0]===o&&e[1])n=2,isIdentStartCodePoint(e[1])||(n+=insertEscapedCodePoint(e,1,e[1]));else{if(e[0]===o&&!e[1])return[92,e[0]];isIdentStartCodePoint(e[0])?n=1:(n=1,n+=insertEscapedCodePoint(e,0,e[0]))}for(let t=n;t=48&&e<=57}function isUppercaseLetterCodePoint(e){return e>=65&&e<=90}function isLowercaseLetterCodePoint(e){return e>=97&&e<=122}function isHexDigitCodePoint(e){return e>=48&&e<=57||e>=97&&e<=102||e>=65&&e<=70}function isLetterCodePoint(e){return isLowercaseLetterCodePoint(e)||isUppercaseLetterCodePoint(e)}function isIdentStartCodePoint(e){return isLetterCodePoint(e)||isNonASCII_IdentCodePoint(e)||95===e}function isIdentCodePoint(e){return isIdentStartCodePoint(e)||isDigitCodePoint(e)||e===o}function isNonASCII_IdentCodePoint(e){return 183===e||8204===e||8205===e||8255===e||8256===e||8204===e||(192<=e&&e<=214||216<=e&&e<=246||248<=e&&e<=893||895<=e&&e<=8191||8304<=e&&e<=8591||11264<=e&&e<=12271||12289<=e&&e<=55295||63744<=e&&e<=64975||65008<=e&&e<=65533||(0===e||(!!isSurrogate(e)||e>=65536)))}function isNonPrintableCodePoint(e){return 11===e||127===e||0<=e&&e<=8||14<=e&&e<=31}function isNewLine(e){return e===r||e===t||12===e}function isWhitespace(e){return 32===e||e===r||9===e||e===t||12===e}function isSurrogate(e){return e>=55296&&e<=57343}function checkIfTwoCodePointsAreAValidEscape(e){return 92===e.source.codePointAt(e.cursor)&&!isNewLine(e.source.codePointAt(e.cursor+1)??-1)}function checkIfThreeCodePointsWouldStartAnIdentSequence(e,n){return n.source.codePointAt(n.cursor)===o?n.source.codePointAt(n.cursor+1)===o||(!!isIdentStartCodePoint(n.source.codePointAt(n.cursor+1)??-1)||92===n.source.codePointAt(n.cursor+1)&&!isNewLine(n.source.codePointAt(n.cursor+2)??-1)):!!isIdentStartCodePoint(n.source.codePointAt(n.cursor)??-1)||checkIfTwoCodePointsAreAValidEscape(n)}function checkIfThreeCodePointsWouldStartANumber(e){return e.source.codePointAt(e.cursor)===i||e.source.codePointAt(e.cursor)===o?!!isDigitCodePoint(e.source.codePointAt(e.cursor+1)??-1)||46===e.source.codePointAt(e.cursor+1)&&isDigitCodePoint(e.source.codePointAt(e.cursor+2)??-1):46===e.source.codePointAt(e.cursor)?isDigitCodePoint(e.source.codePointAt(e.cursor+1)??-1):isDigitCodePoint(e.source.codePointAt(e.cursor)??-1)}function checkIfTwoCodePointsStartAComment(e){return 47===e.source.codePointAt(e.cursor)&&42===e.source.codePointAt(e.cursor+1)}function checkIfThreeCodePointsWouldStartCDC(e){return e.source.codePointAt(e.cursor)===o&&e.source.codePointAt(e.cursor+1)===o&&62===e.source.codePointAt(e.cursor+2)}var c,a,u;function mirrorVariantType(e){switch(e){case c.OpenParen:return c.CloseParen;case c.CloseParen:return c.OpenParen;case c.OpenCurly:return c.CloseCurly;case c.CloseCurly:return c.OpenCurly;case c.OpenSquare:return c.CloseSquare;case c.CloseSquare:return c.OpenSquare;default:return null}}function mirrorVariant(e){switch(e[0]){case c.OpenParen:return[c.CloseParen,")",-1,-1,void 0];case c.CloseParen:return[c.OpenParen,"(",-1,-1,void 0];case c.OpenCurly:return[c.CloseCurly,"}",-1,-1,void 0];case c.CloseCurly:return[c.OpenCurly,"{",-1,-1,void 0];case c.OpenSquare:return[c.CloseSquare,"]",-1,-1,void 0];case c.CloseSquare:return[c.OpenSquare,"[",-1,-1,void 0];default:return null}}function consumeComment(n,t){for(t.advanceCodePoint(2);;){const o=t.readCodePoint();if(void 0===o){const o=[c.Comment,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInComment,t.representationStart,t.representationEnd,["4.3.2. Consume comments","Unexpected EOF"],o)),o}if(42===o&&(void 0!==t.source.codePointAt(t.cursor)&&47===t.source.codePointAt(t.cursor))){t.advanceCodePoint();break}}return[c.Comment,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0]}function consumeEscapedCodePoint(n,o){const i=o.readCodePoint();if(void 0===i)return n.onParseError(new ParseError(e.UnexpectedEOFInEscapedCodePoint,o.representationStart,o.representationEnd,["4.3.7. Consume an escaped code point","Unexpected EOF"])),s;if(isHexDigitCodePoint(i)){const e=[i];let n;for(;void 0!==(n=o.source.codePointAt(o.cursor))&&isHexDigitCodePoint(n)&&e.length<6;)e.push(n),o.advanceCodePoint();isWhitespace(o.source.codePointAt(o.cursor)??-1)&&(o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r&&o.advanceCodePoint(),o.advanceCodePoint());const c=parseInt(String.fromCodePoint(...e),16);return 0===c||isSurrogate(c)||c>1114111?s:c}return 0===i||isSurrogate(i)?s:i}function consumeIdentSequence(e,n){const t=[];for(;;){const o=n.source.codePointAt(n.cursor)??-1;if(0===o||isSurrogate(o))t.push(s),n.advanceCodePoint(+(o>65535)+1);else if(isIdentCodePoint(o))t.push(o),n.advanceCodePoint(+(o>65535)+1);else{if(!checkIfTwoCodePointsAreAValidEscape(n))return t;n.advanceCodePoint(),t.push(consumeEscapedCodePoint(e,n))}}}function consumeHashToken(e,n){n.advanceCodePoint();const t=n.source.codePointAt(n.cursor);if(void 0!==t&&(isIdentCodePoint(t)||checkIfTwoCodePointsAreAValidEscape(n))){let t=u.Unrestricted;checkIfThreeCodePointsWouldStartAnIdentSequence(0,n)&&(t=u.ID);const o=consumeIdentSequence(e,n);return[c.Hash,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...o),type:t}]}return[c.Delim,"#",n.representationStart,n.representationEnd,{value:"#"}]}function consumeNumber(e,n){let t=a.Integer;for(n.source.codePointAt(n.cursor)!==i&&n.source.codePointAt(n.cursor)!==o||n.advanceCodePoint();isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint();if(46===n.source.codePointAt(n.cursor)&&isDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))for(n.advanceCodePoint(2),t=a.Number;isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint();if(101===n.source.codePointAt(n.cursor)||69===n.source.codePointAt(n.cursor)){if(isDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))n.advanceCodePoint(2);else{if(n.source.codePointAt(n.cursor+1)!==o&&n.source.codePointAt(n.cursor+1)!==i||!isDigitCodePoint(n.source.codePointAt(n.cursor+2)??-1))return t;n.advanceCodePoint(3)}for(t=a.Number;isDigitCodePoint(n.source.codePointAt(n.cursor)??-1);)n.advanceCodePoint()}return t}function consumeNumericToken(e,n){let t;{const e=n.source.codePointAt(n.cursor);e===o?t="-":e===i&&(t="+")}const r=consumeNumber(0,n),s=parseFloat(n.source.slice(n.representationStart,n.representationEnd+1));if(checkIfThreeCodePointsWouldStartAnIdentSequence(0,n)){const o=consumeIdentSequence(e,n);return[c.Dimension,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t,type:r,unit:String.fromCodePoint(...o)}]}return 37===n.source.codePointAt(n.cursor)?(n.advanceCodePoint(),[c.Percentage,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t}]):[c.Number,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:s,signCharacter:t,type:r}]}function consumeWhiteSpace(e){for(;isWhitespace(e.source.codePointAt(e.cursor)??-1);)e.advanceCodePoint();return[c.Whitespace,e.source.slice(e.representationStart,e.representationEnd+1),e.representationStart,e.representationEnd,void 0]}!function(e){e.Comment="comment",e.AtKeyword="at-keyword-token",e.BadString="bad-string-token",e.BadURL="bad-url-token",e.CDC="CDC-token",e.CDO="CDO-token",e.Colon="colon-token",e.Comma="comma-token",e.Delim="delim-token",e.Dimension="dimension-token",e.EOF="EOF-token",e.Function="function-token",e.Hash="hash-token",e.Ident="ident-token",e.Number="number-token",e.Percentage="percentage-token",e.Semicolon="semicolon-token",e.String="string-token",e.URL="url-token",e.Whitespace="whitespace-token",e.OpenParen="(-token",e.CloseParen=")-token",e.OpenSquare="[-token",e.CloseSquare="]-token",e.OpenCurly="{-token",e.CloseCurly="}-token",e.UnicodeRange="unicode-range-token"}(c||(c={})),function(e){e.Integer="integer",e.Number="number"}(a||(a={})),function(e){e.Unrestricted="unrestricted",e.ID="id"}(u||(u={}));class Reader{cursor=0;source="";representationStart=0;representationEnd=-1;constructor(e){this.source=e}advanceCodePoint(e=1){this.cursor=this.cursor+e,this.representationEnd=this.cursor-1}readCodePoint(){const e=this.source.codePointAt(this.cursor);if(void 0!==e)return this.cursor=this.cursor+1+ +(e>65535),this.representationEnd=this.cursor-1,e}unreadCodePoint(e=1){this.cursor=this.cursor-e,this.representationEnd=this.cursor-1}resetRepresentation(){this.representationStart=this.cursor,this.representationEnd=-1}}function consumeStringToken(n,o){let i="";const a=o.readCodePoint();for(;;){const u=o.readCodePoint();if(void 0===u){const t=[c.String,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,{value:i}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInString,o.representationStart,o.representationEnd,["4.3.5. Consume a string token","Unexpected EOF"],t)),t}if(isNewLine(u)){o.unreadCodePoint();const i=[c.BadString,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedNewLineInString,o.representationStart,o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r?o.representationEnd+2:o.representationEnd+1,["4.3.5. Consume a string token","Unexpected newline"],i)),i}if(u===a)return[c.String,o.source.slice(o.representationStart,o.representationEnd+1),o.representationStart,o.representationEnd,{value:i}];if(92!==u)0===u||isSurrogate(u)?i+=String.fromCodePoint(s):i+=String.fromCodePoint(u);else{if(void 0===o.source.codePointAt(o.cursor))continue;if(isNewLine(o.source.codePointAt(o.cursor)??-1)){o.source.codePointAt(o.cursor)===t&&o.source.codePointAt(o.cursor+1)===r&&o.advanceCodePoint(),o.advanceCodePoint();continue}i+=String.fromCodePoint(consumeEscapedCodePoint(n,o))}}}function checkIfCodePointsMatchURLIdent(e){return!(3!==e.length||117!==e[0]&&85!==e[0]||114!==e[1]&&82!==e[1]||108!==e[2]&&76!==e[2])}function consumeBadURL(e,n){for(;;){const t=n.source.codePointAt(n.cursor);if(void 0===t)return;if(41===t)return void n.advanceCodePoint();checkIfTwoCodePointsAreAValidEscape(n)?(n.advanceCodePoint(),consumeEscapedCodePoint(e,n)):n.advanceCodePoint()}}function consumeUrlToken(n,t){for(;isWhitespace(t.source.codePointAt(t.cursor)??-1);)t.advanceCodePoint();let o="";for(;;){if(void 0===t.source.codePointAt(t.cursor)){const r=[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Unexpected EOF"],r)),r}if(41===t.source.codePointAt(t.cursor))return t.advanceCodePoint(),[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];if(isWhitespace(t.source.codePointAt(t.cursor)??-1)){for(t.advanceCodePoint();isWhitespace(t.source.codePointAt(t.cursor)??-1);)t.advanceCodePoint();if(void 0===t.source.codePointAt(t.cursor)){const r=[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}];return n.onParseError(new ParseErrorWithToken(e.UnexpectedEOFInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Consume as much whitespace as possible","Unexpected EOF"],r)),r}return 41===t.source.codePointAt(t.cursor)?(t.advanceCodePoint(),[c.URL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,{value:o}]):(consumeBadURL(n,t),[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0])}const r=t.source.codePointAt(t.cursor);if(34===r||39===r||40===r||isNonPrintableCodePoint(r??-1)){consumeBadURL(n,t);const o=[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.UnexpectedCharacterInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","Unexpected U+0022 QUOTATION MARK (\"), U+0027 APOSTROPHE ('), U+0028 LEFT PARENTHESIS (() or non-printable code point"],o)),o}if(92===r){if(checkIfTwoCodePointsAreAValidEscape(t)){t.advanceCodePoint(),o+=String.fromCodePoint(consumeEscapedCodePoint(n,t));continue}consumeBadURL(n,t);const r=[c.BadURL,t.source.slice(t.representationStart,t.representationEnd+1),t.representationStart,t.representationEnd,void 0];return n.onParseError(new ParseErrorWithToken(e.InvalidEscapeSequenceInURL,t.representationStart,t.representationEnd,["4.3.6. Consume a url token","U+005C REVERSE SOLIDUS (\\)","The input stream does not start with a valid escape sequence"],r)),r}0===r||isSurrogate(r??-1)?(o+=String.fromCodePoint(s),t.advanceCodePoint(+((r??-1)>65535)+1)):(o+=String.fromCodePoint(r??-1),t.advanceCodePoint(+((r??-1)>65535)+1))}}function consumeIdentLikeToken(e,n){const t=consumeIdentSequence(e,n);if(40!==n.source.codePointAt(n.cursor))return[c.Ident,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}];if(checkIfCodePointsMatchURLIdent(t)){n.advanceCodePoint();let o=0;for(;;){const e=isWhitespace(n.source.codePointAt(n.cursor)??-1),r=isWhitespace(n.source.codePointAt(n.cursor+1)??-1);if(e&&r){o+=1,n.advanceCodePoint(1);continue}const i=e?n.source.codePointAt(n.cursor+1):n.source.codePointAt(n.cursor);if(34===i||39===i)return o>0&&n.unreadCodePoint(o),[c.Function,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}];break}return consumeUrlToken(e,n)}return n.advanceCodePoint(),[c.Function,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{value:String.fromCodePoint(...t)}]}function checkIfThreeCodePointsWouldStartAUnicodeRange(e){return!(117!==e.source.codePointAt(e.cursor)&&85!==e.source.codePointAt(e.cursor)||e.source.codePointAt(e.cursor+1)!==i||63!==e.source.codePointAt(e.cursor+2)&&!isHexDigitCodePoint(e.source.codePointAt(e.cursor+2)??-1))}function consumeUnicodeRangeToken(e,n){n.advanceCodePoint(2);const t=[],r=[];let i;for(;void 0!==(i=n.source.codePointAt(n.cursor))&&t.length<6&&isHexDigitCodePoint(i);)t.push(i),n.advanceCodePoint();for(;void 0!==(i=n.source.codePointAt(n.cursor))&&t.length<6&&63===i;)0===r.length&&r.push(...t),t.push(48),r.push(70),n.advanceCodePoint();if(!r.length&&n.source.codePointAt(n.cursor)===o&&isHexDigitCodePoint(n.source.codePointAt(n.cursor+1)??-1))for(n.advanceCodePoint();void 0!==(i=n.source.codePointAt(n.cursor))&&r.length<6&&isHexDigitCodePoint(i);)r.push(i),n.advanceCodePoint();if(!r.length){const e=parseInt(String.fromCodePoint(...t),16);return[c.UnicodeRange,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{startOfRange:e,endOfRange:e}]}const s=parseInt(String.fromCodePoint(...t),16),a=parseInt(String.fromCodePoint(...r),16);return[c.UnicodeRange,n.source.slice(n.representationStart,n.representationEnd+1),n.representationStart,n.representationEnd,{startOfRange:s,endOfRange:a}]}function tokenize(e,n){const t=tokenizer(e,n),o=[];for(;!t.endOfFile();)o.push(t.nextToken());return o.push(t.nextToken()),o}function tokenizer(n,s){const a=n.css.valueOf(),u=n.unicodeRangesAllowed??!1,d=new Reader(a),p={onParseError:s?.onParseError??noop};return{nextToken:function nextToken(){d.resetRepresentation();const n=d.source.codePointAt(d.cursor);if(void 0===n)return[c.EOF,"",-1,-1,void 0];if(47===n&&checkIfTwoCodePointsStartAComment(d))return consumeComment(p,d);if(u&&(117===n||85===n)&&checkIfThreeCodePointsWouldStartAUnicodeRange(d))return consumeUnicodeRangeToken(0,d);if(isIdentStartCodePoint(n))return consumeIdentLikeToken(p,d);if(isDigitCodePoint(n))return consumeNumericToken(p,d);switch(n){case 44:return d.advanceCodePoint(),[c.Comma,",",d.representationStart,d.representationEnd,void 0];case 58:return d.advanceCodePoint(),[c.Colon,":",d.representationStart,d.representationEnd,void 0];case 59:return d.advanceCodePoint(),[c.Semicolon,";",d.representationStart,d.representationEnd,void 0];case 40:return d.advanceCodePoint(),[c.OpenParen,"(",d.representationStart,d.representationEnd,void 0];case 41:return d.advanceCodePoint(),[c.CloseParen,")",d.representationStart,d.representationEnd,void 0];case 91:return d.advanceCodePoint(),[c.OpenSquare,"[",d.representationStart,d.representationEnd,void 0];case 93:return d.advanceCodePoint(),[c.CloseSquare,"]",d.representationStart,d.representationEnd,void 0];case 123:return d.advanceCodePoint(),[c.OpenCurly,"{",d.representationStart,d.representationEnd,void 0];case 125:return d.advanceCodePoint(),[c.CloseCurly,"}",d.representationStart,d.representationEnd,void 0];case 39:case 34:return consumeStringToken(p,d);case 35:return consumeHashToken(p,d);case i:case 46:return checkIfThreeCodePointsWouldStartANumber(d)?consumeNumericToken(p,d):(d.advanceCodePoint(),[c.Delim,d.source[d.representationStart],d.representationStart,d.representationEnd,{value:d.source[d.representationStart]}]);case r:case t:case 12:case 9:case 32:return consumeWhiteSpace(d);case o:return checkIfThreeCodePointsWouldStartANumber(d)?consumeNumericToken(p,d):checkIfThreeCodePointsWouldStartCDC(d)?(d.advanceCodePoint(3),[c.CDC,"--\x3e",d.representationStart,d.representationEnd,void 0]):checkIfThreeCodePointsWouldStartAnIdentSequence(0,d)?consumeIdentLikeToken(p,d):(d.advanceCodePoint(),[c.Delim,"-",d.representationStart,d.representationEnd,{value:"-"}]);case 60:return checkIfFourCodePointsWouldStartCDO(d)?(d.advanceCodePoint(4),[c.CDO,"\x3c!--",d.representationStart,d.representationEnd,void 0]):(d.advanceCodePoint(),[c.Delim,"<",d.representationStart,d.representationEnd,{value:"<"}]);case 64:if(d.advanceCodePoint(),checkIfThreeCodePointsWouldStartAnIdentSequence(0,d)){const e=consumeIdentSequence(p,d);return[c.AtKeyword,d.source.slice(d.representationStart,d.representationEnd+1),d.representationStart,d.representationEnd,{value:String.fromCodePoint(...e)}]}return[c.Delim,"@",d.representationStart,d.representationEnd,{value:"@"}];case 92:{if(checkIfTwoCodePointsAreAValidEscape(d))return consumeIdentLikeToken(p,d);d.advanceCodePoint();const n=[c.Delim,"\\",d.representationStart,d.representationEnd,{value:"\\"}];return p.onParseError(new ParseErrorWithToken(e.InvalidEscapeSequenceAfterBackslash,d.representationStart,d.representationEnd,["4.3.1. Consume a token","U+005C REVERSE SOLIDUS (\\)","The input stream does not start with a valid escape sequence"],n)),n}}return d.advanceCodePoint(),[c.Delim,d.source[d.representationStart],d.representationStart,d.representationEnd,{value:d.source[d.representationStart]}]},endOfFile:function endOfFile(){return void 0===d.source.codePointAt(d.cursor)}}}function noop(){}function mutateIdent(e,n){const t=[];for(const e of n)t.push(e.codePointAt(0));const o=String.fromCodePoint(...serializeIdent(t));e[1]=o,e[4].value=n}function mutateUnit(e,n){const t=[];for(const e of n)t.push(e.codePointAt(0));const o=serializeIdent(t);101===o[0]&&insertEscapedCodePoint(o,0,o[0]);const r=String.fromCodePoint(...o),i="+"===e[4].signCharacter?e[4].signCharacter:"",s=e[4].value.toString();e[1]=`${i}${s}${r}`,e[4].unit=n}function serializeIdent(e){let n;if(0===e[0])e.splice(0,1,s),n=1;else if(e[0]===o&&e[1]===o)n=2;else if(e[0]===o&&e[1])n=2,isIdentStartCodePoint(e[1])||(n+=insertEscapedCodePoint(e,1,e[1]));else{if(e[0]===o&&!e[1])return[92,e[0]];isIdentStartCodePoint(e[0])?n=1:(n=1,n+=insertEscapedCodePoint(e,0,e[0]))}for(let t=n;t 0xffff)); continue; } - string = string + reader.source[reader.cursor]; - reader.advanceCodePoint(); + string = string + String.fromCodePoint(codePoint ?? -1); + reader.advanceCodePoint(1 + +((codePoint ?? -1) > 0xffff)); } } diff --git a/packages/css-tokenizer/src/reader.ts b/packages/css-tokenizer/src/reader.ts index d95b0cbcc2..fd1ce3a9bd 100644 --- a/packages/css-tokenizer/src/reader.ts +++ b/packages/css-tokenizer/src/reader.ts @@ -25,7 +25,7 @@ export class Reader implements CodePointReader { return undefined; } - this.cursor = this.cursor + 1; + this.cursor = this.cursor + 1 + +(codePoint > 0xffff); this.representationEnd = this.cursor - 1; return codePoint; From 5f229acbecf9f0c4f9a3580d2b1bdcb9513054cb Mon Sep 17 00:00:00 2001 From: Romain Menke Date: Thu, 17 Sep 2026 22:18:35 +0200 Subject: [PATCH 2/2] increase test coverage --- packages/css-tokenizer/test/test.mjs | 4 + packages/css-tokenizer/test/token/basic.mjs | 14 ++ packages/css-tokenizer/test/token/cdo.mjs | 33 ++++ .../css-tokenizer/test/token/is-token.mjs | 164 +++++++++++++++++- packages/css-tokenizer/test/token/numeric.mjs | 128 ++++++++++++++ .../test/token/unicode-range.mjs | 14 ++ packages/css-tokenizer/test/token/url.mjs | 62 +++++++ .../css-tokenizer/test/util/clone-tokens.mjs | 30 ++++ .../test/util/mirror-variant.mjs | 35 ++++ .../test/wpt/cdc-vs-ident-tokens.mjs | 15 ++ 10 files changed, 498 insertions(+), 1 deletion(-) create mode 100644 packages/css-tokenizer/test/util/clone-tokens.mjs create mode 100644 packages/css-tokenizer/test/util/mirror-variant.mjs diff --git a/packages/css-tokenizer/test/test.mjs b/packages/css-tokenizer/test/test.mjs index 9c5dafb721..6af3898c86 100644 --- a/packages/css-tokenizer/test/test.mjs +++ b/packages/css-tokenizer/test/test.mjs @@ -34,6 +34,10 @@ import './wpt/decimal-points-in-numbers.mjs'; import './wpt/ident-three-code-points.mjs'; import './wpt/inclusive-ranges.mjs'; +// Util +import './util/clone-tokens.mjs'; +import './util/mirror-variant.mjs'; + // Mutations import './mutations/ident.mjs'; import './mutations/dimension.mjs'; diff --git a/packages/css-tokenizer/test/token/basic.mjs b/packages/css-tokenizer/test/token/basic.mjs index b7c8cbb03d..66b9e675d6 100644 --- a/packages/css-tokenizer/test/token/basic.mjs +++ b/packages/css-tokenizer/test/token/basic.mjs @@ -380,6 +380,20 @@ bar") and (fancy(baz))) {}`, ); } +{ + const t = tokenizer({ + css: '-\\', + }); + + assert.deepEqual( + collectTokens(t), + [ + ['ident-token', '-\\', 0, 1, { value: '-�' }], + ['EOF-token', '', -1, -1, undefined], + ], + ); +} + { const t = tokenizer({ css: `\\0 diff --git a/packages/css-tokenizer/test/token/cdo.mjs b/packages/css-tokenizer/test/token/cdo.mjs index b828a04679..65c3249a2c 100644 --- a/packages/css-tokenizer/test/token/cdo.mjs +++ b/packages/css-tokenizer/test/token/cdo.mjs @@ -48,3 +48,36 @@ import { collectTokens } from '../util/collect-tokens.mjs'; ], ); } + +{ + { + const t = tokenizer({ + css: '', 0, 2, undefined], + [TokenType.CDO]: [TokenType.CDO, '