import { WhiteSpace, Delim, Ident, Function as FunctionToken, Url, BadUrl, AtKeyword, Hash, Percentage, Dimension, Number as NumberToken, String as StringToken, Colon, LeftParenthesis, RightParenthesis, CDC } from '../tokenizer/index.js'; const PLUSSIGN = 0x002B; // U+002B PLUS SIGN (+) const HYPHENMINUS = 0x002D; // U+002D HYPHEN-MINUS (-) const code = (type, value) => { if (type === Delim) { type = value; } if (typeof type === 'string') { const charCode = type.charCodeAt(0); return charCode > 0x7F ? 0x8000 : charCode << 8; } return type; }; // https://www.w3.org/TR/css-syntax-3/#serialization // The only requirement for serialization is that it must "round-trip" with parsing, // that is, parsing the stylesheet must produce the same data structures as parsing, // serializing, and parsing again, except for consecutive s, // which may be collapsed into a single token. const specPairs = [ [Ident, Ident], [Ident, FunctionToken], [Ident, Url], [Ident, BadUrl], [Ident, '-'], [Ident, NumberToken], [Ident, Percentage], [Ident, Dimension], [Ident, CDC], [Ident, LeftParenthesis], [AtKeyword, Ident], [AtKeyword, FunctionToken], [AtKeyword, Url], [AtKeyword, BadUrl], [AtKeyword, '-'], [AtKeyword, NumberToken], [AtKeyword, Percentage], [AtKeyword, Dimension], [AtKeyword, CDC], [Hash, Ident], [Hash, FunctionToken], [Hash, Url], [Hash, BadUrl], [Hash, '-'], [Hash, NumberToken], [Hash, Percentage], [Hash, Dimension], [Hash, CDC], [Dimension, Ident], [Dimension, FunctionToken], [Dimension, Url], [Dimension, BadUrl], [Dimension, '-'], [Dimension, NumberToken], [Dimension, Percentage], [Dimension, Dimension], [Dimension, CDC], ['#', Ident], ['#', FunctionToken], ['#', Url], ['#', BadUrl], ['#', '-'], ['#', NumberToken], ['#', Percentage], ['#', Dimension], ['#', CDC], // https://github.com/w3c/csswg-drafts/pull/6874 ['-', Ident], ['-', FunctionToken], ['-', Url], ['-', BadUrl], ['-', '-'], ['-', NumberToken], ['-', Percentage], ['-', Dimension], ['-', CDC], // https://github.com/w3c/csswg-drafts/pull/6874 [NumberToken, Ident], [NumberToken, FunctionToken], [NumberToken, Url], [NumberToken, BadUrl], [NumberToken, NumberToken], [NumberToken, Percentage], [NumberToken, Dimension], [NumberToken, '%'], [NumberToken, CDC], // https://github.com/w3c/csswg-drafts/pull/6874 ['@', Ident], ['@', FunctionToken], ['@', Url], ['@', BadUrl], ['@', '-'], ['@', CDC], // https://github.com/w3c/csswg-drafts/pull/6874 ['.', NumberToken], ['.', Percentage], ['.', Dimension], ['+', NumberToken], ['+', Percentage], ['+', Dimension], ['/', '*'] ]; // validate with scripts/generate-safe const safePairs = specPairs.concat([ [Ident, Hash], [Dimension, Hash], [Hash, Hash], [AtKeyword, LeftParenthesis], [AtKeyword, StringToken], [AtKeyword, Colon], [Percentage, Percentage], [Percentage, Dimension], [Percentage, FunctionToken], [Percentage, '-'], [RightParenthesis, Ident], [RightParenthesis, FunctionToken], [RightParenthesis, Percentage], [RightParenthesis, Dimension], [RightParenthesis, Hash], [RightParenthesis, '-'] ]); function createMap(pairs) { const isWhiteSpaceRequired = new Set( pairs.map(([prev, next]) => (code(prev) << 16 | code(next))) ); return function(prevCode, type, value) { const nextCode = code(type, value); const nextCharCode = value.charCodeAt(0); const emitWs = (nextCharCode === HYPHENMINUS && type !== Ident && type !== FunctionToken && type !== CDC) || (nextCharCode === PLUSSIGN) ? isWhiteSpaceRequired.has(prevCode << 16 | nextCharCode << 8) : isWhiteSpaceRequired.has(prevCode << 16 | nextCode); if (emitWs) { this.emit(' ', WhiteSpace, true); } return nextCode; }; } export const spec = createMap(specPairs); export const safe = createMap(safePairs);