diff --git a/CHANGELOG.md b/CHANGELOG.md index 96a5bffe..c3a37303 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,14 +1,19 @@ # Changelog +# v0.9.1 + +- [x] minification passes #66 +- [x] nesting selector cannot match pseudo element #67 + # v0.9.0 validation - [x] validate invalid pseudo classes - [x] rewrite selector validation -- [ ] lenient mode that preserves - - [ ] unknown at-rules - - [ ] unknown declarations - - [ ] unknown pseudo classes +- [x] lenient mode that preserves + - [x] unknown at-rules + - [x] unknown declarations + - [x] unknown pseudo classes media query level 5 - [x] at-rule custom-media diff --git a/README.md b/README.md index 44e669c9..a41e463e 100644 --- a/README.md +++ b/README.md @@ -701,7 +701,9 @@ for (const {node, parent, root} of walk(ast)) { ## Minification -- [x] reduce calc() +- [x] evaluate math functions calc(), clamp(), min(), max(), round(), mod(), rem(), sin(), cos(), tan(), asin(), + acos(), atan(), atan2(), pow(), sqrt(), hypot(), log(), exp(), abs(), sign() +- [x] multi-pass minification - [x] inline css variables - [x] merge identical rules - [x] merge adjacent rules @@ -817,7 +819,7 @@ the visitor is called only on 'height' declarations ```typescript import {AstDeclaration, LengthToken, ParserOptions} from "../src/@types"; -import {EnumToken, EnumToken} from "../src/lib"; +import {EnumToken} from "../src/lib"; import {transform} from "../src/node"; const options: ParserOptions = { diff --git a/dist/index-umd-web.js b/dist/index-umd-web.js index c360e728..43276ff7 100644 --- a/dist/index-umd-web.js +++ b/dist/index-umd-web.js @@ -466,22 +466,6 @@ .filter((t) => ![exports.EnumToken.LiteralTokenType, exports.EnumToken.CommentTokenType, exports.EnumToken.CommaTokenType, exports.EnumToken.WhitespaceTokenType].includes(t.typ)); } - function xyzd502srgb(x, y, z) { - // @ts-ignore - return lsrgb2srgbvalues( - /* r: */ - x * 3.1341359569958707 - - y * 1.6173863321612538 - - 0.4906619460083532 * z, - /* g: */ - x * -0.978795502912089 + - y * 1.916254567259524 + - 0.03344273116131949 * z, - /* b: */ - x * 0.07195537988411677 - - y * 0.2289768264158322 + - 1.405386058324125 * z); - } function XYZ_to_lin_sRGB(x, y, z) { // convert XYZ to linear-light sRGB const M = [ @@ -750,6 +734,45 @@ 1.7076147009309444 * S); } + /* + */ + function xyzd502lch(x, y, z, alpha) { + // @ts-ignore + const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + // L in range [0,100]. For use in CSS, add a percent + return lab2lchvalues(l, a, b, alpha); + } + function XYZ_D65_to_D50(x, y, z) { + // Bradford chromatic adaptation from D65 to D50 + // The matrix below is the result of three operations: + // - convert from XYZ to retinal cone domain + // - scale components from one reference white to another + // - convert back to XYZ + // see https://github.com/LeaVerou/color.js/pull/354/files + var M = [ + [1.0479297925449969, 0.022946870601609652, -0.05019226628920524], + [0.02962780877005599, 0.9904344267538799, -0.017073799063418826], + [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371] + ]; + return multiplyMatrices(M, [x, y, z]); + } + function xyzd502srgb(x, y, z) { + // @ts-ignore + return lsrgb2srgbvalues( + /* r: */ + x * 3.1341359569958707 - + y * 1.6173863321612538 - + 0.4906619460083532 * z, + /* g: */ + x * -0.978795502912089 + + y * 1.916254567259524 + + 0.03344273116131949 * z, + /* b: */ + x * 0.07195537988411677 - + y * 0.2289768264158322 + + 1.405386058324125 * z); + } + // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 function hex2lab(token) { @@ -1362,28 +1385,6 @@ return hsv2hwb(...hsl2hsv(h, s, l, a)); } - function xyzd502lch(x, y, z, alpha) { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); - // L in range [0,100]. For use in CSS, add a percent - // @ts-ignore - return lab2lchvalues(l, a, b, alpha); - } - function XYZ_D65_to_D50(x, y, z) { - // Bradford chromatic adaptation from D65 to D50 - // The matrix below is the result of three operations: - // - convert from XYZ to retinal cone domain - // - scale components from one reference white to another - // - convert back to XYZ - // see https://github.com/LeaVerou/color.js/pull/354/files - var M = [ - [1.0479297925449969, 0.022946870601609652, -0.05019226628920524], - [0.02962780877005599, 0.9904344267538799, -0.017073799063418826], - [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371] - ]; - return multiplyMatrices(M, [x, y, z]); - } - function prophotorgb2srgbvalues(r, g, b, a = null) { // @ts-ignore return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); @@ -3250,11 +3251,11 @@ } class SourceMap { + lastLocation = null; #version = 3; #sources = []; #map = new Map; #line = -1; - lastLocation = null; add(source, original) { if (original.src !== '') { if (!this.#sources.includes(original.src)) { @@ -3884,7 +3885,7 @@ case exports.EnumToken.PseudoClassTokenType: case exports.EnumToken.PseudoElementTokenType: // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == exports.EnumToken.PseudoElementTokenType && ['::before', '::after', '::first-line', '::first-letter'].includes(token.val)) { + if (token.typ == exports.EnumToken.PseudoElementTokenType && pseudoElements.includes(token.val.slice(1))) { return token.val.slice(1); } case exports.EnumToken.UrlTokenTokenType: @@ -3965,6 +3966,7 @@ 'aural', 'braille', 'embossed', 'handheld', 'projection', 'tty', 'tv', 'speech']; // https://www.w3.org/TR/css-values-4/#math-function const mathFuncs = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign']; + const pseudoElements = [':before', ':after', ':first-line', ':first-letter']; const webkitPseudoAliasMap = { '-webkit-autofill': 'autofill', '-webkit-any': 'is', @@ -6221,13 +6223,13 @@ shorthand: "background" } }; - var config$4 = { + var config$3 = { properties: properties, map: map }; - Object.freeze(config$4); - const getConfig = () => config$4; + Object.freeze(config$3); + const getConfig = () => config$3; function matchType(val, properties) { if (val.typ == exports.EnumToken.IdenTokenType && properties.keywords.includes(val.val) || @@ -7254,7 +7256,7 @@ syntax: "auto || " }, "backdrop-filter": { - syntax: "none | " + syntax: "none | " }, "backface-visibility": { syntax: "visible | hidden" @@ -7668,7 +7670,7 @@ syntax: "nonzero | evenodd" }, filter: { - syntax: "none | " + syntax: "none | " }, flex: { syntax: "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]" @@ -8124,7 +8126,7 @@ syntax: "" }, outline: { - syntax: "[ <'outline-width'> || <'outline-style'> || <'outline-color'> ]" + syntax: "<'outline-width'> || <'outline-style'> || <'outline-color'>" }, "outline-color": { syntax: "auto | " @@ -8553,7 +8555,7 @@ syntax: "space-all | normal | space-first | trim-start" }, "text-transform": { - syntax: "none | capitalize | uppercase | lowercase | full-width | full-size-kana" + syntax: "none | [ capitalize | uppercase | lowercase ] || full-width || full-size-kana | math-auto" }, "text-underline-offset": { syntax: "auto | | " @@ -8643,7 +8645,7 @@ syntax: "visible | hidden | collapse" }, "white-space": { - syntax: "normal | pre | nowrap | pre-wrap | pre-line | break-spaces | [ <'white-space-collapse'> || <'text-wrap'> ]" + syntax: "normal | pre | pre-wrap | pre-line | <'white-space-collapse'> || <'text-wrap-mode'>" }, "white-space-collapse": { syntax: "collapse | preserve | preserve-breaks | preserve-spaces | break-spaces" @@ -8679,7 +8681,7 @@ syntax: "auto | " }, zoom: { - syntax: "normal | reset | | " + syntax: "normal | reset | || " } }; var functions = { @@ -8720,7 +8722,7 @@ syntax: "calc-size( , )" }, circle: { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, clamp: { syntax: "clamp( #{3} )" @@ -8756,7 +8758,7 @@ syntax: "element( )" }, ellipse: { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, env: { syntax: "env( , ? )" @@ -8771,16 +8773,16 @@ syntax: "grayscale( [ | ]? )" }, hsl: { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hsla: { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hue-rotate": { syntax: "hue-rotate( [ | ]? )" }, hwb: { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hypot: { syntax: "hypot( # )" @@ -8869,6 +8871,9 @@ ray: { syntax: "ray( && ? && contain? && [at ]? )" }, + rect: { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, rem: { syntax: "rem( , )" }, @@ -8882,10 +8887,10 @@ syntax: "repeating-radial-gradient( [ || ]? [ at ]? , )" }, rgb: { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, rgba: { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, rotate: { syntax: "rotate( [ | ] )" @@ -8947,6 +8952,9 @@ sqrt: { syntax: "sqrt( )" }, + symbols: { + syntax: "symbols( ? [ | ]+ )" + }, tan: { syntax: "tan( )" }, @@ -8979,6 +8987,9 @@ }, view: { syntax: "view([ || <'view-timeline-inset'>]?)" + }, + xywh: { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" } }; var syntaxes = { @@ -8994,6 +9005,9 @@ "alpha-value": { syntax: " | " }, + "an+b": { + syntax: "odd | even | | | '+'?† n | -n | | '+'?† | | | '+'?† n | -n | | '+'?† n- | -n- | ['+' | '-'] | '+'?† n ['+' | '-'] | -n ['+' | '-'] " + }, "anchor()": { syntax: "anchor( ? && , ? )" }, @@ -9115,7 +9129,7 @@ syntax: "? && " }, "circle()": { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, "clamp()": { syntax: "clamp( #{3} )" @@ -9129,15 +9143,15 @@ color: { syntax: " | currentColor | | | " }, + "color()": { + syntax: "color( [ from ]? [ / [ | none ] ]? )" + }, "color-base": { syntax: " | | | | transparent" }, "color-function": { syntax: " | | | | | | | | | " }, - "color()": { - syntax: "color( [from ]? [ / [ | none ] ]? )" - }, "color-interpolation-method": { syntax: "in [ | ? | ]" }, @@ -9246,6 +9260,9 @@ dasharray: { syntax: "[ [ | ]+ ]#" }, + "dashndashdigit-ident": { + syntax: "" + }, "deprecated-system-color": { syntax: "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonHighlight | ButtonShadow | CaptionText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, @@ -9286,7 +9303,7 @@ syntax: "element( )" }, "ellipse()": { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, "ending-shape": { syntax: "circle | ellipse" @@ -9327,7 +9344,7 @@ "filter-function": { syntax: " | | | | | | | | | " }, - "filter-function-list": { + "filter-value-list": { syntax: "[ | ]+" }, "final-bg-layer": { @@ -9382,10 +9399,10 @@ syntax: "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hsla()": { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hue: { syntax: " | " @@ -9397,7 +9414,7 @@ syntax: "hue-rotate( [ | ]? )" }, "hwb()": { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hypot()": { syntax: "hypot( # )" @@ -9405,6 +9422,9 @@ "id-selector": { syntax: "" }, + integer: { + syntax: "" + }, image: { syntax: " | | | | | | " }, @@ -9570,6 +9590,18 @@ "mod()": { syntax: "mod( , )" }, + "n-dimension": { + syntax: "" + }, + "ndash-dimension": { + syntax: "" + }, + "ndashdigit-dimension": { + syntax: "" + }, + "ndashdigit-ident": { + syntax: "" + }, "name-repeat": { syntax: "repeat( [ | auto-fill ], + )" }, @@ -9582,9 +9614,6 @@ "ns-prefix": { syntax: "[ | '*' ]? '|'" }, - nth: { - syntax: " | even | odd" - }, "number-percentage": { syntax: " | " }, @@ -9693,9 +9722,15 @@ quote: { syntax: "open-quote | close-quote | no-open-quote | no-close-quote" }, + "radial-extent": { + syntax: "closest-corner | closest-side | farthest-corner | farthest-side" + }, "radial-gradient()": { syntax: "radial-gradient( [ || ]? [ at ]? , )" }, + "radial-size": { + syntax: " | | {2}" + }, ratio: { syntax: " [ / ]?" }, @@ -9717,6 +9752,9 @@ "relative-size": { syntax: "larger | smaller" }, + "rect()": { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, "rem()": { syntax: "rem( , )" }, @@ -9736,10 +9774,10 @@ syntax: "reversed( )" }, "rgb()": { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, "rgba()": { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, "rotate()": { syntax: "rotate( [ | ] )" @@ -9813,15 +9851,18 @@ "shape-box": { syntax: " | margin-box" }, - "shape-radius": { - syntax: " | closest-side | farthest-side" - }, "side-or-corner": { syntax: "[ left | right ] || [ top | bottom ]" }, "sign()": { syntax: "sign( )" }, + "signed-integer": { + syntax: "" + }, + "signless-integer": { + syntax: "" + }, "sin()": { syntax: "sin( )" }, @@ -9894,6 +9935,12 @@ symbol: { syntax: " | | " }, + "symbols()": { + syntax: "symbols( ? [ | ]+ )" + }, + "symbols-type": { + syntax: "cyclic | numeric | alphabetic | symbolic | fixed" + }, "system-color": { syntax: "AccentColor | AccentColorText | ActiveText | ButtonBorder | ButtonFace | ButtonText | Canvas | CanvasText | Field | FieldText | GrayText | Highlight | HighlightText | LinkText | Mark | MarkText | SelectedItem | SelectedItemText | VisitedText" }, @@ -9984,6 +10031,9 @@ "wq-name": { syntax: "? " }, + "xywh()": { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" + }, xyz: { syntax: "xyz | xyz-d50 | xyz-d65" }, @@ -10119,16 +10169,16 @@ syntax: ":not( )" }, ":nth-child()": { - syntax: ":nth-child( [ of ]? )" + syntax: ":nth-child( [ of ]? )" }, ":nth-last-child()": { - syntax: ":nth-last-child( [ of ]? )" + syntax: ":nth-last-child( [ of ]? )" }, ":nth-last-of-type()": { - syntax: ":nth-last-of-type( )" + syntax: ":nth-last-of-type( )" }, ":nth-of-type()": { - syntax: ":nth-of-type( )" + syntax: ":nth-of-type( )" }, ":only-child": { syntax: ":only-child" @@ -10411,7 +10461,7 @@ syntax: "normal | " }, "font-display": { - syntax: "[ auto | block | swap | fallback | optional ]" + syntax: "auto | block | swap | fallback | optional" }, "font-family": { syntax: "" @@ -10532,7 +10582,7 @@ } } }; - var config$3 = { + var config$2 = { declarations: declarations, functions: functions, syntaxes: syntaxes, @@ -10540,7 +10590,6 @@ atRules: atRules }; - const specialValues = ['inherit', 'initial', 'unset', 'revert', 'revert-layer']; var ValidationTokenEnum; (function (ValidationTokenEnum) { ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root"; @@ -11542,100 +11591,6 @@ } return position; } - function renderSyntax(token, parent) { - let glue; - switch (token.typ) { - case ValidationTokenEnum.Root: - return token.chi.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Whitespace: - return ' '; - case ValidationTokenEnum.ValidationFunctionDefinition: - return '<' + token.val + '()>'; - case ValidationTokenEnum.HashMark: - return '#'; - case ValidationTokenEnum.Pipe: - return '|'; - case ValidationTokenEnum.Column: - return '||'; - case ValidationTokenEnum.PipeToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '|' : '') + curr.reduce((acc, curr) => acc + renderSyntax(curr), ''), ''); - case ValidationTokenEnum.ColumnToken: - case ValidationTokenEnum.AmpersandToken: - glue = token.typ == ValidationTokenEnum.ColumnToken ? '||' : '&&'; - return token.l.reduce((acc, curr) => acc + renderSyntax(curr), '') + - glue + - token.r.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Function: - case ValidationTokenEnum.PseudoClassFunctionToken: - case ValidationTokenEnum.Parens: - return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ')' + renderAttributes(token); - case ValidationTokenEnum.Comma: - return ','; - case ValidationTokenEnum.Keyword: - return token.val + renderAttributes(token); - case ValidationTokenEnum.OpenBracket: - return '['; - case ValidationTokenEnum.Ampersand: - return '&&'; - case ValidationTokenEnum.QuestionMark: - return '?'; - case ValidationTokenEnum.Separator: - return '/'; - case ValidationTokenEnum.Bracket: - return '[' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']' + renderAttributes(token); - case ValidationTokenEnum.PropertyType: - return '<' + token.val + '>' + renderAttributes(token); - case ValidationTokenEnum.DeclarationType: - return "<'" + token.val + "'>" + renderAttributes(token); - case ValidationTokenEnum.Number: - case ValidationTokenEnum.PseudoClassToken: - case ValidationTokenEnum.StringToken: - return token.val + ''; - case ValidationTokenEnum.SemiColon: - return ';'; - case ValidationTokenEnum.AtRule: - return '@' + token.val; - case ValidationTokenEnum.AtRuleDefinition: - return '@' + token.val + - (token.prelude == null ? '' : ' ' + token.prelude.reduce((acc, curr) => acc + renderSyntax(curr), '')) + - (token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}'; - case ValidationTokenEnum.Block: - return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}'; - case ValidationTokenEnum.DeclarationDefinitionToken: - return token.nam + ': ' + renderSyntax(token.val); - case ValidationTokenEnum.ColumnArrayToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '||' : '') + renderSyntax(curr), ''); - default: - throw new Error('Unhandled token: ' + JSON.stringify({ token })); - } - } - function renderAttributes(token) { - let result = ''; - if (token.isList) { - result += '#'; - } - if (token.isOptional) { - result += '?'; - } - if (token.isRepeatableGroup) { - result += '!'; - } - if (token.isRepeatable) { - result += '*'; - } - if (token.atLeastOnce) { - result += '+'; - } - if (token.occurence != null) { - if (token.occurence.max == 0 || token.occurence.max == token.occurence.min || Number.isNaN(token.occurence.max)) { - result += '{' + token.occurence.min + '}'; - } - else { - result += '{' + token.occurence.min + ',' + token.occurence.max + '}'; - } - } - return result; - } function minify$1(ast) { if (Array.isArray(ast)) { // @ts-ignore @@ -11737,14 +11692,14 @@ } const parsedSyntaxes = new Map(); - Object.freeze(config$3); + Object.freeze(config$2); function getSyntaxConfig() { // @ts-ignore - return config$3; + return config$2; } function getParsedSyntax(group, key) { // @ts-ignore - let obj = config$3[group]; + let obj = config$2[group]; const keys = Array.isArray(key) ? key : [key]; for (let i = 0; i < keys.length; i++) { key = keys[i]; @@ -11782,7 +11737,7 @@ acc[acc.length - 1].push(curr); } return acc; - }, [[]]).slice(1); + }, [[]]); for (let i = 0; i < slice.length; i++) { if (slice[i].length == 0) { // @ts-ignore @@ -11795,26 +11750,15 @@ tokens }; } - if (slice[i][0].typ != exports.EnumToken.IdenTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: tokens, - node: slice[i][0], - syntax: 'ident', - error: 'expecting ident', - tokens - }; - } - for (let j = 1; j < slice[i].length; j++) { - if (slice[i][j].typ != exports.EnumToken.ClassSelectorTokenType) { + for (let j = 0; j < slice[i].length; j++) { + if (slice[i][j].typ != exports.EnumToken.IdenTokenType && slice[i][j].typ != exports.EnumToken.ClassSelectorTokenType) { // @ts-ignore return { valid: ValidationLevel.Drop, matches: tokens, node: slice[i][j], - syntax: 'layer-name', - error: 'expecting class selector', + syntax: '', + error: 'expecting ident or class selector', tokens }; } @@ -12443,1603 +12387,127 @@ return validateKeyframeSelector(i == j ? tokens.slice(i) : tokens.slice(j, i + 1), atRule); } - const config$2 = getSyntaxConfig(); - function consumeToken(tokens) { - tokens.shift(); - } - function consumeSyntax(syntaxes) { - syntaxes.shift(); + function validateURL(token) { + if (token.typ == exports.EnumToken.UrlTokenTokenType) { + // @ts-ignore + return { + valid: ValidationLevel.Valid, + matches: [], + node: token, + // @ts-ignore + syntax: 'url()', + error: '', + tokens: [] + }; + } + if (token.typ != exports.EnumToken.UrlFunctionTokenType) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: token, + // @ts-ignore + syntax: 'url()', + error: 'expected url()', + tokens: [] + }; + } + const children = token.chi.slice(); + consumeWhitespace(children); + if (children.length == 0 || ![exports.EnumToken.UrlTokenTokenType, exports.EnumToken.StringTokenType, exports.EnumToken.HashTokenType].includes(children[0].typ)) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: children[0] ?? token, + // @ts-ignore + syntax: 'url()', + error: 'expected url-token', + tokens: children + }; + } + children.shift(); + consumeWhitespace(children); + if (children.length > 0) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: children[0] ?? token, + // @ts-ignore + syntax: 'url()', + error: 'unexpected token', + tokens: children + }; + } + // @ts-ignore + return { + valid: ValidationLevel.Valid, + matches: [], + node: token, + // @ts-ignore + syntax: 'url()', + error: '', + tokens: [] + }; } - function splice(tokens, matches) { - if (matches.length == 0) { - return tokens; + + const validateSelectorList = validateComplexSelectorList; + + function validateSelector(selector, options, root) { + if (root == null) { + return validateSelectorList(selector, root, options); } // @ts-ignore - const index = tokens.indexOf(matches.at(-1)); - if (index > -1) { - tokens.splice(0, index + 1); + if (root.typ == exports.EnumToken.AtRuleNodeType && root.nam.match(/^(-[a-z]+-)?keyframes$/)) { + return validateKeyframeBlockList(selector, root); } - return tokens; + let isNested = root.typ == exports.EnumToken.RuleNodeType ? 1 : 0; + let currentRoot = root.parent; + while (currentRoot != null && isNested == 0) { + if (currentRoot.typ == exports.EnumToken.RuleNodeType) { + isNested++; + if (isNested > 0) { + // @ts-ignore + return validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector: true }); + } + } + currentRoot = currentRoot.parent; + } + const nestedSelector = isNested > 0; + // @ts-ignore + return nestedSelector ? validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector }) : validateSelectorList(selector, root, { ...(options ?? {}), nestedSelector }); } - function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) { - console.error(JSON.stringify({ - syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''), - syntaxes, - tokens, - s: new Error('bar').stack - }, null, 1)); - if (syntaxes == null) { + + function validateAtRuleMedia(atRule, options, root) { + // media-query-list + if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) { // @ts-ignore return { - valid: ValidationLevel.Drop, + valid: ValidationLevel.Valid, matches: [], - node: tokens[0] ?? null, + node: null, syntax: null, - error: 'no matching syntaxes found', - tokens + error: '', + tokens: [] }; } - let token = null; - let syntax; let result = null; - let validSyntax = false; - let matched = false; - const matches = []; - tokens = tokens.slice(); - syntaxes = syntaxes.slice(); - tokens = tokens.slice(); - if (context.cache == null) { - context.cache = new WeakMap; + const slice = atRule.tokens.slice(); + consumeWhitespace(slice); + if (slice.length == 0) { + return { + valid: ValidationLevel.Valid, + matches: [], + node: atRule, + syntax: '@media', + error: '', + tokens: [] + }; } - if (context.tokens == null) { - context.tokens = tokens.slice(); - } - context = { ...context }; - main: while (tokens.length > 0) { - if (syntaxes.length == 0) { - break; - } - token = tokens[0]; - syntax = syntaxes[0]; - // @ts-ignore - context.position = context.tokens.indexOf(token); - const cached = context.cache.get(token)?.get(syntax.text) ?? null; - if (cached != null) { - if (cached.error.length > 0) { - return { ...cached, tokens, node: cached.valid == ValidationLevel.Valid ? null : token }; - } - syntaxes.shift(); - tokens.shift(); - continue; - } - if (token.typ == exports.EnumToken.DescendantCombinatorTokenType) { - tokens.shift(); - if (syntax.typ == ValidationTokenEnum.Whitespace) { - syntaxes.shift(); - } - continue; - } - else if (syntax.typ == ValidationTokenEnum.Whitespace) { - syntaxes.shift(); - if (token.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - continue; - } - else if (syntax.typ == ValidationTokenEnum.Block && exports.EnumToken.AtRuleTokenType == token.typ && ('chi' in token)) { - syntaxes.shift(); - tokens.shift(); - // @ts-ignore - matches.push(token); - continue; - } - if (syntax.isOptional) { - if (!context.cache.has(token)) { - context.cache.set(token, new Map); - } - if (context.cache.get(token).has(syntax.text)) { - result = context.cache.get(token).get(syntax.text); - return { ...result, tokens, node: result.valid == ValidationLevel.Valid ? null : token }; - } - // @ts-ignore - const { isOptional, ...c } = syntax; - // @ts-ignore - let result2; - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.valid == ValidationLevel.Valid && result2.matches.length > 0) { - tokens = result2.tokens; - // splice(tokens, result2.matches); - // tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - matched = true; - result = result2; - } - else { - syntaxes.shift(); - continue; - } - syntaxes.shift(); - if (syntaxes.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Valid, - matches: result2.matches, - node: result2.node, - syntax: result2.syntax, - error: result2.error, - tokens - }; - } - continue; - } - if (syntax.isList) { - let index = -1; - // @ts-ignore - let { isList, ...c } = syntax; - // const c: ValidationToken = {...syntaxes, isList: false} as ValidationToken; - let result2 = null; - validSyntax = false; - do { - for (let i = index + 1; i < tokens.length; i++) { - if (tokens[i].typ == exports.EnumToken.CommaTokenType) { - index = i; - break; - } - } - if (tokens[index + 1]?.typ == exports.EnumToken.CommaTokenType) { - return { - valid: ValidationLevel.Drop, - matches, - node: tokens[0], - syntax, - error: 'unexpected token', - tokens - }; - } - if (index == -1) { - index = tokens.length; - } - if (index == 0) { - break; - } - // @ts-ignore - result2 = validateSyntax([c], tokens.slice(0, index), root, options, context); - matched = result2.valid == ValidationLevel.Valid && result2.matches.length > 0; - if (matched) { - const l = tokens.length; - validSyntax = true; - // @ts-ignore - // matches.push(...result2.matches); - // splice(tokens, result2.matches); - if (tokens.length == 1 && tokens[0].typ == exports.EnumToken.CommaTokenType) { - return { - valid: ValidationLevel.Drop, - matches, - node: tokens[0], - syntax, - error: 'unexpected token', - tokens - }; - } - tokens = tokens.slice(index); - result = result2; - // @ts-ignore - matches.push(...result2.matches); - if (result.tokens.length > 0) { - if (index == -1) { - tokens = result.tokens; - } - else { - tokens = tokens.slice(index - result.tokens.length); - } - } - else if (index > 0) { - tokens = tokens.slice(index); - } - index = -1; - if (l == tokens.length) { - break; - } - } - else { - break; - } - } while (tokens.length > 0); - // if (level == 0) { - // } - if (!matched) { - return { - valid: ValidationLevel.Drop, - // @ts-ignore - matches: [...new Set(matches)], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - syntaxes.shift(); - continue; - } - if (syntax.isRepeatable) { - // @ts-ignore - let { isRepeatable, ...c } = syntax; - let result2 = null; - validSyntax = false; - let l = tokens.length; - let tok = null; - do { - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.matches.length == 0 && result2.error.length > 0) { - syntaxes.shift(); - break main; - } - if (result2.valid == ValidationLevel.Valid) { - tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - result = result2; - if (l == tokens.length) { - if (tok == tokens[0]) { - break; - } - if (result2.matches.length == 0 && tokens.length > 0) { - tokens = result2.tokens; - tok = tokens[0]; - continue; - } - break; - } - if (matches.length == 0) { - tokens = result2.tokens; - } - l = tokens.length; - continue; - } - break; - } while (result2.valid == ValidationLevel.Valid && tokens.length > 0); - // if (lastResult != null) { - // - // splice(tokens, lastResult.matches); - // // tokens = lastResult.tokens; - // } - syntaxes.shift(); - continue; - } - // at least one match - if (syntax.isRepeatableGroup) { - validSyntax = false; - let count = 0; - let l = tokens.length; - let result2 = null; - do { - // @ts-ignore - const { isRepeatableGroup, ...c } = syntax; - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.valid == ValidationLevel.Drop || result2.matches.length == 0) { - if (count > 0) { - syntaxes.shift(); - // if (result2.matches.length == 0) { - tokens = result2.tokens; - // break main; - if (syntaxes.length == 0) { - return result2; - } - break main; - } - return result2; - } - if (result2.valid == ValidationLevel.Valid && result2.matches.length > 0) { - count++; - // lastResult = result; - validSyntax = true; - tokens = result2.tokens; - // splice(tokens, result2.matches); - // tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - result = result2; - if (l == tokens.length) { - break; - } - l = tokens.length; - } - else { - break; - } - } while (tokens.length > 0 && result.valid == ValidationLevel.Valid); - // if (lastResult != null) { - // - // splice(tokens, lastResult.matches); - // // tokens = lastResult.tokens; - // } - // at least one match is expected - if (!validSyntax /* || result.matches.length == 0 */) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - node: token, - tokens, - syntax, - error: 'unexpected token', - matches: [] - }; - } - syntaxes.shift(); - continue; - } - if (syntax.atLeastOnce) { - const { atLeastOnce, ...c } = syntax; - result = validateSyntax([c], tokens, root, options, context); - if (result.valid == ValidationLevel.Drop) { - return result; - } - splice(tokens, result.matches); - // tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - let l = tokens.length; - let r = validateSyntax([c], tokens, root, options, context); - while (r.valid == ValidationLevel.Valid) { - splice(tokens, r.matches); - // tokens = r.tokens; - r = validateSyntax([c], tokens, root, options, context); - if (l == tokens.length) { - break; - } - if (r.valid == ValidationLevel.Valid && r.matches.length > 0) { - // @ts-ignore - matches.push(...result.matches); - } - l = tokens.length; - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (syntax.occurence != null) { - // @ts-ignore - const { occurence, ...c } = syntax; - // && syntaxes.occurence.max != null - // consume all tokens - let match = 1; - // @ts-ignore - result = validateSyntax([c], tokens, root, options, context); - if (result.valid == ValidationLevel.Drop) { - return result; - } - if (result.matches.length == 0) { - syntaxes.shift(); - continue; - } - // splice(tokens, result.matches); - // tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - matched = true; - tokens = result.tokens; - while (occurence.max == null || match < occurence.max) { - // trim whitespace - if (tokens[0]?.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - // @ts-ignore - let r = validateSyntax([c], tokens, root, options, context); - if (r.valid != ValidationLevel.Valid || r.matches.length == 0) { - break; - } - result = r; - // splice(tokens, r.matches); - // tokens = r.tokens; - // @ts-ignore - matches.push(...result.matches); - match++; - tokens = r.tokens; - result = r; - if (tokens.length == 0 || (occurence.max != null && match >= occurence.max)) { - break; - } - // @ts-ignore - // r = validateSyntax([c], tokens, root, options, context); - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (syntax.typ == ValidationTokenEnum.Whitespace) { - if (token.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (token.val != null && specialValues.includes(token.val)) { - matched = true; - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - // @ts-ignore - matches.push(...result.matches); - } - else { - result = doValidateSyntax(syntax, token, tokens, root, options, context); - matched = result.valid == ValidationLevel.Valid && result.matches.length > 0; - if (matched) { - // splice(tokens, result.matches); - tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - } - } - if (result.valid == ValidationLevel.Drop) { - // @ts-ignore - return { ...result, matches, tokens, node: result.valid == ValidationLevel.Valid ? null : token }; - } - consumeSyntax(syntaxes); - if (tokens.length == 0) { - return result; - } - } - if (result?.valid == ValidationLevel.Valid) { - // splice(tokens, result.matches); - tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - } - if ( /* result == null && */tokens.length == 0 && syntaxes.length > 0) { - validSyntax = isOptionalSyntax(syntaxes); - } - if (result == null) { - result = { - valid: validSyntax ? ValidationLevel.Valid : ValidationLevel.Drop, - matches, - node: validSyntax ? null : tokens[0] ?? null, - // @ts-ignore - syntax, - error: validSyntax ? '' : 'unexpected token', - tokens - }; - } - if (token != null) { - if (!context.cache.has(token)) { - context.cache.set(token, new Map); - } - context.cache.get(token).set(syntax.text, result); - } - if (result != null) { - // @ts-ignore - return { ...result, matches: [...(new Set(matches))] }; - } - return result; - } - function isOptionalSyntax(syntaxes) { - return syntaxes.length > 0 && syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val) ?? []))); - } - function doValidateSyntax(syntax, token, tokens, root, options, context) { - let valid = false; - let result; - let children; - let queue; - let matches; - let child; - let astNodes = new Set; - if (token.typ == exports.EnumToken.NestingSelectorTokenType && syntax.typ == 2) { - valid = root != null && 'relative-selector' == syntax.val; - return { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - switch (syntax.typ) { - case ValidationTokenEnum.Comma: - valid = token.typ === exports.EnumToken.CommaTokenType; - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.AtRule: - if (token.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule', - tokens - }; - } - if (token.nam != syntax.val) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: `expecting '@${syntax.val}' but found '@${token.nam}'`, - tokens - }; - } - if (root == null) { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - if (root.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'not allowed here', - tokens - }; - } - if (!('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '@at-rule must have children', - tokens - }; - } - // @ts-ignore - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - break; - case ValidationTokenEnum.AtRuleDefinition: - if (token.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule', - tokens - }; - } - if ('chi' in syntax && !('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '@at-rule must have children', - tokens - }; - } - if ('chi' in token && !('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'children not allowed here', - tokens - }; - } - const s = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + token.nam); - if ('prelude' in syntax) { - if (!('tokens' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expected at-rule prelude', - tokens - }; - } - result = validateSyntax(s[0].prelude, token.tokens, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - if (result.valid == ValidationLevel.Drop) { - return result; - } - } - const hasBody = 'chi' in s[0]; - if ('chi' in token) { - if (!hasBody) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected at-rule body', - tokens - }; - } - } - else if (hasBody) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule body', - tokens - }; - } - break; - case ValidationTokenEnum.DeclarationType: - // @ts-ignore - result = validateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, syntax.val), [token], root, options, context); - break; - case ValidationTokenEnum.Keyword: - valid = (token.typ == exports.EnumToken.IdenTokenType && token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0) || - (token.typ == exports.EnumToken.ColorTokenType && token.kin == 'lit' && syntax.val.localeCompare(token.val, 'en', { sensitivity: 'base' }) == 0); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.SemiColon: - valid = root == null || [exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType, exports.EnumToken.StyleSheetNodeType].includes(root.typ); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.Separator: - valid = token.typ == exports.EnumToken.LiteralTokenType && token.val != '/'; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.PropertyType: - // - if ('image' == syntax.val) { - valid = token.typ == exports.EnumToken.UrlFunctionTokenType || token.typ == exports.EnumToken.ImageFunctionTokenType; - if (!valid) { - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected ', - tokens - }; - } - result = validateImage(token); - } - else if (['media-feature', 'mf-plain'].includes(syntax.val)) { - valid = token.typ == exports.EnumToken.DeclarationNodeType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (syntax.val == 'pseudo-page') { - valid = token.typ == exports.EnumToken.PseudoClassTokenType && [':left', ':right', ':first', ':blank'].includes(token.val); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (syntax.val == 'page-body') { - if (token.typ == exports.EnumToken.DeclarationNodeType) { - valid = true; - // @ts-ignore - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - while (tokens.length > 0 && [exports.EnumToken.DeclarationNodeType].includes(tokens[0].typ)) { - // @ts-ignore - result.matches.push(tokens.shift()); - } - } - else if (token.typ == exports.EnumToken.AtRuleNodeType) { - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'page-margin-box-type'), [token], root, options, context); - } - } - else if (syntax.val == 'group-rule-body') { - valid = [exports.EnumToken.AtRuleNodeType, exports.EnumToken.RuleNodeType].includes(token.typ); - if (!valid && token.typ == exports.EnumToken.DeclarationNodeType && root?.typ == exports.EnumToken.AtRuleNodeType && root.nam == 'media') { - // allowed only if nested rule - let parent = root; - while (parent != null) { - if (parent.typ == exports.EnumToken.RuleNodeType) { - valid = true; - break; - } - // @ts-ignore - parent = parent.parent; - } - } - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'token is not allowed as a child', - tokens - }; - if (!valid) { - return result; - } - } - // - else if ('type-selector' == syntax.val) { - valid = (token.typ == exports.EnumToken.UniversalSelectorTokenType) || - token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || - (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('wq-name' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (exports.EnumToken.UniversalSelectorTokenType == token.typ && 'subclass-selector' == syntax.val) { - valid = true; - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else if ('attribute-selector' == syntax.val) { - valid = token.typ == exports.EnumToken.AttrTokenType && token.chi.length > 0; - if (valid) { - const children = token.chi.filter(t => t.typ != exports.EnumToken.WhitespaceTokenType && t.typ != exports.EnumToken.CommaTokenType); - valid = children.length == 1 && [ - exports.EnumToken.IdenTokenType, - exports.EnumToken.NameSpaceAttributeTokenType, - exports.EnumToken.MatchExpressionTokenType - ].includes(children[0].typ); - if (valid && children[0].typ == exports.EnumToken.MatchExpressionTokenType) { - const t = children[0]; - valid = [ - exports.EnumToken.IdenTokenType, - exports.EnumToken.NameSpaceAttributeTokenType - ].includes(t.l.typ) && - (t.op == null || ([ - exports.EnumToken.DelimTokenType, exports.EnumToken.DashMatchTokenType, - exports.EnumToken.StartMatchTokenType, exports.EnumToken.ContainMatchTokenType, - exports.EnumToken.EndMatchTokenType, exports.EnumToken.IncludeMatchTokenType - ].includes(t.op.typ) && - t.r != null && - [ - exports.EnumToken.StringTokenType, - exports.EnumToken.IdenTokenType - ].includes(t.r.typ))); - if (valid && t.attr != null) { - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'attr-modifier')[0]; - valid = s.chi.some((l) => l.some((r) => r.val == t.attr)); - } - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - if (!valid) { - return result; - } - } - else if ('combinator' == syntax.val) { - valid = [ - exports.EnumToken.DescendantCombinatorTokenType, - exports.EnumToken.SubsequentSiblingCombinatorTokenType, - exports.EnumToken.NextSiblingCombinatorTokenType, - exports.EnumToken.ChildCombinatorTokenType, - exports.EnumToken.ColumnCombinatorTokenType - ].includes(token.typ); - if (valid) { - // @ts-ignore - const position = context.tokens.indexOf(token); - if (root == null) { - valid = position > 0 && context.tokens[position - 1]?.typ != exports.EnumToken.CommaTokenType; - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - if (!valid) { - return result; - } - } - else if ('ident-token' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('hex-color' == syntax.val) { - valid = token.typ == exports.EnumToken.ColorTokenType && token.kin == 'hex'; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('resolution' == syntax.val) { - valid = token.typ == exports.EnumToken.ResolutionTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('angle' == syntax.val) { - valid = token.typ == exports.EnumToken.AngleTokenType || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('time' == syntax.val) { - valid = token.typ == exports.EnumToken.TimingFunctionTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('ident' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (['id-selector', 'hash-token'].includes(syntax.val)) { - valid = token.typ == exports.EnumToken.HashTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (['integer', 'number'].includes(syntax.val)) { - // valid = token.typ == EnumToken.NumberTokenType; - valid = token.typ == exports.EnumToken.NumberTokenType && ('integer' != syntax.val || Number.isInteger(+token.val)); - if (valid && 'range' in syntax) { - const value = Number(token.val); - const range = syntax.range; - valid = value >= range[0] && (range[1] == null || value <= range[1]); - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('length' == syntax.val) { - valid = isLength(token) || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('percentage' == syntax.val) { - valid = token.typ == exports.EnumToken.PercentageTokenType || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('dashed-ident' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('custom-ident' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType || token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('custom-property-name' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('string' == syntax.val) { - valid = token.typ == exports.EnumToken.StringTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('declaration-value' == syntax.val) { - valid = token.typ != exports.EnumToken.LiteralTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('url' == syntax.val) { - valid = token.typ == exports.EnumToken.UrlFunctionTokenType || token.typ == exports.EnumToken.StringTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('declaration' == syntax.val) { - valid = token.typ == exports.EnumToken.DeclarationNodeType && (token.nam.startsWith(('--')) || token.nam in config$2.declarations || token.nam in config$2.syntaxes); - if (!valid) { - // @ts-ignore - result = { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - else if (token.nam.startsWith(('--'))) { - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else { - result = validateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, token.nam) ?? getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, token.nam), token.val, token, options, { - ...context, - tokens: null, - level: 0 - }); - if (result.valid == ValidationLevel.Valid && result.error.length == 0) { - tokens = result.tokens; - } - } - } - else if ('class-selector' == syntax.val) { - valid = exports.EnumToken.ClassSelectorTokenType == token.typ || exports.EnumToken.UniversalSelectorTokenType == token.typ; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - // else if ('complex-selector' == (syntaxes as ValidationPropertyToken).val) { - // - // result = validateSyntax(getParsedSyntax(ValidationSyntaxGroupEnum.Syntaxes, (syntaxes as ValidationPropertyToken).val) as ValidationToken[], tokens, root as AstNode, options, context); - // - // } - else if (['pseudo-element-selector', 'pseudo-class-selector'].includes(syntax.val)) { - valid = false; - if (token.typ == exports.EnumToken.PseudoClassTokenType) { - let val = token.val; - if (val == ':before' || val == ':after') { - val = ':' + val; - } - valid = val in config$2.selectors; - if (!valid && val.match(/^:?:-/) != null) { - const match = token.val.match(/^(:?:)(-[^-]+-)(.*)$/); - if (match != null) { - valid = true; - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'invalid pseudo class', - tokens - }; - } - else if (token.typ == exports.EnumToken.PseudoClassFuncTokenType) { - let key = token.val in config$2.selectors ? token.val : token.val + '()'; - valid = key in config$2.selectors; - if (!valid && token.val.match(/^:?:-/)) { - const match = token.val.match(/^(:?:)(-[^-]+-)(.*)$/); - if (match != null) { - key = match[1] + match[3] in config$2.selectors ? match[1] + match[3] : match[1] + match[3] + '()'; - valid = key in config$2.selectors; - } - } - const s = getParsedSyntax("selectors" /* ValidationSyntaxGroupEnum.Selectors */, key); - if (s != null) { - const r = s[0]; - if (r.typ != ValidationTokenEnum.PseudoClassFunctionToken) { - valid = false; - } - else { - result = validateSyntax(s[0].chi, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - break; - } - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - // - // - else if ('relative-selector' == syntax.val) { - if (tokens.length == 1 && token.typ == exports.EnumToken.NestingSelectorTokenType) { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: token, - syntax, - error: '', - tokens - }; - } - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val), token.typ == exports.EnumToken.NestingSelectorTokenType ? tokens.slice(1) : tokens, root, options, context); - } - // - // - else if (['forgiving-selector-list', 'forgiving-relative-selector-list'].includes(syntax.val)) { - // @ts-ignore - result = { tokens: tokens.slice(), ...validateSelector(tokens, options, root) }; - } - // https://github.com/mdn/data/pull/186#issuecomment-369604537 - else if (syntax.val.endsWith('-token')) { - const val = syntax.val; - valid = true; - switch (val) { - case 'function-token': - valid = token.typ != exports.EnumToken.ParensTokenType && funcLike.includes(token.typ); - break; - case 'ident-token': - valid = token.typ == exports.EnumToken.DashedIdenTokenType || token.typ == exports.EnumToken.IdenTokenType; - break; - case 'hash-token': - valid = token.typ == exports.EnumToken.HashTokenType; - break; - case 'string-token': - valid = token.typ == exports.EnumToken.StringTokenType; - break; - default: - console.error(new Error(`unhandled syntax: '<${val}>'`)); - break; - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('wq-name' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else { - const val = syntax.val; - // https://github.com/mdn/data/pull/186#issuecomment-369604537 - if (val == 'any-value') { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else if (val in config$2.declarations || val in config$2.syntaxes) { - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, val), tokens, root, options, context); - } - else { - // @ts-ignore - result = { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - } - break; - case ValidationTokenEnum.Parens: - case ValidationTokenEnum.Function: - if (syntax.typ == ValidationTokenEnum.Parens) { - valid = token.typ == exports.EnumToken.ParensTokenType; - } - else { - valid = 'chi' in token && 'val' in token && - token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0; - } - result = !valid ? - // @ts-ignore - { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - } : validateSyntax(syntax.chi, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - break; - case ValidationTokenEnum.ValidationFunctionDefinition: - valid = 'val' in token && 'chi' in token; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: '', - tokens - }; - if (result.valid == ValidationLevel.Valid) { - valid = token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - error: '', - syntax, - tokens - }; - if (result.valid == ValidationLevel.Valid) { - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val + '()'); // config[ValidationSyntaxGroupEnum.Syntaxes][(syntaxes as ValidationFunctionDefinitionToken).val + '()'] as ValidationSyntaxNode; - result = validateSyntax(s, tokens, root, options, context); - } - } - break; - case ValidationTokenEnum.Bracket: - result = validateSyntax(syntax.chi, tokens, root, options, context); - break; - case ValidationTokenEnum.PipeToken: - for (const lines of syntax.chi) { - result = validateSyntax(lines, tokens, root, options, context); - if (result.valid == ValidationLevel.Valid) { - break; - } - } - break; - case ValidationTokenEnum.AmpersandToken: - children = [...syntax.l.slice(), ...syntax.r.slice()]; - matches = []; - queue = []; - let m = []; - for (let j = 0; j < children.length; j++) { - const res = validateSyntax([children[j]], tokens, root, options, context); - // @ts-ignore - if (res.valid == ValidationLevel.Valid) { - m.push(...res.matches); - matches.push(...children.splice(j, 1)); - j = 0; - // @ts-ignore - astNodes.delete(token); - consumeToken(tokens); - token = tokens[0]; - if (token == null) { - break; - } - // @ts-ignore - astNodes.add(token); - } - } - if (astNodes.size > 0) { - // @ts-ignore - tokens.unshift(...astNodes); - astNodes = new Set(); - } - valid = matches.length > 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: m, - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - break; - case ValidationTokenEnum.ColumnToken: - children = [...syntax.l.slice(), ...syntax.r.slice()]; - matches = []; - queue = []; - while ((child = children.shift())) { - const res = validateSyntax([child], tokens, root, options, context); - if (res.valid == ValidationLevel.Valid) { - matches.push(child); - consumeToken(tokens); - token = tokens[0]; - if (queue.length > 0) { - children.unshift(...queue); - queue = []; - } - if (token == null) { - break; - } - } - else { - queue.push(child); - } - } - valid = matches.length > 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - break; - case ValidationTokenEnum.StringToken: - valid = token.typ == exports.EnumToken.StringTokenType && syntax.val.slice(1, -1) == token.val.slice(1, -1); - return { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - case ValidationTokenEnum.PseudoClassFunctionToken: - valid = token.typ == exports.EnumToken.PseudoClassFuncTokenType; - if (valid) { - let key = token.val in config$2.selectors ? token.val : token.val + '()'; - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, key); - valid = s != null && validateSyntax(s, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }).valid == ValidationLevel.Valid; - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'invalid token', - tokens - }; - break; - case ValidationTokenEnum.DeclarationDefinitionToken: - if (token.typ != exports.EnumToken.DeclarationNodeType || token.nam != syntax.nam) { - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '', - tokens - }; - } - return validateSyntax([syntax.val], token.val, root, options, context); - default: - throw new Error('not implemented: ' + JSON.stringify({ syntax, token, tokens }, null, 1)); - } - // @ts-ignore - return result; - } - - function validateURL(token) { - if (token.typ == exports.EnumToken.UrlTokenTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Valid, - matches: [], - node: token, - // @ts-ignore - syntax: 'url()', - error: '', - tokens: [] - }; - } - if (token.typ != exports.EnumToken.UrlFunctionTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - // @ts-ignore - syntax: 'url()', - error: 'expected url()', - tokens: [] - }; - } - const children = token.chi.slice(); - consumeWhitespace(children); - if (children.length == 0 || ![exports.EnumToken.UrlTokenTokenType, exports.EnumToken.StringTokenType, exports.EnumToken.HashTokenType].includes(children[0].typ)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0] ?? token, - // @ts-ignore - syntax: 'url()', - error: 'expected url-token', - tokens: children - }; - } - children.shift(); - consumeWhitespace(children); - if (children.length > 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0] ?? token, - // @ts-ignore - syntax: 'url()', - error: 'unexpected token', - tokens: children - }; - } - // @ts-ignore - return { - valid: ValidationLevel.Valid, - matches: [], - node: token, - // @ts-ignore - syntax: 'url()', - error: '', - tokens: [] - }; - } - - function validateImage(token) { - if (token.typ == exports.EnumToken.UrlFunctionTokenType) { - return validateURL(token); - } - if (token.typ == exports.EnumToken.ImageFunctionTokenType) { - return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, token.val + '()'), token.chi); - } - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax: 'image()', - error: 'expected or ', - tokens: [] - }; - } - - const validateSelectorList = validateComplexSelectorList; - - function validateSelector(selector, options, root) { - if (root == null) { - return validateSelectorList(selector, root, options); - } - // @ts-ignore - if (root.typ == exports.EnumToken.AtRuleNodeType && root.nam.match(/^(-[a-z]+-)?keyframes$/)) { - return validateKeyframeBlockList(selector, root); - } - let isNested = root.typ == exports.EnumToken.RuleNodeType ? 1 : 0; - let currentRoot = root.parent; - while (currentRoot != null && isNested == 0) { - if (currentRoot.typ == exports.EnumToken.RuleNodeType) { - isNested++; - if (isNested > 0) { - // @ts-ignore - return validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector: true }); - } - } - currentRoot = currentRoot.parent; - } - const nestedSelector = isNested > 0; - // @ts-ignore - return nestedSelector ? validateRelativeSelectorList(selector, root, { ...(options ?? {}), nestedSelector }) : validateSelectorList(selector, root, { ...(options ?? {}), nestedSelector }); - } - - function validateAtRuleMedia(atRule, options, root) { - // media-query-list - if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Valid, - matches: [], - node: null, - syntax: null, - error: '', - tokens: [] - }; - } - let result = null; - const slice = atRule.tokens.slice(); - consumeWhitespace(slice); - if (slice.length == 0) { - return { - valid: ValidationLevel.Valid, - matches: [], - node: atRule, - syntax: '@media', - error: '', - tokens: [] - }; - } - result = validateAtRuleMediaQueryList(atRule.tokens, atRule); - if (result.valid == ValidationLevel.Drop) { - return result; + result = validateAtRuleMediaQueryList(atRule.tokens, atRule); + if (result.valid == ValidationLevel.Drop) { + return result; } if (!('chi' in atRule)) { // @ts-ignore @@ -14228,7 +12696,7 @@ if (token.typ == exports.EnumToken.MediaFeatureNotTokenType) { return validateMediaCondition(token.val, atRule); } - if (token.typ != exports.EnumToken.ParensTokenType && !(['when', 'else'].includes(atRule.nam) && token.typ == exports.EnumToken.FunctionTokenType && ['media', 'supports'].includes(token.val))) { + if (token.typ != exports.EnumToken.ParensTokenType && !(['when', 'else', 'import'].includes(atRule.nam) && token.typ == exports.EnumToken.FunctionTokenType && ['media', 'supports', 'selector'].includes(token.val))) { return false; } const chi = token.chi.filter((t) => t.typ != exports.EnumToken.CommentTokenType && t.typ != exports.EnumToken.WhitespaceTokenType); @@ -14244,6 +12712,7 @@ if (chi[0].typ == exports.EnumToken.MediaQueryConditionTokenType) { return chi[0].l.typ == exports.EnumToken.IdenTokenType; } + console.error(chi[0].parent); return false; } function validateMediaFeature(token) { @@ -14490,6 +12959,7 @@ }; } function validateAtRuleSupportsConditions(atRule, tokenList) { + let result = null; for (const tokens of splitTokenList(tokenList)) { if (tokens.length == 0) { // @ts-ignore @@ -14503,22 +12973,46 @@ }; } let previousToken = null; - let result = null; while (tokens.length > 0) { result = validateSupportCondition(atRule, tokens[0]); // supports-condition - if (result == null || result.valid == ValidationLevel.Valid) { + if (result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { result = validateSupportFeature(tokens[0]); - if (result == null || result.valid == ValidationLevel.Valid) { + if ( /*result == null || */result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { - return result; + if (tokens[0].typ == exports.EnumToken.ParensTokenType) { + result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if ( /* result == null || */result.valid == ValidationLevel.Valid) { + previousToken = tokens[0]; + tokens.shift(); + // continue; + } + else { + return result; + } + } + else { + return result; + } + // if (result!= null && result.valid == ValidationLevel.Drop) { + // + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0] ?? atRule, + // syntax: '@' + atRule.nam, + // // @ts-ignore + // error: result.error as string ?? 'unexpected token', + // tokens: [] + // }; + // } } } if (tokens.length == 0) { @@ -14573,7 +13067,14 @@ } } } - return null; + return { + valid: ValidationLevel.Valid, + matches: [], + node: atRule, + syntax: '@' + atRule.nam, + error: '', + tokens: [] + }; } function validateSupportCondition(atRule, token) { if (token.typ == exports.EnumToken.MediaFeatureNotTokenType) { @@ -14640,7 +13141,7 @@ function validateSupportFeature(token) { if (token.typ == exports.EnumToken.FunctionTokenType) { if (token.val.localeCompare('selector', undefined, { sensitivity: 'base' }) == 0) { - return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'complex-selector'), token.chi); + return validateComplexSelector(parseSelector(token.chi)); } if (token.val.localeCompare('font-tech', undefined, { sensitivity: 'base' }) == 0) { const chi = token.chi.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(t.typ)); @@ -14764,6 +13265,9 @@ }; } } + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); } else { // @ts-ignore @@ -14799,71 +13303,70 @@ // @ts-ignore else if (tokens[0].typ == exports.EnumToken.FunctionTokenType) { // @ts-ignore - if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) != 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting layer()', - tokens - }; - } - // @ts-ignore - const result = validateLayerName(tokens[0].chi); - if (result.valid == ValidationLevel.Drop) { - return result; - } - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; - } - } - } - if (tokens.length > 0) { - // @ts-ignore - if (tokens[0].typ == exports.EnumToken.AtRuleTokenType) { - if (tokens[0].nam != 'supports') { + if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateLayerName(tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting @supports or media query list', - tokens - }; + consumeWhitespace(tokens); } // @ts-ignore - const result = validateAtRuleSupports(tokens[0]); - if (result.valid == ValidationLevel.Drop) { - return result; - } - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { + if ('supports'.localeCompare(tokens[0]?.val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; + consumeWhitespace(tokens); } } } + // if (tokens.length > 0) { + // + // // @ts-ignore + // if (tokens[0].typ == EnumToken.AtRuleTokenType) { + // + // if ((tokens[0] as AstAtRule).nam != 'supports') { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting @supports or media query list', + // tokens + // } + // } + // + // // @ts-ignore + // const result: ValidationSyntaxResult = validateAtRuleSupports(tokens[0] as AstAtRule, options, atRule); + // + // if (result.valid == ValidationLevel.Drop) { + // + // return result; + // } + // + // tokens.shift(); + // + // // @ts-ignore + // if (!consumeWhitespace(tokens)) { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting whitespace', + // tokens + // } + // } + // } + // } if (tokens.length > 0) { return validateAtRuleMediaQueryList(tokens, atRule); } @@ -15032,71 +13535,50 @@ tokens }; } - if (tokens[0].typ == exports.EnumToken.CommaTokenType) { + for (const t of splitTokenList(tokens)) { + if (t.length != 1) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'unexpected token', + tokens + }; + } // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - while (tokens.length > 0) { - if (tokens[0].typ == exports.EnumToken.CommentTokenType) { - tokens.shift(); - consumeWhitespace(tokens); + if ((t[0].typ != exports.EnumToken.FunctionTokenType && t[0].typ != exports.EnumToken.UrlFunctionTokenType) || !['url', 'url-prefix', 'domain', 'media-document', 'regexp'].some((f) => f.localeCompare(t[0].val, undefined, { sensitivity: 'base' }) == 0)) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'expecting any of url-prefix(), domain(), media-document(), regexp() but found ' + t[0].val, + tokens + }; } - result = validateURL(tokens[0]); - if (result.valid == ValidationLevel.Valid) { - tokens.shift(); - consumeWhitespace(tokens); + if (t[0].typ == exports.EnumToken.UrlFunctionTokenType) { + result = validateURL(t[0]); + if (result.valid == ValidationLevel.Drop) { + return result; + } continue; } - if (tokens[0].typ == exports.EnumToken.FunctionTokenType) { - if (!['url-prefix', 'domain', 'media-document', 'regexp'].some((t) => t.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - const children = tokens[0].chi.slice(); - consumeWhitespace(children); - if (children.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'expecting string argument', - tokens - }; - } - if (children[0].typ == exports.EnumToken.StringTokenType) { - children.shift(); - consumeWhitespace(children); - } - if (children.length > 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - tokens.shift(); - consumeWhitespace(tokens); + const children = t[0].chi.slice(); + consumeWhitespace(children); + if (children.length != 1 || (children[0].typ != exports.EnumToken.StringTokenType && children[0].typ != exports.EnumToken.UrlTokenTokenType)) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@document', + error: 'expecting string argument', + tokens + }; } + tokens.shift(); + consumeWhitespace(tokens); } // @ts-ignore return { @@ -16032,7 +14514,7 @@ await parseNode(tokens, context, stats, options, errors, src, map, rawTokens); rawTokens.length = 0; if (context != null && context.typ == exports.EnumToken.InvalidRuleTokenType) { - const index = context.chi.findIndex(node => node == context); + const index = context.chi.findIndex((node) => node == context); if (index > -1) { context.chi.splice(index, 1); } @@ -16196,8 +14678,13 @@ continue; } if (type != exports.EnumToken.AtRuleNodeType) { - errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); - return null; + // @ts-ignore + if (!(type == exports.EnumToken.InvalidAtRuleTokenType && + // @ts-ignore + ['charset', 'layer', 'import'].includes(context.chi[i].nam))) { + errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); + return null; + } } // @ts-ignore const name = context.chi[i].nam; @@ -16232,12 +14719,20 @@ if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType) { if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType || tokens[1].typ == exports.EnumToken.StringTokenType) { tokens.shift(); - if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType) { + if (tokens[0]?.typ == exports.EnumToken.UrlTokenTokenType) { // @ts-ignore tokens[0].typ = exports.EnumToken.StringTokenType; // @ts-ignore tokens[0].val = `"${tokens[0].val}"`; } + // @ts-ignore + while (tokens[1]?.typ == exports.EnumToken.WhitespaceTokenType || tokens[1]?.typ == exports.EnumToken.CommentTokenType) { + tokens.splice(1, 1); + } + // @ts-ignore + if (tokens[1]?.typ == exports.EnumToken.EndParensTokenType) { + tokens.splice(1, 1); + } } } // @ts-ignore @@ -16551,7 +15046,7 @@ // // const valid: ValidationResult = validateDeclaration(result, options, context); // - // console.error({valid}); + // // console.error({valid}); // // if (valid.valid == ValidationLevel.Drop) { // @@ -16925,7 +15420,7 @@ } : ( // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - val.startsWith('::') || [':before', ':after', ':first-line', ':first-letter'].includes(val) ? { + val.startsWith('::') || pseudoElements.includes(val) ? { typ: exports.EnumToken.PseudoElementTokenType, val } : @@ -17109,25 +15604,25 @@ break; } } - Object.assign(t, { + const attr = Object.assign(t, { typ: inAttr == 0 ? exports.EnumToken.AttrTokenType : exports.EnumToken.InvalidAttrTokenType, chi: tokens.splice(i + 1, k - i) }); // @ts-ignore - if (t.chi.at(-1).typ == exports.EnumToken.AttrEndTokenType) { + if (attr.chi.at(-1).typ == exports.EnumToken.AttrEndTokenType) { // @ts-ignore - t.chi.pop(); + attr.chi.pop(); } // @ts-ignore - if (t.chi.length > 1) { + if (attr.chi.length > 1) { /*(t).chi =*/ // @ts-ignore - parseTokens(t.chi, t.typ); + parseTokens(attr.chi, t.typ); } - let m = t.chi.length; + let m = attr.chi.length; let val; - for (m = 0; m < t.chi.length; m++) { - val = t.chi[m]; + for (m = 0; m < attr.chi.length; m++) { + val = attr.chi[m]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -17137,55 +15632,55 @@ else if (val.typ == exports.EnumToken.LiteralTokenType && val.val == '|') { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == exports.EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == exports.EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == exports.EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == exports.EnumToken.CommentTokenType) { continue; } break; } // @ts-ignore - t.chi[m] = { + attr.chi[m] = { typ: exports.EnumToken.NameSpaceAttributeTokenType, - l: t.chi[lower], - r: t.chi[upper] + l: attr.chi[lower], + r: attr.chi[upper] }; - t.chi.splice(upper, 1); + attr.chi.splice(upper, 1); if (lower >= 0) { - t.chi.splice(lower, 1); + attr.chi.splice(lower, 1); m--; } } else if ([ exports.EnumToken.DashMatchTokenType, exports.EnumToken.StartMatchTokenType, exports.EnumToken.ContainMatchTokenType, exports.EnumToken.EndMatchTokenType, exports.EnumToken.IncludeMatchTokenType, exports.EnumToken.DelimTokenType - ].includes(t.chi[m].typ)) { + ].includes(attr.chi[m].typ)) { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == exports.EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == exports.EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == exports.EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == exports.EnumToken.CommentTokenType) { continue; } break; } - val = t.chi[lower]; + val = attr.chi[lower]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { Object.assign(val, { typ: exports.EnumToken.IdenTokenType, val: slice }); } } - val = t.chi[upper]; + val = attr.chi[upper]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -17305,7 +15800,9 @@ t.typ = exports.EnumToken.ColorTokenType; // @ts-ignore t.kin = t.val; + // @ts-ignore if (t.chi[0].typ == exports.EnumToken.IdenTokenType) { + // @ts-ignore if (t.chi[0].val == 'from') { // @ts-ignore t.cal = 'rel'; @@ -17315,10 +15812,11 @@ // @ts-ignore t.cal = 'mix'; } - else if (t.val == 'color') { - // @ts-ignore - t.cal = 'col'; - // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ)); + else { // @ts-ignore + if (t.val == 'color') { + // @ts-ignore + t.cal = 'col'; + } } } const filter = [exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType]; @@ -17352,7 +15850,7 @@ if (t.chi.length > 0) { if (t.typ == exports.EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) { // - const count = t.chi.filter(t => t.typ != exports.EnumToken.CommentTokenType).length; + const count = t.chi.filter((t) => t.typ != exports.EnumToken.CommentTokenType).length; if (count == 1 || (i == 0 && (tokens[i + 1]?.typ == exports.EnumToken.CommaTokenType || tokens.length == i + 1)) || @@ -17627,7 +16125,7 @@ } else { // selRule = splitRule(selRule.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.join(''), '')); - const arSelf = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); + const arSelf = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); if (arSelf.length == 0) { ast.chi.splice(i--, 1); continue; @@ -17646,7 +16144,7 @@ let withoutCompound = []; // pseudo elements cannot be used with '&' // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))); + const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))); const parentSelector = !node.sel.includes('&'); if (rules.length == 0) { ast.chi.splice(i--, 1); diff --git a/dist/index.cjs b/dist/index.cjs index cd9f3701..cb4229d0 100644 --- a/dist/index.cjs +++ b/dist/index.cjs @@ -465,22 +465,6 @@ function getComponents(token) { .filter((t) => ![exports.EnumToken.LiteralTokenType, exports.EnumToken.CommentTokenType, exports.EnumToken.CommaTokenType, exports.EnumToken.WhitespaceTokenType].includes(t.typ)); } -function xyzd502srgb(x, y, z) { - // @ts-ignore - return lsrgb2srgbvalues( - /* r: */ - x * 3.1341359569958707 - - y * 1.6173863321612538 - - 0.4906619460083532 * z, - /* g: */ - x * -0.978795502912089 + - y * 1.916254567259524 + - 0.03344273116131949 * z, - /* b: */ - x * 0.07195537988411677 - - y * 0.2289768264158322 + - 1.405386058324125 * z); -} function XYZ_to_lin_sRGB(x, y, z) { // convert XYZ to linear-light sRGB const M = [ @@ -749,6 +733,45 @@ function OKLab_to_sRGB(l, a, b) { 1.7076147009309444 * S); } +/* +*/ +function xyzd502lch(x, y, z, alpha) { + // @ts-ignore + const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); + // L in range [0,100]. For use in CSS, add a percent + return lab2lchvalues(l, a, b, alpha); +} +function XYZ_D65_to_D50(x, y, z) { + // Bradford chromatic adaptation from D65 to D50 + // The matrix below is the result of three operations: + // - convert from XYZ to retinal cone domain + // - scale components from one reference white to another + // - convert back to XYZ + // see https://github.com/LeaVerou/color.js/pull/354/files + var M = [ + [1.0479297925449969, 0.022946870601609652, -0.05019226628920524], + [0.02962780877005599, 0.9904344267538799, -0.017073799063418826], + [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371] + ]; + return multiplyMatrices(M, [x, y, z]); +} +function xyzd502srgb(x, y, z) { + // @ts-ignore + return lsrgb2srgbvalues( + /* r: */ + x * 3.1341359569958707 - + y * 1.6173863321612538 - + 0.4906619460083532 * z, + /* g: */ + x * -0.978795502912089 + + y * 1.916254567259524 + + 0.03344273116131949 * z, + /* b: */ + x * 0.07195537988411677 - + y * 0.2289768264158322 + + 1.405386058324125 * z); +} + // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 function hex2lab(token) { @@ -1361,28 +1384,6 @@ function hsl2hwbvalues(h, s, l, a = null) { return hsv2hwb(...hsl2hsv(h, s, l, a)); } -function xyzd502lch(x, y, z, alpha) { - // @ts-ignore - const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); - // L in range [0,100]. For use in CSS, add a percent - // @ts-ignore - return lab2lchvalues(l, a, b, alpha); -} -function XYZ_D65_to_D50(x, y, z) { - // Bradford chromatic adaptation from D65 to D50 - // The matrix below is the result of three operations: - // - convert from XYZ to retinal cone domain - // - scale components from one reference white to another - // - convert back to XYZ - // see https://github.com/LeaVerou/color.js/pull/354/files - var M = [ - [1.0479297925449969, 0.022946870601609652, -0.05019226628920524], - [0.02962780877005599, 0.9904344267538799, -0.017073799063418826], - [-0.009243040646204504, 0.015055191490298152, 0.7518742814281371] - ]; - return multiplyMatrices(M, [x, y, z]); -} - function prophotorgb2srgbvalues(r, g, b, a = null) { // @ts-ignore return xyzd502srgb(...prophotorgb2xyz50(r, g, b, a)); @@ -3249,11 +3250,11 @@ function encode_integer(num) { } class SourceMap { + lastLocation = null; #version = 3; #sources = []; #map = new Map; #line = -1; - lastLocation = null; add(source, original) { if (original.src !== '') { if (!this.#sources.includes(original.src)) { @@ -3883,7 +3884,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer, case exports.EnumToken.PseudoClassTokenType: case exports.EnumToken.PseudoElementTokenType: // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == exports.EnumToken.PseudoElementTokenType && ['::before', '::after', '::first-line', '::first-letter'].includes(token.val)) { + if (token.typ == exports.EnumToken.PseudoElementTokenType && pseudoElements.includes(token.val.slice(1))) { return token.val.slice(1); } case exports.EnumToken.UrlTokenTokenType: @@ -3964,6 +3965,7 @@ const mediaTypes = ['all', 'print', 'screen', 'aural', 'braille', 'embossed', 'handheld', 'projection', 'tty', 'tv', 'speech']; // https://www.w3.org/TR/css-values-4/#math-function const mathFuncs = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign']; +const pseudoElements = [':before', ':after', ':first-line', ':first-letter']; const webkitPseudoAliasMap = { '-webkit-autofill': 'autofill', '-webkit-any': 'is', @@ -6220,13 +6222,13 @@ var map = { shorthand: "background" } }; -var config$4 = { +var config$3 = { properties: properties, map: map }; -Object.freeze(config$4); -const getConfig = () => config$4; +Object.freeze(config$3); +const getConfig = () => config$3; function matchType(val, properties) { if (val.typ == exports.EnumToken.IdenTokenType && properties.keywords.includes(val.val) || @@ -7253,7 +7255,7 @@ var declarations = { syntax: "auto || " }, "backdrop-filter": { - syntax: "none | " + syntax: "none | " }, "backface-visibility": { syntax: "visible | hidden" @@ -7667,7 +7669,7 @@ var declarations = { syntax: "nonzero | evenodd" }, filter: { - syntax: "none | " + syntax: "none | " }, flex: { syntax: "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]" @@ -8123,7 +8125,7 @@ var declarations = { syntax: "" }, outline: { - syntax: "[ <'outline-width'> || <'outline-style'> || <'outline-color'> ]" + syntax: "<'outline-width'> || <'outline-style'> || <'outline-color'>" }, "outline-color": { syntax: "auto | " @@ -8552,7 +8554,7 @@ var declarations = { syntax: "space-all | normal | space-first | trim-start" }, "text-transform": { - syntax: "none | capitalize | uppercase | lowercase | full-width | full-size-kana" + syntax: "none | [ capitalize | uppercase | lowercase ] || full-width || full-size-kana | math-auto" }, "text-underline-offset": { syntax: "auto | | " @@ -8642,7 +8644,7 @@ var declarations = { syntax: "visible | hidden | collapse" }, "white-space": { - syntax: "normal | pre | nowrap | pre-wrap | pre-line | break-spaces | [ <'white-space-collapse'> || <'text-wrap'> ]" + syntax: "normal | pre | pre-wrap | pre-line | <'white-space-collapse'> || <'text-wrap-mode'>" }, "white-space-collapse": { syntax: "collapse | preserve | preserve-breaks | preserve-spaces | break-spaces" @@ -8678,7 +8680,7 @@ var declarations = { syntax: "auto | " }, zoom: { - syntax: "normal | reset | | " + syntax: "normal | reset | || " } }; var functions = { @@ -8719,7 +8721,7 @@ var functions = { syntax: "calc-size( , )" }, circle: { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, clamp: { syntax: "clamp( #{3} )" @@ -8755,7 +8757,7 @@ var functions = { syntax: "element( )" }, ellipse: { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, env: { syntax: "env( , ? )" @@ -8770,16 +8772,16 @@ var functions = { syntax: "grayscale( [ | ]? )" }, hsl: { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hsla: { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hue-rotate": { syntax: "hue-rotate( [ | ]? )" }, hwb: { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hypot: { syntax: "hypot( # )" @@ -8868,6 +8870,9 @@ var functions = { ray: { syntax: "ray( && ? && contain? && [at ]? )" }, + rect: { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, rem: { syntax: "rem( , )" }, @@ -8881,10 +8886,10 @@ var functions = { syntax: "repeating-radial-gradient( [ || ]? [ at ]? , )" }, rgb: { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, rgba: { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, rotate: { syntax: "rotate( [ | ] )" @@ -8946,6 +8951,9 @@ var functions = { sqrt: { syntax: "sqrt( )" }, + symbols: { + syntax: "symbols( ? [ | ]+ )" + }, tan: { syntax: "tan( )" }, @@ -8978,6 +8986,9 @@ var functions = { }, view: { syntax: "view([ || <'view-timeline-inset'>]?)" + }, + xywh: { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" } }; var syntaxes = { @@ -8993,6 +9004,9 @@ var syntaxes = { "alpha-value": { syntax: " | " }, + "an+b": { + syntax: "odd | even | | | '+'?† n | -n | | '+'?† | | | '+'?† n | -n | | '+'?† n- | -n- | ['+' | '-'] | '+'?† n ['+' | '-'] | -n ['+' | '-'] " + }, "anchor()": { syntax: "anchor( ? && , ? )" }, @@ -9114,7 +9128,7 @@ var syntaxes = { syntax: "? && " }, "circle()": { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, "clamp()": { syntax: "clamp( #{3} )" @@ -9128,15 +9142,15 @@ var syntaxes = { color: { syntax: " | currentColor | | | " }, + "color()": { + syntax: "color( [ from ]? [ / [ | none ] ]? )" + }, "color-base": { syntax: " | | | | transparent" }, "color-function": { syntax: " | | | | | | | | | " }, - "color()": { - syntax: "color( [from ]? [ / [ | none ] ]? )" - }, "color-interpolation-method": { syntax: "in [ | ? | ]" }, @@ -9245,6 +9259,9 @@ var syntaxes = { dasharray: { syntax: "[ [ | ]+ ]#" }, + "dashndashdigit-ident": { + syntax: "" + }, "deprecated-system-color": { syntax: "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonHighlight | ButtonShadow | CaptionText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, @@ -9285,7 +9302,7 @@ var syntaxes = { syntax: "element( )" }, "ellipse()": { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, "ending-shape": { syntax: "circle | ellipse" @@ -9326,7 +9343,7 @@ var syntaxes = { "filter-function": { syntax: " | | | | | | | | | " }, - "filter-function-list": { + "filter-value-list": { syntax: "[ | ]+" }, "final-bg-layer": { @@ -9381,10 +9398,10 @@ var syntaxes = { syntax: "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hsla()": { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hue: { syntax: " | " @@ -9396,7 +9413,7 @@ var syntaxes = { syntax: "hue-rotate( [ | ]? )" }, "hwb()": { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hypot()": { syntax: "hypot( # )" @@ -9404,6 +9421,9 @@ var syntaxes = { "id-selector": { syntax: "" }, + integer: { + syntax: "" + }, image: { syntax: " | | | | | | " }, @@ -9569,6 +9589,18 @@ var syntaxes = { "mod()": { syntax: "mod( , )" }, + "n-dimension": { + syntax: "" + }, + "ndash-dimension": { + syntax: "" + }, + "ndashdigit-dimension": { + syntax: "" + }, + "ndashdigit-ident": { + syntax: "" + }, "name-repeat": { syntax: "repeat( [ | auto-fill ], + )" }, @@ -9581,9 +9613,6 @@ var syntaxes = { "ns-prefix": { syntax: "[ | '*' ]? '|'" }, - nth: { - syntax: " | even | odd" - }, "number-percentage": { syntax: " | " }, @@ -9692,9 +9721,15 @@ var syntaxes = { quote: { syntax: "open-quote | close-quote | no-open-quote | no-close-quote" }, + "radial-extent": { + syntax: "closest-corner | closest-side | farthest-corner | farthest-side" + }, "radial-gradient()": { syntax: "radial-gradient( [ || ]? [ at ]? , )" }, + "radial-size": { + syntax: " | | {2}" + }, ratio: { syntax: " [ / ]?" }, @@ -9716,6 +9751,9 @@ var syntaxes = { "relative-size": { syntax: "larger | smaller" }, + "rect()": { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, "rem()": { syntax: "rem( , )" }, @@ -9735,10 +9773,10 @@ var syntaxes = { syntax: "reversed( )" }, "rgb()": { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, "rgba()": { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, "rotate()": { syntax: "rotate( [ | ] )" @@ -9812,15 +9850,18 @@ var syntaxes = { "shape-box": { syntax: " | margin-box" }, - "shape-radius": { - syntax: " | closest-side | farthest-side" - }, "side-or-corner": { syntax: "[ left | right ] || [ top | bottom ]" }, "sign()": { syntax: "sign( )" }, + "signed-integer": { + syntax: "" + }, + "signless-integer": { + syntax: "" + }, "sin()": { syntax: "sin( )" }, @@ -9893,6 +9934,12 @@ var syntaxes = { symbol: { syntax: " | | " }, + "symbols()": { + syntax: "symbols( ? [ | ]+ )" + }, + "symbols-type": { + syntax: "cyclic | numeric | alphabetic | symbolic | fixed" + }, "system-color": { syntax: "AccentColor | AccentColorText | ActiveText | ButtonBorder | ButtonFace | ButtonText | Canvas | CanvasText | Field | FieldText | GrayText | Highlight | HighlightText | LinkText | Mark | MarkText | SelectedItem | SelectedItemText | VisitedText" }, @@ -9983,6 +10030,9 @@ var syntaxes = { "wq-name": { syntax: "? " }, + "xywh()": { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" + }, xyz: { syntax: "xyz | xyz-d50 | xyz-d65" }, @@ -10118,16 +10168,16 @@ var selectors = { syntax: ":not( )" }, ":nth-child()": { - syntax: ":nth-child( [ of ]? )" + syntax: ":nth-child( [ of ]? )" }, ":nth-last-child()": { - syntax: ":nth-last-child( [ of ]? )" + syntax: ":nth-last-child( [ of ]? )" }, ":nth-last-of-type()": { - syntax: ":nth-last-of-type( )" + syntax: ":nth-last-of-type( )" }, ":nth-of-type()": { - syntax: ":nth-of-type( )" + syntax: ":nth-of-type( )" }, ":only-child": { syntax: ":only-child" @@ -10410,7 +10460,7 @@ var atRules = { syntax: "normal | " }, "font-display": { - syntax: "[ auto | block | swap | fallback | optional ]" + syntax: "auto | block | swap | fallback | optional" }, "font-family": { syntax: "" @@ -10531,7 +10581,7 @@ var atRules = { } } }; -var config$3 = { +var config$2 = { declarations: declarations, functions: functions, syntaxes: syntaxes, @@ -10539,7 +10589,6 @@ var config$3 = { atRules: atRules }; -const specialValues = ['inherit', 'initial', 'unset', 'revert', 'revert-layer']; var ValidationTokenEnum; (function (ValidationTokenEnum) { ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root"; @@ -11541,100 +11590,6 @@ function move(position, chr) { } return position; } -function renderSyntax(token, parent) { - let glue; - switch (token.typ) { - case ValidationTokenEnum.Root: - return token.chi.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Whitespace: - return ' '; - case ValidationTokenEnum.ValidationFunctionDefinition: - return '<' + token.val + '()>'; - case ValidationTokenEnum.HashMark: - return '#'; - case ValidationTokenEnum.Pipe: - return '|'; - case ValidationTokenEnum.Column: - return '||'; - case ValidationTokenEnum.PipeToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '|' : '') + curr.reduce((acc, curr) => acc + renderSyntax(curr), ''), ''); - case ValidationTokenEnum.ColumnToken: - case ValidationTokenEnum.AmpersandToken: - glue = token.typ == ValidationTokenEnum.ColumnToken ? '||' : '&&'; - return token.l.reduce((acc, curr) => acc + renderSyntax(curr), '') + - glue + - token.r.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Function: - case ValidationTokenEnum.PseudoClassFunctionToken: - case ValidationTokenEnum.Parens: - return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ')' + renderAttributes(token); - case ValidationTokenEnum.Comma: - return ','; - case ValidationTokenEnum.Keyword: - return token.val + renderAttributes(token); - case ValidationTokenEnum.OpenBracket: - return '['; - case ValidationTokenEnum.Ampersand: - return '&&'; - case ValidationTokenEnum.QuestionMark: - return '?'; - case ValidationTokenEnum.Separator: - return '/'; - case ValidationTokenEnum.Bracket: - return '[' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']' + renderAttributes(token); - case ValidationTokenEnum.PropertyType: - return '<' + token.val + '>' + renderAttributes(token); - case ValidationTokenEnum.DeclarationType: - return "<'" + token.val + "'>" + renderAttributes(token); - case ValidationTokenEnum.Number: - case ValidationTokenEnum.PseudoClassToken: - case ValidationTokenEnum.StringToken: - return token.val + ''; - case ValidationTokenEnum.SemiColon: - return ';'; - case ValidationTokenEnum.AtRule: - return '@' + token.val; - case ValidationTokenEnum.AtRuleDefinition: - return '@' + token.val + - (token.prelude == null ? '' : ' ' + token.prelude.reduce((acc, curr) => acc + renderSyntax(curr), '')) + - (token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}'; - case ValidationTokenEnum.Block: - return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}'; - case ValidationTokenEnum.DeclarationDefinitionToken: - return token.nam + ': ' + renderSyntax(token.val); - case ValidationTokenEnum.ColumnArrayToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '||' : '') + renderSyntax(curr), ''); - default: - throw new Error('Unhandled token: ' + JSON.stringify({ token })); - } -} -function renderAttributes(token) { - let result = ''; - if (token.isList) { - result += '#'; - } - if (token.isOptional) { - result += '?'; - } - if (token.isRepeatableGroup) { - result += '!'; - } - if (token.isRepeatable) { - result += '*'; - } - if (token.atLeastOnce) { - result += '+'; - } - if (token.occurence != null) { - if (token.occurence.max == 0 || token.occurence.max == token.occurence.min || Number.isNaN(token.occurence.max)) { - result += '{' + token.occurence.min + '}'; - } - else { - result += '{' + token.occurence.min + ',' + token.occurence.max + '}'; - } - } - return result; -} function minify$1(ast) { if (Array.isArray(ast)) { // @ts-ignore @@ -11736,14 +11691,14 @@ function* walkValidationToken(token, parent, callback, key) { } const parsedSyntaxes = new Map(); -Object.freeze(config$3); +Object.freeze(config$2); function getSyntaxConfig() { // @ts-ignore - return config$3; + return config$2; } function getParsedSyntax(group, key) { // @ts-ignore - let obj = config$3[group]; + let obj = config$2[group]; const keys = Array.isArray(key) ? key : [key]; for (let i = 0; i < keys.length; i++) { key = keys[i]; @@ -11781,7 +11736,7 @@ function validateLayerName(tokens) { acc[acc.length - 1].push(curr); } return acc; - }, [[]]).slice(1); + }, [[]]); for (let i = 0; i < slice.length; i++) { if (slice[i].length == 0) { // @ts-ignore @@ -11794,26 +11749,15 @@ function validateLayerName(tokens) { tokens }; } - if (slice[i][0].typ != exports.EnumToken.IdenTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: tokens, - node: slice[i][0], - syntax: 'ident', - error: 'expecting ident', - tokens - }; - } - for (let j = 1; j < slice[i].length; j++) { - if (slice[i][j].typ != exports.EnumToken.ClassSelectorTokenType) { + for (let j = 0; j < slice[i].length; j++) { + if (slice[i][j].typ != exports.EnumToken.IdenTokenType && slice[i][j].typ != exports.EnumToken.ClassSelectorTokenType) { // @ts-ignore return { valid: ValidationLevel.Drop, matches: tokens, node: slice[i][j], - syntax: 'layer-name', - error: 'expecting class selector', + syntax: '', + error: 'expecting ident or class selector', tokens }; } @@ -12442,1463 +12386,104 @@ function validateKeyframeBlockList(tokens, atRule, options) { return validateKeyframeSelector(i == j ? tokens.slice(i) : tokens.slice(j, i + 1), atRule); } -const config$2 = getSyntaxConfig(); -function consumeToken(tokens) { - tokens.shift(); -} -function consumeSyntax(syntaxes) { - syntaxes.shift(); +const matchUrl = /^(https?:)?\/\//; +function dirname(path) { + if (path == '/' || path === '') { + return path; + } + let i = 0; + let parts = ['']; + for (; i < path.length; i++) { + const chr = path.charAt(i); + if (chr == '/') { + parts.push(''); + } + else if (chr == '?' || chr == '#') { + break; + } + else { + parts[parts.length - 1] += chr; + } + } + parts.pop(); + return parts.length == 0 ? '/' : parts.join('/'); } -function splice(tokens, matches) { - if (matches.length == 0) { - return tokens; +function splitPath(result) { + const parts = ['']; + let i = 0; + for (; i < result.length; i++) { + const chr = result.charAt(i); + if (chr == '/') { + parts.push(''); + } + else if (chr == '?' || chr == '#') { + break; + } + else { + parts[parts.length - 1] += chr; + } } - // @ts-ignore - const index = tokens.indexOf(matches.at(-1)); - if (index > -1) { - tokens.splice(0, index + 1); + let k = -1; + while (++k < parts.length) { + if (parts[k] == '.') { + parts.splice(k--, 1); + } + else if (parts[k] == '..') { + parts.splice(k - 1, 2); + k -= 2; + } } - return tokens; + return { parts, i }; } -function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) { - console.error(JSON.stringify({ - syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''), - syntaxes, - tokens, - s: new Error('bar').stack - }, null, 1)); - if (syntaxes == null) { - // @ts-ignore +function resolve(url, currentDirectory, cwd) { + if (matchUrl.test(url)) { return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0] ?? null, - syntax: null, - error: 'no matching syntaxes found', - tokens + absolute: url, + relative: url }; } - let token = null; - let syntax; - let result = null; - let validSyntax = false; - let matched = false; - const matches = []; - tokens = tokens.slice(); - syntaxes = syntaxes.slice(); - tokens = tokens.slice(); - if (context.cache == null) { - context.cache = new WeakMap; + if (matchUrl.test(currentDirectory)) { + const path = new URL(url, currentDirectory).href; + return { + absolute: path, + relative: path + }; } - if (context.tokens == null) { - context.tokens = tokens.slice(); + let result; + if (url.charAt(0) == '/') { + result = url; } - context = { ...context }; - main: while (tokens.length > 0) { - if (syntaxes.length == 0) { - break; - } - token = tokens[0]; - syntax = syntaxes[0]; - // @ts-ignore - context.position = context.tokens.indexOf(token); - const cached = context.cache.get(token)?.get(syntax.text) ?? null; - if (cached != null) { - if (cached.error.length > 0) { - return { ...cached, tokens, node: cached.valid == ValidationLevel.Valid ? null : token }; - } - syntaxes.shift(); - tokens.shift(); - continue; - } - if (token.typ == exports.EnumToken.DescendantCombinatorTokenType) { - tokens.shift(); - if (syntax.typ == ValidationTokenEnum.Whitespace) { - syntaxes.shift(); - } - continue; - } - else if (syntax.typ == ValidationTokenEnum.Whitespace) { - syntaxes.shift(); - if (token.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - continue; + else if (currentDirectory.charAt(0) == '/') { + result = dirname(currentDirectory) + '/' + url; + } + else if (currentDirectory === '' || dirname(currentDirectory) === '') { + result = url; + } + else { + result = dirname(currentDirectory) + '/' + url; + } + let { parts, i } = splitPath(result); + if (parts.length == 0) { + const path = result.charAt(0) == '/' ? '/' : ''; + return { + absolute: path, + relative: path + }; + } + const absolute = parts.join('/'); + const { parts: dirs } = splitPath(cwd ?? currentDirectory); + for (const p of dirs) { + if (parts[0] == p) { + parts.shift(); } - else if (syntax.typ == ValidationTokenEnum.Block && exports.EnumToken.AtRuleTokenType == token.typ && ('chi' in token)) { - syntaxes.shift(); - tokens.shift(); - // @ts-ignore - matches.push(token); - continue; + else { + parts.unshift('..'); } - if (syntax.isOptional) { - if (!context.cache.has(token)) { - context.cache.set(token, new Map); - } - if (context.cache.get(token).has(syntax.text)) { - result = context.cache.get(token).get(syntax.text); - return { ...result, tokens, node: result.valid == ValidationLevel.Valid ? null : token }; - } - // @ts-ignore - const { isOptional, ...c } = syntax; - // @ts-ignore - let result2; - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.valid == ValidationLevel.Valid && result2.matches.length > 0) { - tokens = result2.tokens; - // splice(tokens, result2.matches); - // tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - matched = true; - result = result2; - } - else { - syntaxes.shift(); - continue; - } - syntaxes.shift(); - if (syntaxes.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Valid, - matches: result2.matches, - node: result2.node, - syntax: result2.syntax, - error: result2.error, - tokens - }; - } - continue; - } - if (syntax.isList) { - let index = -1; - // @ts-ignore - let { isList, ...c } = syntax; - // const c: ValidationToken = {...syntaxes, isList: false} as ValidationToken; - let result2 = null; - validSyntax = false; - do { - for (let i = index + 1; i < tokens.length; i++) { - if (tokens[i].typ == exports.EnumToken.CommaTokenType) { - index = i; - break; - } - } - if (tokens[index + 1]?.typ == exports.EnumToken.CommaTokenType) { - return { - valid: ValidationLevel.Drop, - matches, - node: tokens[0], - syntax, - error: 'unexpected token', - tokens - }; - } - if (index == -1) { - index = tokens.length; - } - if (index == 0) { - break; - } - // @ts-ignore - result2 = validateSyntax([c], tokens.slice(0, index), root, options, context); - matched = result2.valid == ValidationLevel.Valid && result2.matches.length > 0; - if (matched) { - const l = tokens.length; - validSyntax = true; - // @ts-ignore - // matches.push(...result2.matches); - // splice(tokens, result2.matches); - if (tokens.length == 1 && tokens[0].typ == exports.EnumToken.CommaTokenType) { - return { - valid: ValidationLevel.Drop, - matches, - node: tokens[0], - syntax, - error: 'unexpected token', - tokens - }; - } - tokens = tokens.slice(index); - result = result2; - // @ts-ignore - matches.push(...result2.matches); - if (result.tokens.length > 0) { - if (index == -1) { - tokens = result.tokens; - } - else { - tokens = tokens.slice(index - result.tokens.length); - } - } - else if (index > 0) { - tokens = tokens.slice(index); - } - index = -1; - if (l == tokens.length) { - break; - } - } - else { - break; - } - } while (tokens.length > 0); - // if (level == 0) { - // } - if (!matched) { - return { - valid: ValidationLevel.Drop, - // @ts-ignore - matches: [...new Set(matches)], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - syntaxes.shift(); - continue; - } - if (syntax.isRepeatable) { - // @ts-ignore - let { isRepeatable, ...c } = syntax; - let result2 = null; - validSyntax = false; - let l = tokens.length; - let tok = null; - do { - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.matches.length == 0 && result2.error.length > 0) { - syntaxes.shift(); - break main; - } - if (result2.valid == ValidationLevel.Valid) { - tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - result = result2; - if (l == tokens.length) { - if (tok == tokens[0]) { - break; - } - if (result2.matches.length == 0 && tokens.length > 0) { - tokens = result2.tokens; - tok = tokens[0]; - continue; - } - break; - } - if (matches.length == 0) { - tokens = result2.tokens; - } - l = tokens.length; - continue; - } - break; - } while (result2.valid == ValidationLevel.Valid && tokens.length > 0); - // if (lastResult != null) { - // - // splice(tokens, lastResult.matches); - // // tokens = lastResult.tokens; - // } - syntaxes.shift(); - continue; - } - // at least one match - if (syntax.isRepeatableGroup) { - validSyntax = false; - let count = 0; - let l = tokens.length; - let result2 = null; - do { - // @ts-ignore - const { isRepeatableGroup, ...c } = syntax; - // @ts-ignore - result2 = validateSyntax([c], tokens, root, options, context); - if (result2.valid == ValidationLevel.Drop || result2.matches.length == 0) { - if (count > 0) { - syntaxes.shift(); - // if (result2.matches.length == 0) { - tokens = result2.tokens; - // break main; - if (syntaxes.length == 0) { - return result2; - } - break main; - } - return result2; - } - if (result2.valid == ValidationLevel.Valid && result2.matches.length > 0) { - count++; - // lastResult = result; - validSyntax = true; - tokens = result2.tokens; - // splice(tokens, result2.matches); - // tokens = result2.tokens; - // @ts-ignore - matches.push(...result2.matches); - result = result2; - if (l == tokens.length) { - break; - } - l = tokens.length; - } - else { - break; - } - } while (tokens.length > 0 && result.valid == ValidationLevel.Valid); - // if (lastResult != null) { - // - // splice(tokens, lastResult.matches); - // // tokens = lastResult.tokens; - // } - // at least one match is expected - if (!validSyntax /* || result.matches.length == 0 */) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - node: token, - tokens, - syntax, - error: 'unexpected token', - matches: [] - }; - } - syntaxes.shift(); - continue; - } - if (syntax.atLeastOnce) { - const { atLeastOnce, ...c } = syntax; - result = validateSyntax([c], tokens, root, options, context); - if (result.valid == ValidationLevel.Drop) { - return result; - } - splice(tokens, result.matches); - // tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - let l = tokens.length; - let r = validateSyntax([c], tokens, root, options, context); - while (r.valid == ValidationLevel.Valid) { - splice(tokens, r.matches); - // tokens = r.tokens; - r = validateSyntax([c], tokens, root, options, context); - if (l == tokens.length) { - break; - } - if (r.valid == ValidationLevel.Valid && r.matches.length > 0) { - // @ts-ignore - matches.push(...result.matches); - } - l = tokens.length; - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (syntax.occurence != null) { - // @ts-ignore - const { occurence, ...c } = syntax; - // && syntaxes.occurence.max != null - // consume all tokens - let match = 1; - // @ts-ignore - result = validateSyntax([c], tokens, root, options, context); - if (result.valid == ValidationLevel.Drop) { - return result; - } - if (result.matches.length == 0) { - syntaxes.shift(); - continue; - } - // splice(tokens, result.matches); - // tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - matched = true; - tokens = result.tokens; - while (occurence.max == null || match < occurence.max) { - // trim whitespace - if (tokens[0]?.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - // @ts-ignore - let r = validateSyntax([c], tokens, root, options, context); - if (r.valid != ValidationLevel.Valid || r.matches.length == 0) { - break; - } - result = r; - // splice(tokens, r.matches); - // tokens = r.tokens; - // @ts-ignore - matches.push(...result.matches); - match++; - tokens = r.tokens; - result = r; - if (tokens.length == 0 || (occurence.max != null && match >= occurence.max)) { - break; - } - // @ts-ignore - // r = validateSyntax([c], tokens, root, options, context); - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (syntax.typ == ValidationTokenEnum.Whitespace) { - if (token.typ == exports.EnumToken.WhitespaceTokenType) { - tokens.shift(); - } - syntaxes.shift(); - continue; - } - // @ts-ignore - if (token.val != null && specialValues.includes(token.val)) { - matched = true; - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - // @ts-ignore - matches.push(...result.matches); - } - else { - result = doValidateSyntax(syntax, token, tokens, root, options, context); - matched = result.valid == ValidationLevel.Valid && result.matches.length > 0; - if (matched) { - // splice(tokens, result.matches); - tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - } - } - if (result.valid == ValidationLevel.Drop) { - // @ts-ignore - return { ...result, matches, tokens, node: result.valid == ValidationLevel.Valid ? null : token }; - } - consumeSyntax(syntaxes); - if (tokens.length == 0) { - return result; - } - } - if (result?.valid == ValidationLevel.Valid) { - // splice(tokens, result.matches); - tokens = result.tokens; - // @ts-ignore - matches.push(...result.matches); - } - if ( /* result == null && */tokens.length == 0 && syntaxes.length > 0) { - validSyntax = isOptionalSyntax(syntaxes); - } - if (result == null) { - result = { - valid: validSyntax ? ValidationLevel.Valid : ValidationLevel.Drop, - matches, - node: validSyntax ? null : tokens[0] ?? null, - // @ts-ignore - syntax, - error: validSyntax ? '' : 'unexpected token', - tokens - }; - } - if (token != null) { - if (!context.cache.has(token)) { - context.cache.set(token, new Map); - } - context.cache.get(token).set(syntax.text, result); - } - if (result != null) { - // @ts-ignore - return { ...result, matches: [...(new Set(matches))] }; - } - return result; -} -function isOptionalSyntax(syntaxes) { - return syntaxes.length > 0 && syntaxes.every(t => t.typ == ValidationTokenEnum.Whitespace || t.isOptional || t.isRepeatable || (t.typ == ValidationTokenEnum.PropertyType && isOptionalSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, t.val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, t.val) ?? []))); -} -function doValidateSyntax(syntax, token, tokens, root, options, context) { - let valid = false; - let result; - let children; - let queue; - let matches; - let child; - let astNodes = new Set; - if (token.typ == exports.EnumToken.NestingSelectorTokenType && syntax.typ == 2) { - valid = root != null && 'relative-selector' == syntax.val; - return { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - switch (syntax.typ) { - case ValidationTokenEnum.Comma: - valid = token.typ === exports.EnumToken.CommaTokenType; - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.AtRule: - if (token.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule', - tokens - }; - } - if (token.nam != syntax.val) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: `expecting '@${syntax.val}' but found '@${token.nam}'`, - tokens - }; - } - if (root == null) { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - if (root.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'not allowed here', - tokens - }; - } - if (!('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '@at-rule must have children', - tokens - }; - } - // @ts-ignore - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - break; - case ValidationTokenEnum.AtRuleDefinition: - if (token.typ != exports.EnumToken.AtRuleNodeType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule', - tokens - }; - } - if ('chi' in syntax && !('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '@at-rule must have children', - tokens - }; - } - if ('chi' in token && !('chi' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'children not allowed here', - tokens - }; - } - const s = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + token.nam); - if ('prelude' in syntax) { - if (!('tokens' in token)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expected at-rule prelude', - tokens - }; - } - result = validateSyntax(s[0].prelude, token.tokens, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - if (result.valid == ValidationLevel.Drop) { - return result; - } - } - const hasBody = 'chi' in s[0]; - if ('chi' in token) { - if (!hasBody) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected at-rule body', - tokens - }; - } - } - else if (hasBody) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'expecting at-rule body', - tokens - }; - } - break; - case ValidationTokenEnum.DeclarationType: - // @ts-ignore - result = validateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, syntax.val), [token], root, options, context); - break; - case ValidationTokenEnum.Keyword: - valid = (token.typ == exports.EnumToken.IdenTokenType && token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0) || - (token.typ == exports.EnumToken.ColorTokenType && token.kin == 'lit' && syntax.val.localeCompare(token.val, 'en', { sensitivity: 'base' }) == 0); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.SemiColon: - valid = root == null || [exports.EnumToken.RuleNodeType, exports.EnumToken.AtRuleNodeType, exports.EnumToken.StyleSheetNodeType].includes(root.typ); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.Separator: - valid = token.typ == exports.EnumToken.LiteralTokenType && token.val != '/'; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - break; - case ValidationTokenEnum.PropertyType: - // - if ('image' == syntax.val) { - valid = token.typ == exports.EnumToken.UrlFunctionTokenType || token.typ == exports.EnumToken.ImageFunctionTokenType; - if (!valid) { - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected ', - tokens - }; - } - result = validateImage(token); - } - else if (['media-feature', 'mf-plain'].includes(syntax.val)) { - valid = token.typ == exports.EnumToken.DeclarationNodeType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (syntax.val == 'pseudo-page') { - valid = token.typ == exports.EnumToken.PseudoClassTokenType && [':left', ':right', ':first', ':blank'].includes(token.val); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (syntax.val == 'page-body') { - if (token.typ == exports.EnumToken.DeclarationNodeType) { - valid = true; - // @ts-ignore - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - while (tokens.length > 0 && [exports.EnumToken.DeclarationNodeType].includes(tokens[0].typ)) { - // @ts-ignore - result.matches.push(tokens.shift()); - } - } - else if (token.typ == exports.EnumToken.AtRuleNodeType) { - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'page-margin-box-type'), [token], root, options, context); - } - } - else if (syntax.val == 'group-rule-body') { - valid = [exports.EnumToken.AtRuleNodeType, exports.EnumToken.RuleNodeType].includes(token.typ); - if (!valid && token.typ == exports.EnumToken.DeclarationNodeType && root?.typ == exports.EnumToken.AtRuleNodeType && root.nam == 'media') { - // allowed only if nested rule - let parent = root; - while (parent != null) { - if (parent.typ == exports.EnumToken.RuleNodeType) { - valid = true; - break; - } - // @ts-ignore - parent = parent.parent; - } - } - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'token is not allowed as a child', - tokens - }; - if (!valid) { - return result; - } - } - // - else if ('type-selector' == syntax.val) { - valid = (token.typ == exports.EnumToken.UniversalSelectorTokenType) || - token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || - (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('wq-name' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (exports.EnumToken.UniversalSelectorTokenType == token.typ && 'subclass-selector' == syntax.val) { - valid = true; - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else if ('attribute-selector' == syntax.val) { - valid = token.typ == exports.EnumToken.AttrTokenType && token.chi.length > 0; - if (valid) { - const children = token.chi.filter(t => t.typ != exports.EnumToken.WhitespaceTokenType && t.typ != exports.EnumToken.CommaTokenType); - valid = children.length == 1 && [ - exports.EnumToken.IdenTokenType, - exports.EnumToken.NameSpaceAttributeTokenType, - exports.EnumToken.MatchExpressionTokenType - ].includes(children[0].typ); - if (valid && children[0].typ == exports.EnumToken.MatchExpressionTokenType) { - const t = children[0]; - valid = [ - exports.EnumToken.IdenTokenType, - exports.EnumToken.NameSpaceAttributeTokenType - ].includes(t.l.typ) && - (t.op == null || ([ - exports.EnumToken.DelimTokenType, exports.EnumToken.DashMatchTokenType, - exports.EnumToken.StartMatchTokenType, exports.EnumToken.ContainMatchTokenType, - exports.EnumToken.EndMatchTokenType, exports.EnumToken.IncludeMatchTokenType - ].includes(t.op.typ) && - t.r != null && - [ - exports.EnumToken.StringTokenType, - exports.EnumToken.IdenTokenType - ].includes(t.r.typ))); - if (valid && t.attr != null) { - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'attr-modifier')[0]; - valid = s.chi.some((l) => l.some((r) => r.val == t.attr)); - } - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - if (!valid) { - return result; - } - } - else if ('combinator' == syntax.val) { - valid = [ - exports.EnumToken.DescendantCombinatorTokenType, - exports.EnumToken.SubsequentSiblingCombinatorTokenType, - exports.EnumToken.NextSiblingCombinatorTokenType, - exports.EnumToken.ChildCombinatorTokenType, - exports.EnumToken.ColumnCombinatorTokenType - ].includes(token.typ); - if (valid) { - // @ts-ignore - const position = context.tokens.indexOf(token); - if (root == null) { - valid = position > 0 && context.tokens[position - 1]?.typ != exports.EnumToken.CommaTokenType; - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - if (!valid) { - return result; - } - } - else if ('ident-token' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('hex-color' == syntax.val) { - valid = token.typ == exports.EnumToken.ColorTokenType && token.kin == 'hex'; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('resolution' == syntax.val) { - valid = token.typ == exports.EnumToken.ResolutionTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('angle' == syntax.val) { - valid = token.typ == exports.EnumToken.AngleTokenType || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('time' == syntax.val) { - valid = token.typ == exports.EnumToken.TimingFunctionTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('ident' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (['id-selector', 'hash-token'].includes(syntax.val)) { - valid = token.typ == exports.EnumToken.HashTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if (['integer', 'number'].includes(syntax.val)) { - // valid = token.typ == EnumToken.NumberTokenType; - valid = token.typ == exports.EnumToken.NumberTokenType && ('integer' != syntax.val || Number.isInteger(+token.val)); - if (valid && 'range' in syntax) { - const value = Number(token.val); - const range = syntax.range; - valid = value >= range[0] && (range[1] == null || value <= range[1]); - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('length' == syntax.val) { - valid = isLength(token) || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - // @ts-ignore - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('percentage' == syntax.val) { - valid = token.typ == exports.EnumToken.PercentageTokenType || (token.typ == exports.EnumToken.NumberTokenType && token.val == '0'); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('dashed-ident' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('custom-ident' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType || token.typ == exports.EnumToken.IdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('custom-property-name' == syntax.val) { - valid = token.typ == exports.EnumToken.DashedIdenTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('string' == syntax.val) { - valid = token.typ == exports.EnumToken.StringTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('declaration-value' == syntax.val) { - valid = token.typ != exports.EnumToken.LiteralTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('url' == syntax.val) { - valid = token.typ == exports.EnumToken.UrlFunctionTokenType || token.typ == exports.EnumToken.StringTokenType; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('declaration' == syntax.val) { - valid = token.typ == exports.EnumToken.DeclarationNodeType && (token.nam.startsWith(('--')) || token.nam in config$2.declarations || token.nam in config$2.syntaxes); - if (!valid) { - // @ts-ignore - result = { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - else if (token.nam.startsWith(('--'))) { - result = { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else { - result = validateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, token.nam) ?? getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, token.nam), token.val, token, options, { - ...context, - tokens: null, - level: 0 - }); - if (result.valid == ValidationLevel.Valid && result.error.length == 0) { - tokens = result.tokens; - } - } - } - else if ('class-selector' == syntax.val) { - valid = exports.EnumToken.ClassSelectorTokenType == token.typ || exports.EnumToken.UniversalSelectorTokenType == token.typ; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - // else if ('complex-selector' == (syntaxes as ValidationPropertyToken).val) { - // - // result = validateSyntax(getParsedSyntax(ValidationSyntaxGroupEnum.Syntaxes, (syntaxes as ValidationPropertyToken).val) as ValidationToken[], tokens, root as AstNode, options, context); - // - // } - else if (['pseudo-element-selector', 'pseudo-class-selector'].includes(syntax.val)) { - valid = false; - if (token.typ == exports.EnumToken.PseudoClassTokenType) { - let val = token.val; - if (val == ':before' || val == ':after') { - val = ':' + val; - } - valid = val in config$2.selectors; - if (!valid && val.match(/^:?:-/) != null) { - const match = token.val.match(/^(:?:)(-[^-]+-)(.*)$/); - if (match != null) { - valid = true; - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'invalid pseudo class', - tokens - }; - } - else if (token.typ == exports.EnumToken.PseudoClassFuncTokenType) { - let key = token.val in config$2.selectors ? token.val : token.val + '()'; - valid = key in config$2.selectors; - if (!valid && token.val.match(/^:?:-/)) { - const match = token.val.match(/^(:?:)(-[^-]+-)(.*)$/); - if (match != null) { - key = match[1] + match[3] in config$2.selectors ? match[1] + match[3] : match[1] + match[3] + '()'; - valid = key in config$2.selectors; - } - } - const s = getParsedSyntax("selectors" /* ValidationSyntaxGroupEnum.Selectors */, key); - if (s != null) { - const r = s[0]; - if (r.typ != ValidationTokenEnum.PseudoClassFunctionToken) { - valid = false; - } - else { - result = validateSyntax(s[0].chi, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - break; - } - } - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - // - // - else if ('relative-selector' == syntax.val) { - if (tokens.length == 1 && token.typ == exports.EnumToken.NestingSelectorTokenType) { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: token, - syntax, - error: '', - tokens - }; - } - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val), token.typ == exports.EnumToken.NestingSelectorTokenType ? tokens.slice(1) : tokens, root, options, context); - } - // - // - else if (['forgiving-selector-list', 'forgiving-relative-selector-list'].includes(syntax.val)) { - // @ts-ignore - result = { tokens: tokens.slice(), ...validateSelector(tokens, options, root) }; - } - // https://github.com/mdn/data/pull/186#issuecomment-369604537 - else if (syntax.val.endsWith('-token')) { - const val = syntax.val; - valid = true; - switch (val) { - case 'function-token': - valid = token.typ != exports.EnumToken.ParensTokenType && funcLike.includes(token.typ); - break; - case 'ident-token': - valid = token.typ == exports.EnumToken.DashedIdenTokenType || token.typ == exports.EnumToken.IdenTokenType; - break; - case 'hash-token': - valid = token.typ == exports.EnumToken.HashTokenType; - break; - case 'string-token': - valid = token.typ == exports.EnumToken.StringTokenType; - break; - default: - console.error(new Error(`unhandled syntax: '<${val}>'`)); - break; - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else if ('wq-name' == syntax.val) { - valid = token.typ == exports.EnumToken.IdenTokenType || (token.typ == exports.EnumToken.NameSpaceAttributeTokenType && - (token.l == null || token.l.typ == exports.EnumToken.IdenTokenType || (token.l.typ == exports.EnumToken.LiteralTokenType && token.l.val == '*')) && - token.r.typ == exports.EnumToken.IdenTokenType); - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: token, - syntax, - error: valid ? '' : 'unexpected token', - tokens - }; - } - else { - const val = syntax.val; - // https://github.com/mdn/data/pull/186#issuecomment-369604537 - if (val == 'any-value') { - return { - valid: ValidationLevel.Valid, - matches: [token], - node: null, - syntax, - error: '', - tokens - }; - } - else if (val in config$2.declarations || val in config$2.syntaxes) { - result = validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, val) ?? getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, val), tokens, root, options, context); - } - else { - // @ts-ignore - result = { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - }; - } - } - break; - case ValidationTokenEnum.Parens: - case ValidationTokenEnum.Function: - if (syntax.typ == ValidationTokenEnum.Parens) { - valid = token.typ == exports.EnumToken.ParensTokenType; - } - else { - valid = 'chi' in token && 'val' in token && - token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0; - } - result = !valid ? - // @ts-ignore - { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: 'unexpected token', - tokens - } : validateSyntax(syntax.chi, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }); - break; - case ValidationTokenEnum.ValidationFunctionDefinition: - valid = 'val' in token && 'chi' in token; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: '', - tokens - }; - if (result.valid == ValidationLevel.Valid) { - valid = token.val.localeCompare(syntax.val, 'en', { sensitivity: 'base' }) == 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - error: '', - syntax, - tokens - }; - if (result.valid == ValidationLevel.Valid) { - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, syntax.val + '()'); // config[ValidationSyntaxGroupEnum.Syntaxes][(syntaxes as ValidationFunctionDefinitionToken).val + '()'] as ValidationSyntaxNode; - result = validateSyntax(s, tokens, root, options, context); - } - } - break; - case ValidationTokenEnum.Bracket: - result = validateSyntax(syntax.chi, tokens, root, options, context); - break; - case ValidationTokenEnum.PipeToken: - for (const lines of syntax.chi) { - result = validateSyntax(lines, tokens, root, options, context); - if (result.valid == ValidationLevel.Valid) { - break; - } - } - break; - case ValidationTokenEnum.AmpersandToken: - children = [...syntax.l.slice(), ...syntax.r.slice()]; - matches = []; - queue = []; - let m = []; - for (let j = 0; j < children.length; j++) { - const res = validateSyntax([children[j]], tokens, root, options, context); - // @ts-ignore - if (res.valid == ValidationLevel.Valid) { - m.push(...res.matches); - matches.push(...children.splice(j, 1)); - j = 0; - // @ts-ignore - astNodes.delete(token); - consumeToken(tokens); - token = tokens[0]; - if (token == null) { - break; - } - // @ts-ignore - astNodes.add(token); - } - } - if (astNodes.size > 0) { - // @ts-ignore - tokens.unshift(...astNodes); - astNodes = new Set(); - } - valid = matches.length > 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: m, - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - break; - case ValidationTokenEnum.ColumnToken: - children = [...syntax.l.slice(), ...syntax.r.slice()]; - matches = []; - queue = []; - while ((child = children.shift())) { - const res = validateSyntax([child], tokens, root, options, context); - if (res.valid == ValidationLevel.Valid) { - matches.push(child); - consumeToken(tokens); - token = tokens[0]; - if (queue.length > 0) { - children.unshift(...queue); - queue = []; - } - if (token == null) { - break; - } - } - else { - queue.push(child); - } - } - valid = matches.length > 0; - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - break; - case ValidationTokenEnum.StringToken: - valid = token.typ == exports.EnumToken.StringTokenType && syntax.val.slice(1, -1) == token.val.slice(1, -1); - return { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'expecting token', - tokens - }; - case ValidationTokenEnum.PseudoClassFunctionToken: - valid = token.typ == exports.EnumToken.PseudoClassFuncTokenType; - if (valid) { - let key = token.val in config$2.selectors ? token.val : token.val + '()'; - const s = getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, key); - valid = s != null && validateSyntax(s, token.chi, root, options, { - ...context, - tokens: null, - level: context.level + 1 - }).valid == ValidationLevel.Valid; - } - result = { - valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, - matches: valid ? [token] : [], - node: valid ? null : token, - syntax, - error: valid ? '' : 'invalid token', - tokens - }; - break; - case ValidationTokenEnum.DeclarationDefinitionToken: - if (token.typ != exports.EnumToken.DeclarationNodeType || token.nam != syntax.nam) { - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax, - error: '', - tokens - }; - } - return validateSyntax([syntax.val], token.val, root, options, context); - default: - throw new Error('not implemented: ' + JSON.stringify({ syntax, token, tokens }, null, 1)); } - // @ts-ignore - return result; + return { + absolute, + relative: parts.join('/') + (i < result.length ? result.slice(i) : '') + }; } function validateURL(token) { @@ -13966,23 +12551,6 @@ function validateURL(token) { }; } -function validateImage(token) { - if (token.typ == exports.EnumToken.UrlFunctionTokenType) { - return validateURL(token); - } - if (token.typ == exports.EnumToken.ImageFunctionTokenType) { - return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, token.val + '()'), token.chi); - } - return { - valid: ValidationLevel.Drop, - matches: [], - node: token, - syntax: 'image()', - error: 'expected or ', - tokens: [] - }; -} - const validateSelectorList = validateComplexSelectorList; function validateSelector(selector, options, root) { @@ -14227,7 +12795,7 @@ function validateMediaCondition(token, atRule) { if (token.typ == exports.EnumToken.MediaFeatureNotTokenType) { return validateMediaCondition(token.val, atRule); } - if (token.typ != exports.EnumToken.ParensTokenType && !(['when', 'else'].includes(atRule.nam) && token.typ == exports.EnumToken.FunctionTokenType && ['media', 'supports'].includes(token.val))) { + if (token.typ != exports.EnumToken.ParensTokenType && !(['when', 'else', 'import'].includes(atRule.nam) && token.typ == exports.EnumToken.FunctionTokenType && ['media', 'supports', 'selector'].includes(token.val))) { return false; } const chi = token.chi.filter((t) => t.typ != exports.EnumToken.CommentTokenType && t.typ != exports.EnumToken.WhitespaceTokenType); @@ -14243,6 +12811,7 @@ function validateMediaCondition(token, atRule) { if (chi[0].typ == exports.EnumToken.MediaQueryConditionTokenType) { return chi[0].l.typ == exports.EnumToken.IdenTokenType; } + console.error(chi[0].parent); return false; } function validateMediaFeature(token) { @@ -14489,6 +13058,7 @@ function validateAtRuleSupports(atRule, options, root) { }; } function validateAtRuleSupportsConditions(atRule, tokenList) { + let result = null; for (const tokens of splitTokenList(tokenList)) { if (tokens.length == 0) { // @ts-ignore @@ -14502,22 +13072,46 @@ function validateAtRuleSupportsConditions(atRule, tokenList) { }; } let previousToken = null; - let result = null; while (tokens.length > 0) { result = validateSupportCondition(atRule, tokens[0]); // supports-condition - if (result == null || result.valid == ValidationLevel.Valid) { + if (result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { result = validateSupportFeature(tokens[0]); - if (result == null || result.valid == ValidationLevel.Valid) { + if ( /*result == null || */result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { - return result; + if (tokens[0].typ == exports.EnumToken.ParensTokenType) { + result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if ( /* result == null || */result.valid == ValidationLevel.Valid) { + previousToken = tokens[0]; + tokens.shift(); + // continue; + } + else { + return result; + } + } + else { + return result; + } + // if (result!= null && result.valid == ValidationLevel.Drop) { + // + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0] ?? atRule, + // syntax: '@' + atRule.nam, + // // @ts-ignore + // error: result.error as string ?? 'unexpected token', + // tokens: [] + // }; + // } } } if (tokens.length == 0) { @@ -14572,7 +13166,14 @@ function validateAtRuleSupportsConditions(atRule, tokenList) { } } } - return null; + return { + valid: ValidationLevel.Valid, + matches: [], + node: atRule, + syntax: '@' + atRule.nam, + error: '', + tokens: [] + }; } function validateSupportCondition(atRule, token) { if (token.typ == exports.EnumToken.MediaFeatureNotTokenType) { @@ -14639,7 +13240,7 @@ function validateSupportCondition(atRule, token) { function validateSupportFeature(token) { if (token.typ == exports.EnumToken.FunctionTokenType) { if (token.val.localeCompare('selector', undefined, { sensitivity: 'base' }) == 0) { - return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'complex-selector'), token.chi); + return validateComplexSelector(parseSelector(token.chi)); } if (token.val.localeCompare('font-tech', undefined, { sensitivity: 'base' }) == 0) { const chi = token.chi.filter((t) => ![exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType].includes(t.typ)); @@ -14748,106 +13349,7 @@ function validateAtRuleImport(atRule, options, root) { tokens }; } - else { - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; - } - } - } - else { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting url() or string', - tokens - }; - } - if (tokens.length > 0) { - // @ts-ignore - if (tokens[0].typ == exports.EnumToken.IdenTokenType) { - // @ts-ignore - if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0) { - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; - } - } - } - // @ts-ignore - else if (tokens[0].typ == exports.EnumToken.FunctionTokenType) { - // @ts-ignore - if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) != 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting layer()', - tokens - }; - } - // @ts-ignore - const result = validateLayerName(tokens[0].chi); - if (result.valid == ValidationLevel.Drop) { - return result; - } - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; - } - } - } - if (tokens.length > 0) { - // @ts-ignore - if (tokens[0].typ == exports.EnumToken.AtRuleTokenType) { - if (tokens[0].nam != 'supports') { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting @supports or media query list', - tokens - }; - } - // @ts-ignore - const result = validateAtRuleSupports(tokens[0]); - if (result.valid == ValidationLevel.Drop) { - return result; - } + else { tokens.shift(); // @ts-ignore if (!consumeWhitespace(tokens)) { @@ -14862,7 +13364,108 @@ function validateAtRuleImport(atRule, options, root) { }; } } + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); + } + else { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@' + atRule.nam, + error: 'expecting url() or string', + tokens + }; + } + if (tokens.length > 0) { + // @ts-ignore + if (tokens[0].typ == exports.EnumToken.IdenTokenType) { + // @ts-ignore + if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0) { + tokens.shift(); + // @ts-ignore + if (!consumeWhitespace(tokens)) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@' + atRule.nam, + error: 'expecting whitespace', + tokens + }; + } + } + } + // @ts-ignore + else if (tokens[0].typ == exports.EnumToken.FunctionTokenType) { + // @ts-ignore + if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateLayerName(tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); + } + // @ts-ignore + if ('supports'.localeCompare(tokens[0]?.val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); + } + } } + // if (tokens.length > 0) { + // + // // @ts-ignore + // if (tokens[0].typ == EnumToken.AtRuleTokenType) { + // + // if ((tokens[0] as AstAtRule).nam != 'supports') { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting @supports or media query list', + // tokens + // } + // } + // + // // @ts-ignore + // const result: ValidationSyntaxResult = validateAtRuleSupports(tokens[0] as AstAtRule, options, atRule); + // + // if (result.valid == ValidationLevel.Drop) { + // + // return result; + // } + // + // tokens.shift(); + // + // // @ts-ignore + // if (!consumeWhitespace(tokens)) { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting whitespace', + // tokens + // } + // } + // } + // } if (tokens.length > 0) { return validateAtRuleMediaQueryList(tokens, atRule); } @@ -15031,71 +13634,50 @@ function validateAtRuleDocument(atRule, options, root) { tokens }; } - if (tokens[0].typ == exports.EnumToken.CommaTokenType) { + for (const t of splitTokenList(tokens)) { + if (t.length != 1) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'unexpected token', + tokens + }; + } // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - while (tokens.length > 0) { - if (tokens[0].typ == exports.EnumToken.CommentTokenType) { - tokens.shift(); - consumeWhitespace(tokens); + if ((t[0].typ != exports.EnumToken.FunctionTokenType && t[0].typ != exports.EnumToken.UrlFunctionTokenType) || !['url', 'url-prefix', 'domain', 'media-document', 'regexp'].some((f) => f.localeCompare(t[0].val, undefined, { sensitivity: 'base' }) == 0)) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'expecting any of url-prefix(), domain(), media-document(), regexp() but found ' + t[0].val, + tokens + }; } - result = validateURL(tokens[0]); - if (result.valid == ValidationLevel.Valid) { - tokens.shift(); - consumeWhitespace(tokens); + if (t[0].typ == exports.EnumToken.UrlFunctionTokenType) { + result = validateURL(t[0]); + if (result.valid == ValidationLevel.Drop) { + return result; + } continue; } - if (tokens[0].typ == exports.EnumToken.FunctionTokenType) { - if (!['url-prefix', 'domain', 'media-document', 'regexp'].some((t) => t.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - const children = tokens[0].chi.slice(); - consumeWhitespace(children); - if (children.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'expecting string argument', - tokens - }; - } - if (children[0].typ == exports.EnumToken.StringTokenType) { - children.shift(); - consumeWhitespace(children); - } - if (children.length > 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - tokens.shift(); - consumeWhitespace(tokens); + const children = t[0].chi.slice(); + consumeWhitespace(children); + if (children.length != 1 || (children[0].typ != exports.EnumToken.StringTokenType && children[0].typ != exports.EnumToken.UrlTokenTokenType)) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@document', + error: 'expecting string argument', + tokens + }; } + tokens.shift(); + consumeWhitespace(tokens); } // @ts-ignore return { @@ -16031,7 +14613,7 @@ async function doParse(iterator, options = {}) { await parseNode(tokens, context, stats, options, errors, src, map, rawTokens); rawTokens.length = 0; if (context != null && context.typ == exports.EnumToken.InvalidRuleTokenType) { - const index = context.chi.findIndex(node => node == context); + const index = context.chi.findIndex((node) => node == context); if (index > -1) { context.chi.splice(index, 1); } @@ -16195,8 +14777,13 @@ async function parseNode(results, context, stats, options, errors, src, map, raw continue; } if (type != exports.EnumToken.AtRuleNodeType) { - errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); - return null; + // @ts-ignore + if (!(type == exports.EnumToken.InvalidAtRuleTokenType && + // @ts-ignore + ['charset', 'layer', 'import'].includes(context.chi[i].nam))) { + errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); + return null; + } } // @ts-ignore const name = context.chi[i].nam; @@ -16231,12 +14818,20 @@ async function parseNode(results, context, stats, options, errors, src, map, raw if (tokens[0].typ == exports.EnumToken.UrlFunctionTokenType) { if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType || tokens[1].typ == exports.EnumToken.StringTokenType) { tokens.shift(); - if (tokens[1].typ == exports.EnumToken.UrlTokenTokenType) { + if (tokens[0]?.typ == exports.EnumToken.UrlTokenTokenType) { // @ts-ignore tokens[0].typ = exports.EnumToken.StringTokenType; // @ts-ignore tokens[0].val = `"${tokens[0].val}"`; } + // @ts-ignore + while (tokens[1]?.typ == exports.EnumToken.WhitespaceTokenType || tokens[1]?.typ == exports.EnumToken.CommentTokenType) { + tokens.splice(1, 1); + } + // @ts-ignore + if (tokens[1]?.typ == exports.EnumToken.EndParensTokenType) { + tokens.splice(1, 1); + } } } // @ts-ignore @@ -16550,7 +15145,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw // // const valid: ValidationResult = validateDeclaration(result, options, context); // - // console.error({valid}); + // // console.error({valid}); // // if (valid.valid == ValidationLevel.Drop) { // @@ -16924,7 +15519,7 @@ function getTokenType(val, hint) { } : ( // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - val.startsWith('::') || [':before', ':after', ':first-line', ':first-letter'].includes(val) ? { + val.startsWith('::') || pseudoElements.includes(val) ? { typ: exports.EnumToken.PseudoElementTokenType, val } : @@ -17108,25 +15703,25 @@ function parseTokens(tokens, options = {}) { break; } } - Object.assign(t, { + const attr = Object.assign(t, { typ: inAttr == 0 ? exports.EnumToken.AttrTokenType : exports.EnumToken.InvalidAttrTokenType, chi: tokens.splice(i + 1, k - i) }); // @ts-ignore - if (t.chi.at(-1).typ == exports.EnumToken.AttrEndTokenType) { + if (attr.chi.at(-1).typ == exports.EnumToken.AttrEndTokenType) { // @ts-ignore - t.chi.pop(); + attr.chi.pop(); } // @ts-ignore - if (t.chi.length > 1) { + if (attr.chi.length > 1) { /*(t).chi =*/ // @ts-ignore - parseTokens(t.chi, t.typ); + parseTokens(attr.chi, t.typ); } - let m = t.chi.length; + let m = attr.chi.length; let val; - for (m = 0; m < t.chi.length; m++) { - val = t.chi[m]; + for (m = 0; m < attr.chi.length; m++) { + val = attr.chi[m]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -17136,55 +15731,55 @@ function parseTokens(tokens, options = {}) { else if (val.typ == exports.EnumToken.LiteralTokenType && val.val == '|') { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == exports.EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == exports.EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == exports.EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == exports.EnumToken.CommentTokenType) { continue; } break; } // @ts-ignore - t.chi[m] = { + attr.chi[m] = { typ: exports.EnumToken.NameSpaceAttributeTokenType, - l: t.chi[lower], - r: t.chi[upper] + l: attr.chi[lower], + r: attr.chi[upper] }; - t.chi.splice(upper, 1); + attr.chi.splice(upper, 1); if (lower >= 0) { - t.chi.splice(lower, 1); + attr.chi.splice(lower, 1); m--; } } else if ([ exports.EnumToken.DashMatchTokenType, exports.EnumToken.StartMatchTokenType, exports.EnumToken.ContainMatchTokenType, exports.EnumToken.EndMatchTokenType, exports.EnumToken.IncludeMatchTokenType, exports.EnumToken.DelimTokenType - ].includes(t.chi[m].typ)) { + ].includes(attr.chi[m].typ)) { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == exports.EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == exports.EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == exports.EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == exports.EnumToken.CommentTokenType) { continue; } break; } - val = t.chi[lower]; + val = attr.chi[lower]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { Object.assign(val, { typ: exports.EnumToken.IdenTokenType, val: slice }); } } - val = t.chi[upper]; + val = attr.chi[upper]; if (val.typ == exports.EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -17304,7 +15899,9 @@ function parseTokens(tokens, options = {}) { t.typ = exports.EnumToken.ColorTokenType; // @ts-ignore t.kin = t.val; + // @ts-ignore if (t.chi[0].typ == exports.EnumToken.IdenTokenType) { + // @ts-ignore if (t.chi[0].val == 'from') { // @ts-ignore t.cal = 'rel'; @@ -17314,10 +15911,11 @@ function parseTokens(tokens, options = {}) { // @ts-ignore t.cal = 'mix'; } - else if (t.val == 'color') { - // @ts-ignore - t.cal = 'col'; - // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ)); + else { // @ts-ignore + if (t.val == 'color') { + // @ts-ignore + t.cal = 'col'; + } } } const filter = [exports.EnumToken.WhitespaceTokenType, exports.EnumToken.CommentTokenType]; @@ -17351,7 +15949,7 @@ function parseTokens(tokens, options = {}) { if (t.chi.length > 0) { if (t.typ == exports.EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) { // - const count = t.chi.filter(t => t.typ != exports.EnumToken.CommentTokenType).length; + const count = t.chi.filter((t) => t.typ != exports.EnumToken.CommentTokenType).length; if (count == 1 || (i == 0 && (tokens[i + 1]?.typ == exports.EnumToken.CommaTokenType || tokens.length == i + 1)) || @@ -17626,7 +16224,7 @@ function expandRule(node) { } else { // selRule = splitRule(selRule.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.join(''), '')); - const arSelf = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); + const arSelf = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); if (arSelf.length == 0) { ast.chi.splice(i--, 1); continue; @@ -17645,7 +16243,7 @@ function expandRule(node) { let withoutCompound = []; // pseudo elements cannot be used with '&' // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))); + const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))); const parentSelector = !node.sel.includes('&'); if (rules.length == 0) { ast.chi.splice(i--, 1); @@ -20129,106 +18727,6 @@ function reduceRuleSelector(node) { } } -const matchUrl = /^(https?:)?\/\//; -function dirname(path) { - if (path == '/' || path === '') { - return path; - } - let i = 0; - let parts = ['']; - for (; i < path.length; i++) { - const chr = path.charAt(i); - if (chr == '/') { - parts.push(''); - } - else if (chr == '?' || chr == '#') { - break; - } - else { - parts[parts.length - 1] += chr; - } - } - parts.pop(); - return parts.length == 0 ? '/' : parts.join('/'); -} -function splitPath(result) { - const parts = ['']; - let i = 0; - for (; i < result.length; i++) { - const chr = result.charAt(i); - if (chr == '/') { - parts.push(''); - } - else if (chr == '?' || chr == '#') { - break; - } - else { - parts[parts.length - 1] += chr; - } - } - let k = -1; - while (++k < parts.length) { - if (parts[k] == '.') { - parts.splice(k--, 1); - } - else if (parts[k] == '..') { - parts.splice(k - 1, 2); - k -= 2; - } - } - return { parts, i }; -} -function resolve(url, currentDirectory, cwd) { - if (matchUrl.test(url)) { - return { - absolute: url, - relative: url - }; - } - if (matchUrl.test(currentDirectory)) { - const path = new URL(url, currentDirectory).href; - return { - absolute: path, - relative: path - }; - } - let result; - if (url.charAt(0) == '/') { - result = url; - } - else if (currentDirectory.charAt(0) == '/') { - result = dirname(currentDirectory) + '/' + url; - } - else if (currentDirectory === '' || dirname(currentDirectory) === '') { - result = url; - } - else { - result = dirname(currentDirectory) + '/' + url; - } - let { parts, i } = splitPath(result); - if (parts.length == 0) { - const path = result.charAt(0) == '/' ? '/' : ''; - return { - absolute: path, - relative: path - }; - } - const absolute = parts.join('/'); - const { parts: dirs } = splitPath(cwd ?? currentDirectory); - for (const p of dirs) { - if (parts[0] == p) { - parts.shift(); - } - else { - parts.unshift('..'); - } - } - return { - absolute, - relative: parts.join('/') + (i < result.length ? result.slice(i) : '') - }; -} - function parseResponse(response) { if (!response.ok) { throw new Error(`${response.status} ${response.statusText} ${response.url}`); diff --git a/dist/lib/ast/expand.js b/dist/lib/ast/expand.js index 7f3e7649..bdd3e9ee 100644 --- a/dist/lib/ast/expand.js +++ b/dist/lib/ast/expand.js @@ -70,7 +70,7 @@ function expandRule(node) { } else { // selRule = splitRule(selRule.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.join(''), '')); - const arSelf = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); + const arSelf = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); if (arSelf.length == 0) { ast.chi.splice(i--, 1); continue; @@ -89,7 +89,7 @@ function expandRule(node) { let withoutCompound = []; // pseudo elements cannot be used with '&' // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))); + const rules = splitRule(ast.sel).filter((r) => r.every((t) => t != ':before' && t != ':after' && !t.startsWith('::'))); const parentSelector = !node.sel.includes('&'); if (rules.length == 0) { ast.chi.splice(i--, 1); diff --git a/dist/lib/parser/parse.js b/dist/lib/parser/parse.js index 989fb840..2023706b 100644 --- a/dist/lib/parser/parse.js +++ b/dist/lib/parser/parse.js @@ -1,4 +1,4 @@ -import { webkitPseudoAliasMap, isIdentStart, isIdent, mathFuncs, isColor, isHexColor, isPseudo, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHash, mediaTypes } from '../syntax/syntax.js'; +import { webkitPseudoAliasMap, isIdentStart, isIdent, mathFuncs, isColor, isHexColor, isPseudo, pseudoElements, isAtKeyword, isFunction, isNumber, isPercentage, isFlex, isDimension, parseDimension, isHash, mediaTypes } from '../syntax/syntax.js'; import './utils/config.js'; import { EnumToken, funcLike, ValidationLevel } from '../ast/types.js'; import { minify, definedPropertySettings, combinators } from '../ast/minify.js'; @@ -166,7 +166,7 @@ async function doParse(iterator, options = {}) { await parseNode(tokens, context, stats, options, errors, src, map, rawTokens); rawTokens.length = 0; if (context != null && context.typ == EnumToken.InvalidRuleTokenType) { - const index = context.chi.findIndex(node => node == context); + const index = context.chi.findIndex((node) => node == context); if (index > -1) { context.chi.splice(index, 1); } @@ -330,8 +330,13 @@ async function parseNode(results, context, stats, options, errors, src, map, raw continue; } if (type != EnumToken.AtRuleNodeType) { - errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); - return null; + // @ts-ignore + if (!(type == EnumToken.InvalidAtRuleTokenType && + // @ts-ignore + ['charset', 'layer', 'import'].includes(context.chi[i].nam))) { + errors.push({ action: 'drop', message: 'invalid @import', location: { src, ...position } }); + return null; + } } // @ts-ignore const name = context.chi[i].nam; @@ -366,12 +371,20 @@ async function parseNode(results, context, stats, options, errors, src, map, raw if (tokens[0].typ == EnumToken.UrlFunctionTokenType) { if (tokens[1].typ == EnumToken.UrlTokenTokenType || tokens[1].typ == EnumToken.StringTokenType) { tokens.shift(); - if (tokens[1].typ == EnumToken.UrlTokenTokenType) { + if (tokens[0]?.typ == EnumToken.UrlTokenTokenType) { // @ts-ignore tokens[0].typ = EnumToken.StringTokenType; // @ts-ignore tokens[0].val = `"${tokens[0].val}"`; } + // @ts-ignore + while (tokens[1]?.typ == EnumToken.WhitespaceTokenType || tokens[1]?.typ == EnumToken.CommentTokenType) { + tokens.splice(1, 1); + } + // @ts-ignore + if (tokens[1]?.typ == EnumToken.EndParensTokenType) { + tokens.splice(1, 1); + } } } // @ts-ignore @@ -685,7 +698,7 @@ async function parseNode(results, context, stats, options, errors, src, map, raw // // const valid: ValidationResult = validateDeclaration(result, options, context); // - // console.error({valid}); + // // console.error({valid}); // // if (valid.valid == ValidationLevel.Drop) { // @@ -1059,7 +1072,7 @@ function getTokenType(val, hint) { } : ( // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - val.startsWith('::') || [':before', ':after', ':first-line', ':first-letter'].includes(val) ? { + val.startsWith('::') || pseudoElements.includes(val) ? { typ: EnumToken.PseudoElementTokenType, val } : @@ -1243,25 +1256,25 @@ function parseTokens(tokens, options = {}) { break; } } - Object.assign(t, { + const attr = Object.assign(t, { typ: inAttr == 0 ? EnumToken.AttrTokenType : EnumToken.InvalidAttrTokenType, chi: tokens.splice(i + 1, k - i) }); // @ts-ignore - if (t.chi.at(-1).typ == EnumToken.AttrEndTokenType) { + if (attr.chi.at(-1).typ == EnumToken.AttrEndTokenType) { // @ts-ignore - t.chi.pop(); + attr.chi.pop(); } // @ts-ignore - if (t.chi.length > 1) { + if (attr.chi.length > 1) { /*(t).chi =*/ // @ts-ignore - parseTokens(t.chi, t.typ); + parseTokens(attr.chi, t.typ); } - let m = t.chi.length; + let m = attr.chi.length; let val; - for (m = 0; m < t.chi.length; m++) { - val = t.chi[m]; + for (m = 0; m < attr.chi.length; m++) { + val = attr.chi[m]; if (val.typ == EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -1271,55 +1284,55 @@ function parseTokens(tokens, options = {}) { else if (val.typ == EnumToken.LiteralTokenType && val.val == '|') { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == EnumToken.CommentTokenType) { continue; } break; } // @ts-ignore - t.chi[m] = { + attr.chi[m] = { typ: EnumToken.NameSpaceAttributeTokenType, - l: t.chi[lower], - r: t.chi[upper] + l: attr.chi[lower], + r: attr.chi[upper] }; - t.chi.splice(upper, 1); + attr.chi.splice(upper, 1); if (lower >= 0) { - t.chi.splice(lower, 1); + attr.chi.splice(lower, 1); m--; } } else if ([ EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType, EnumToken.DelimTokenType - ].includes(t.chi[m].typ)) { + ].includes(attr.chi[m].typ)) { let upper = m; let lower = m; - while (++upper < t.chi.length) { - if (t.chi[upper].typ == EnumToken.CommentTokenType) { + while (++upper < attr.chi.length) { + if (attr.chi[upper].typ == EnumToken.CommentTokenType) { continue; } break; } while (lower-- > 0) { - if (t.chi[lower].typ == EnumToken.CommentTokenType) { + if (attr.chi[lower].typ == EnumToken.CommentTokenType) { continue; } break; } - val = t.chi[lower]; + val = attr.chi[lower]; if (val.typ == EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { Object.assign(val, { typ: EnumToken.IdenTokenType, val: slice }); } } - val = t.chi[upper]; + val = attr.chi[upper]; if (val.typ == EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); if ((slice.charAt(0) != '-' || (slice.charAt(0) == '-' && isIdentStart(slice.charCodeAt(1)))) && isIdent(slice)) { @@ -1439,7 +1452,9 @@ function parseTokens(tokens, options = {}) { t.typ = EnumToken.ColorTokenType; // @ts-ignore t.kin = t.val; + // @ts-ignore if (t.chi[0].typ == EnumToken.IdenTokenType) { + // @ts-ignore if (t.chi[0].val == 'from') { // @ts-ignore t.cal = 'rel'; @@ -1449,10 +1464,11 @@ function parseTokens(tokens, options = {}) { // @ts-ignore t.cal = 'mix'; } - else if (t.val == 'color') { - // @ts-ignore - t.cal = 'col'; - // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ)); + else { // @ts-ignore + if (t.val == 'color') { + // @ts-ignore + t.cal = 'col'; + } } } const filter = [EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType]; @@ -1486,7 +1502,7 @@ function parseTokens(tokens, options = {}) { if (t.chi.length > 0) { if (t.typ == EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) { // - const count = t.chi.filter(t => t.typ != EnumToken.CommentTokenType).length; + const count = t.chi.filter((t) => t.typ != EnumToken.CommentTokenType).length; if (count == 1 || (i == 0 && (tokens[i + 1]?.typ == EnumToken.CommaTokenType || tokens.length == i + 1)) || diff --git a/dist/lib/renderer/color/color.js b/dist/lib/renderer/color/color.js index f4298178..a1d39304 100644 --- a/dist/lib/renderer/color/color.js +++ b/dist/lib/renderer/color/color.js @@ -15,9 +15,9 @@ import { xyz2srgb, lsrgb2srgbvalues, srgb2lsrgbvalues, lch2srgb, oklab2srgb, lab import { prophotorgb2srgbvalues, srgb2prophotorgbvalues } from './prophotorgb.js'; import { a98rgb2srgbvalues, srgb2a98values } from './a98rgb.js'; import { rec20202srgb, srgb2rec2020values } from './rec2020.js'; -import { xyzd502srgb, srgb2xyz } from './xyz.js'; +import { srgb2xyz } from './xyz.js'; import { p32srgbvalues, srgb2p3values } from './p3.js'; -import { XYZ_D65_to_D50 } from './xyzd50.js'; +import { xyzd502srgb, XYZ_D65_to_D50 } from './xyzd50.js'; import '../sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; diff --git a/dist/lib/renderer/color/lab.js b/dist/lib/renderer/color/lab.js index 3df9a0e3..be79f797 100644 --- a/dist/lib/renderer/color/lab.js +++ b/dist/lib/renderer/color/lab.js @@ -1,6 +1,6 @@ import { e, k, D50 } from './utils/constants.js'; import { getComponents } from './utils/components.js'; -import { srgb2xyz, xyzd502srgb } from './xyz.js'; +import { srgb2xyz } from './xyz.js'; import { oklch2srgb, hwb2srgb, hsl2srgb, rgb2srgb, hex2srgb } from './srgb.js'; import { getLCHComponents } from './lch.js'; import { OKLab_to_XYZ, getOKLABComponents } from './oklab.js'; @@ -9,6 +9,7 @@ import { EnumToken } from '../../ast/types.js'; import '../../ast/minify.js'; import '../../ast/walk.js'; import '../../parser/parse.js'; +import { xyzd502srgb } from './xyzd50.js'; import '../sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; diff --git a/dist/lib/renderer/color/prophotoRgb.js b/dist/lib/renderer/color/prophotoRgb.js index 73a87466..f11819ff 100644 --- a/dist/lib/renderer/color/prophotoRgb.js +++ b/dist/lib/renderer/color/prophotoRgb.js @@ -1,5 +1,5 @@ -import { srgb2xyz, xyzd502srgb } from './xyz.js'; -import { XYZ_D65_to_D50 } from './xyzd50.js'; +import { srgb2xyz } from './xyz.js'; +import { XYZ_D65_to_D50, xyzd502srgb } from './xyzd50.js'; function prophotorgb2srgbvalues(r, g, b, a = null) { // @ts-ignore diff --git a/dist/lib/renderer/color/prophotorgb.js b/dist/lib/renderer/color/prophotorgb.js index 73a87466..f11819ff 100644 --- a/dist/lib/renderer/color/prophotorgb.js +++ b/dist/lib/renderer/color/prophotorgb.js @@ -1,5 +1,5 @@ -import { srgb2xyz, xyzd502srgb } from './xyz.js'; -import { XYZ_D65_to_D50 } from './xyzd50.js'; +import { srgb2xyz } from './xyz.js'; +import { XYZ_D65_to_D50, xyzd502srgb } from './xyzd50.js'; function prophotorgb2srgbvalues(r, g, b, a = null) { // @ts-ignore diff --git a/dist/lib/renderer/color/xyz.js b/dist/lib/renderer/color/xyz.js index 6c3e0a5d..9c68d10e 100644 --- a/dist/lib/renderer/color/xyz.js +++ b/dist/lib/renderer/color/xyz.js @@ -4,26 +4,10 @@ import '../../ast/types.js'; import '../../ast/minify.js'; import '../../ast/walk.js'; import '../../parser/parse.js'; -import { srgb2lsrgbvalues, lsrgb2srgbvalues } from './srgb.js'; +import { srgb2lsrgbvalues } from './srgb.js'; import '../sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; -function xyzd502srgb(x, y, z) { - // @ts-ignore - return lsrgb2srgbvalues( - /* r: */ - x * 3.1341359569958707 - - y * 1.6173863321612538 - - 0.4906619460083532 * z, - /* g: */ - x * -0.978795502912089 + - y * 1.916254567259524 + - 0.03344273116131949 * z, - /* b: */ - x * 0.07195537988411677 - - y * 0.2289768264158322 + - 1.405386058324125 * z); -} function XYZ_to_lin_sRGB(x, y, z) { // convert XYZ to linear-light sRGB const M = [ @@ -63,4 +47,4 @@ function srgb2xyz(r, g, b, alpha) { return rgb; } -export { XYZ_D50_to_D65, XYZ_to_lin_sRGB, srgb2xyz, xyzd502srgb }; +export { XYZ_D50_to_D65, XYZ_to_lin_sRGB, srgb2xyz }; diff --git a/dist/lib/renderer/color/xyzd50.js b/dist/lib/renderer/color/xyzd50.js index ac436db6..4f5a8a71 100644 --- a/dist/lib/renderer/color/xyzd50.js +++ b/dist/lib/renderer/color/xyzd50.js @@ -1,3 +1,4 @@ +import { lsrgb2srgbvalues } from './srgb.js'; import { multiplyMatrices } from './utils/matrix.js'; import './utils/constants.js'; import '../../ast/types.js'; @@ -10,11 +11,12 @@ import { XYZ_D50_to_D65 } from './xyz.js'; import '../sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; +/* +*/ function xyzd502lch(x, y, z, alpha) { // @ts-ignore const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); // L in range [0,100]. For use in CSS, add a percent - // @ts-ignore return lab2lchvalues(l, a, b, alpha); } function XYZ_D65_to_D50(x, y, z) { @@ -31,5 +33,21 @@ function XYZ_D65_to_D50(x, y, z) { ]; return multiplyMatrices(M, [x, y, z]); } +function xyzd502srgb(x, y, z) { + // @ts-ignore + return lsrgb2srgbvalues( + /* r: */ + x * 3.1341359569958707 - + y * 1.6173863321612538 - + 0.4906619460083532 * z, + /* g: */ + x * -0.978795502912089 + + y * 1.916254567259524 + + 0.03344273116131949 * z, + /* b: */ + x * 0.07195537988411677 - + y * 0.2289768264158322 + + 1.405386058324125 * z); +} -export { XYZ_D65_to_D50, xyzd502lch }; +export { XYZ_D65_to_D50, xyzd502lch, xyzd502srgb }; diff --git a/dist/lib/renderer/render.js b/dist/lib/renderer/render.js index 03c72a9d..78a5dcc3 100644 --- a/dist/lib/renderer/render.js +++ b/dist/lib/renderer/render.js @@ -9,7 +9,7 @@ import { expand } from '../ast/expand.js'; import { colorMix } from './color/colormix.js'; import { parseRelativeColor } from './color/relativecolor.js'; import { SourceMap } from './sourcemap/sourcemap.js'; -import { isColor, mathFuncs, isNewLine } from '../syntax/syntax.js'; +import { isColor, pseudoElements, mathFuncs, isNewLine } from '../syntax/syntax.js'; const colorsFunc = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark']; function reduceNumber(val) { @@ -591,7 +591,7 @@ function renderToken(token, options = {}, cache = Object.create(null), reducer, case EnumToken.PseudoClassTokenType: case EnumToken.PseudoElementTokenType: // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == EnumToken.PseudoElementTokenType && ['::before', '::after', '::first-line', '::first-letter'].includes(token.val)) { + if (token.typ == EnumToken.PseudoElementTokenType && pseudoElements.includes(token.val.slice(1))) { return token.val.slice(1); } case EnumToken.UrlTokenTokenType: diff --git a/dist/lib/renderer/sourcemap/sourcemap.js b/dist/lib/renderer/sourcemap/sourcemap.js index ab8ba5df..d6bd6dde 100644 --- a/dist/lib/renderer/sourcemap/sourcemap.js +++ b/dist/lib/renderer/sourcemap/sourcemap.js @@ -1,11 +1,11 @@ import { encode } from './lib/encode.js'; class SourceMap { + lastLocation = null; #version = 3; #sources = []; #map = new Map; #line = -1; - lastLocation = null; add(source, original) { if (original.src !== '') { if (!this.#sources.includes(original.src)) { diff --git a/dist/lib/syntax/syntax.js b/dist/lib/syntax/syntax.js index 0e813550..0b219a21 100644 --- a/dist/lib/syntax/syntax.js +++ b/dist/lib/syntax/syntax.js @@ -25,6 +25,7 @@ const mediaTypes = ['all', 'print', 'screen', 'aural', 'braille', 'embossed', 'handheld', 'projection', 'tty', 'tv', 'speech']; // https://www.w3.org/TR/css-values-4/#math-function const mathFuncs = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign']; +const pseudoElements = [':before', ':after', ':first-line', ':first-letter']; const webkitPseudoAliasMap = { '-webkit-autofill': 'autofill', '-webkit-any': 'is', @@ -811,4 +812,4 @@ function isWhiteSpace(codepoint) { codepoint == 0xa || codepoint == 0xc || codepoint == 0xd; } -export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseDimension, webkitExtensions, webkitPseudoAliasMap }; +export { colorFontTech, fontFeaturesTech, fontFormat, isAngle, isAtKeyword, isColor, isColorspace, isDigit, isDimension, isFlex, isFrequency, isFunction, isHash, isHexColor, isHueInterpolationMethod, isIdent, isIdentCodepoint, isIdentStart, isLength, isNewLine, isNonPrintable, isNumber, isPercentage, isPolarColorspace, isPseudo, isRectangularOrthogonalColorspace, isResolution, isTime, isWhiteSpace, mathFuncs, mediaTypes, mozExtensions, parseDimension, pseudoElements, webkitExtensions, webkitPseudoAliasMap }; diff --git a/dist/lib/validation/at-rules/document.js b/dist/lib/validation/at-rules/document.js index 9ab02f54..4cd2b0bc 100644 --- a/dist/lib/validation/at-rules/document.js +++ b/dist/lib/validation/at-rules/document.js @@ -6,6 +6,7 @@ import '../../renderer/color/utils/constants.js'; import '../../renderer/sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; import { consumeWhitespace } from '../utils/whitespace.js'; +import { splitTokenList } from '../utils/list.js'; import { validateURL } from '../syntaxes/url.js'; function validateAtRuleDocument(atRule, options, root) { @@ -34,71 +35,50 @@ function validateAtRuleDocument(atRule, options, root) { tokens }; } - if (tokens[0].typ == EnumToken.CommaTokenType) { + for (const t of splitTokenList(tokens)) { + if (t.length != 1) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'unexpected token', + tokens + }; + } // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - while (tokens.length > 0) { - if (tokens[0].typ == EnumToken.CommentTokenType) { - tokens.shift(); - consumeWhitespace(tokens); + if ((t[0].typ != EnumToken.FunctionTokenType && t[0].typ != EnumToken.UrlFunctionTokenType) || !['url', 'url-prefix', 'domain', 'media-document', 'regexp'].some((f) => f.localeCompare(t[0].val, undefined, { sensitivity: 'base' }) == 0)) { + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'expecting any of url-prefix(), domain(), media-document(), regexp() but found ' + t[0].val, + tokens + }; } - result = validateURL(tokens[0]); - if (result.valid == ValidationLevel.Valid) { - tokens.shift(); - consumeWhitespace(tokens); + if (t[0].typ == EnumToken.UrlFunctionTokenType) { + result = validateURL(t[0]); + if (result.valid == ValidationLevel.Drop) { + return result; + } continue; } - if (tokens[0].typ == EnumToken.FunctionTokenType) { - if (!['url-prefix', 'domain', 'media-document', 'regexp'].some((t) => t.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - const children = tokens[0].chi.slice(); - consumeWhitespace(children); - if (children.length == 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'expecting string argument', - tokens - }; - } - if (children[0].typ == EnumToken.StringTokenType) { - children.shift(); - consumeWhitespace(children); - } - if (children.length > 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0], - syntax: '@document', - error: 'unexpected token', - tokens - }; - } - tokens.shift(); - consumeWhitespace(tokens); + const children = t[0].chi.slice(); + consumeWhitespace(children); + if (children.length != 1 || (children[0].typ != EnumToken.StringTokenType && children[0].typ != EnumToken.UrlTokenTokenType)) { + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@document', + error: 'expecting string argument', + tokens + }; } + tokens.shift(); + consumeWhitespace(tokens); } // @ts-ignore return { diff --git a/dist/lib/validation/at-rules/import.js b/dist/lib/validation/at-rules/import.js index 5ee98dd6..511936be 100644 --- a/dist/lib/validation/at-rules/import.js +++ b/dist/lib/validation/at-rules/import.js @@ -5,7 +5,6 @@ import '../../parser/parse.js'; import '../../renderer/color/utils/constants.js'; import '../../renderer/sourcemap/lib/encode.js'; import '../../parser/utils/config.js'; -import { validateAtRuleSupports } from './supports.js'; import { validateAtRuleMediaQueryList } from './media.js'; import { consumeWhitespace } from '../utils/whitespace.js'; import { validateLayerName } from '../syntaxes/layer-name.js'; @@ -13,6 +12,7 @@ import '../syntaxes/complex-selector.js'; import '../parser/types.js'; import '../parser/parse.js'; import '../config.js'; +import { validateAtRuleSupportsConditions } from './supports.js'; function validateAtRuleImport(atRule, options, root) { if (!Array.isArray(atRule.tokens) || atRule.tokens.length == 0) { @@ -82,6 +82,9 @@ function validateAtRuleImport(atRule, options, root) { }; } } + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); } else { // @ts-ignore @@ -117,71 +120,70 @@ function validateAtRuleImport(atRule, options, root) { // @ts-ignore else if (tokens[0].typ == EnumToken.FunctionTokenType) { // @ts-ignore - if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) != 0) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting layer()', - tokens - }; - } - // @ts-ignore - const result = validateLayerName(tokens[0].chi); - if (result.valid == ValidationLevel.Drop) { - return result; - } - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; - } - } - } - if (tokens.length > 0) { - // @ts-ignore - if (tokens[0].typ == EnumToken.AtRuleTokenType) { - if (tokens[0].nam != 'supports') { + if ('layer'.localeCompare(tokens[0].val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateLayerName(tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting @supports or media query list', - tokens - }; + consumeWhitespace(tokens); } // @ts-ignore - const result = validateAtRuleSupports(tokens[0]); - if (result.valid == ValidationLevel.Drop) { - return result; - } - tokens.shift(); - // @ts-ignore - if (!consumeWhitespace(tokens)) { + if ('supports'.localeCompare(tokens[0]?.val, undefined, { sensitivity: 'base' }) == 0) { + const result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if (result.valid == ValidationLevel.Drop) { + return result; + } + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - }; + consumeWhitespace(tokens); } } } + // if (tokens.length > 0) { + // + // // @ts-ignore + // if (tokens[0].typ == EnumToken.AtRuleTokenType) { + // + // if ((tokens[0] as AstAtRule).nam != 'supports') { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting @supports or media query list', + // tokens + // } + // } + // + // // @ts-ignore + // const result: ValidationSyntaxResult = validateAtRuleSupports(tokens[0] as AstAtRule, options, atRule); + // + // if (result.valid == ValidationLevel.Drop) { + // + // return result; + // } + // + // tokens.shift(); + // + // // @ts-ignore + // if (!consumeWhitespace(tokens)) { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting whitespace', + // tokens + // } + // } + // } + // } if (tokens.length > 0) { return validateAtRuleMediaQueryList(tokens, atRule); } diff --git a/dist/lib/validation/at-rules/media.js b/dist/lib/validation/at-rules/media.js index 8f7de66f..a041a7fd 100644 --- a/dist/lib/validation/at-rules/media.js +++ b/dist/lib/validation/at-rules/media.js @@ -225,7 +225,7 @@ function validateMediaCondition(token, atRule) { if (token.typ == EnumToken.MediaFeatureNotTokenType) { return validateMediaCondition(token.val, atRule); } - if (token.typ != EnumToken.ParensTokenType && !(['when', 'else'].includes(atRule.nam) && token.typ == EnumToken.FunctionTokenType && ['media', 'supports'].includes(token.val))) { + if (token.typ != EnumToken.ParensTokenType && !(['when', 'else', 'import'].includes(atRule.nam) && token.typ == EnumToken.FunctionTokenType && ['media', 'supports', 'selector'].includes(token.val))) { return false; } const chi = token.chi.filter((t) => t.typ != EnumToken.CommentTokenType && t.typ != EnumToken.WhitespaceTokenType); @@ -241,6 +241,7 @@ function validateMediaCondition(token, atRule) { if (chi[0].typ == EnumToken.MediaQueryConditionTokenType) { return chi[0].l.typ == EnumToken.IdenTokenType; } + console.error(chi[0].parent); return false; } function validateMediaFeature(token) { diff --git a/dist/lib/validation/at-rules/supports.js b/dist/lib/validation/at-rules/supports.js index f6797492..ce7f3d11 100644 --- a/dist/lib/validation/at-rules/supports.js +++ b/dist/lib/validation/at-rules/supports.js @@ -1,15 +1,14 @@ import { ValidationLevel, EnumToken } from '../../ast/types.js'; import '../../ast/minify.js'; import '../../ast/walk.js'; -import '../../parser/parse.js'; +import { parseSelector } from '../../parser/parse.js'; import { colorFontTech, fontFeaturesTech, fontFormat } from '../../syntax/syntax.js'; import '../../parser/utils/config.js'; import '../../renderer/color/utils/constants.js'; import '../../renderer/sourcemap/lib/encode.js'; import { consumeWhitespace } from '../utils/whitespace.js'; import { splitTokenList } from '../utils/list.js'; -import { validateSyntax } from '../syntax.js'; -import { getParsedSyntax } from '../config.js'; +import { validateComplexSelector } from '../syntaxes/complex-selector.js'; function validateAtRuleSupports(atRule, options, root) { // media-query-list @@ -53,6 +52,7 @@ function validateAtRuleSupports(atRule, options, root) { }; } function validateAtRuleSupportsConditions(atRule, tokenList) { + let result = null; for (const tokens of splitTokenList(tokenList)) { if (tokens.length == 0) { // @ts-ignore @@ -66,22 +66,46 @@ function validateAtRuleSupportsConditions(atRule, tokenList) { }; } let previousToken = null; - let result = null; while (tokens.length > 0) { result = validateSupportCondition(atRule, tokens[0]); // supports-condition - if (result == null || result.valid == ValidationLevel.Valid) { + if (result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { result = validateSupportFeature(tokens[0]); - if (result == null || result.valid == ValidationLevel.Valid) { + if ( /*result == null || */result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { - return result; + if (tokens[0].typ == EnumToken.ParensTokenType) { + result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + if ( /* result == null || */result.valid == ValidationLevel.Valid) { + previousToken = tokens[0]; + tokens.shift(); + // continue; + } + else { + return result; + } + } + else { + return result; + } + // if (result!= null && result.valid == ValidationLevel.Drop) { + // + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0] ?? atRule, + // syntax: '@' + atRule.nam, + // // @ts-ignore + // error: result.error as string ?? 'unexpected token', + // tokens: [] + // }; + // } } } if (tokens.length == 0) { @@ -136,7 +160,14 @@ function validateAtRuleSupportsConditions(atRule, tokenList) { } } } - return null; + return { + valid: ValidationLevel.Valid, + matches: [], + node: atRule, + syntax: '@' + atRule.nam, + error: '', + tokens: [] + }; } function validateSupportCondition(atRule, token) { if (token.typ == EnumToken.MediaFeatureNotTokenType) { @@ -203,7 +234,7 @@ function validateSupportCondition(atRule, token) { function validateSupportFeature(token) { if (token.typ == EnumToken.FunctionTokenType) { if (token.val.localeCompare('selector', undefined, { sensitivity: 'base' }) == 0) { - return validateSyntax(getParsedSyntax("syntaxes" /* ValidationSyntaxGroupEnum.Syntaxes */, 'complex-selector'), token.chi); + return validateComplexSelector(parseSelector(token.chi)); } if (token.val.localeCompare('font-tech', undefined, { sensitivity: 'base' }) == 0) { const chi = token.chi.filter((t) => ![EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ)); diff --git a/dist/lib/validation/config.json.js b/dist/lib/validation/config.json.js index 92915d39..5bc6a250 100644 --- a/dist/lib/validation/config.json.js +++ b/dist/lib/validation/config.json.js @@ -372,7 +372,7 @@ var declarations = { syntax: "auto || " }, "backdrop-filter": { - syntax: "none | " + syntax: "none | " }, "backface-visibility": { syntax: "visible | hidden" @@ -786,7 +786,7 @@ var declarations = { syntax: "nonzero | evenodd" }, filter: { - syntax: "none | " + syntax: "none | " }, flex: { syntax: "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]" @@ -1242,7 +1242,7 @@ var declarations = { syntax: "" }, outline: { - syntax: "[ <'outline-width'> || <'outline-style'> || <'outline-color'> ]" + syntax: "<'outline-width'> || <'outline-style'> || <'outline-color'>" }, "outline-color": { syntax: "auto | " @@ -1671,7 +1671,7 @@ var declarations = { syntax: "space-all | normal | space-first | trim-start" }, "text-transform": { - syntax: "none | capitalize | uppercase | lowercase | full-width | full-size-kana" + syntax: "none | [ capitalize | uppercase | lowercase ] || full-width || full-size-kana | math-auto" }, "text-underline-offset": { syntax: "auto | | " @@ -1761,7 +1761,7 @@ var declarations = { syntax: "visible | hidden | collapse" }, "white-space": { - syntax: "normal | pre | nowrap | pre-wrap | pre-line | break-spaces | [ <'white-space-collapse'> || <'text-wrap'> ]" + syntax: "normal | pre | pre-wrap | pre-line | <'white-space-collapse'> || <'text-wrap-mode'>" }, "white-space-collapse": { syntax: "collapse | preserve | preserve-breaks | preserve-spaces | break-spaces" @@ -1797,7 +1797,7 @@ var declarations = { syntax: "auto | " }, zoom: { - syntax: "normal | reset | | " + syntax: "normal | reset | || " } }; var functions = { @@ -1838,7 +1838,7 @@ var functions = { syntax: "calc-size( , )" }, circle: { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, clamp: { syntax: "clamp( #{3} )" @@ -1874,7 +1874,7 @@ var functions = { syntax: "element( )" }, ellipse: { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, env: { syntax: "env( , ? )" @@ -1889,16 +1889,16 @@ var functions = { syntax: "grayscale( [ | ]? )" }, hsl: { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hsla: { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hue-rotate": { syntax: "hue-rotate( [ | ]? )" }, hwb: { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hypot: { syntax: "hypot( # )" @@ -1987,6 +1987,9 @@ var functions = { ray: { syntax: "ray( && ? && contain? && [at ]? )" }, + rect: { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, rem: { syntax: "rem( , )" }, @@ -2000,10 +2003,10 @@ var functions = { syntax: "repeating-radial-gradient( [ || ]? [ at ]? , )" }, rgb: { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, rgba: { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, rotate: { syntax: "rotate( [ | ] )" @@ -2065,6 +2068,9 @@ var functions = { sqrt: { syntax: "sqrt( )" }, + symbols: { + syntax: "symbols( ? [ | ]+ )" + }, tan: { syntax: "tan( )" }, @@ -2097,6 +2103,9 @@ var functions = { }, view: { syntax: "view([ || <'view-timeline-inset'>]?)" + }, + xywh: { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" } }; var syntaxes = { @@ -2112,6 +2121,9 @@ var syntaxes = { "alpha-value": { syntax: " | " }, + "an+b": { + syntax: "odd | even | | | '+'?† n | -n | | '+'?† | | | '+'?† n | -n | | '+'?† n- | -n- | ['+' | '-'] | '+'?† n ['+' | '-'] | -n ['+' | '-'] " + }, "anchor()": { syntax: "anchor( ? && , ? )" }, @@ -2233,7 +2245,7 @@ var syntaxes = { syntax: "? && " }, "circle()": { - syntax: "circle( [ ]? [ at ]? )" + syntax: "circle( ? [ at ]? )" }, "clamp()": { syntax: "clamp( #{3} )" @@ -2247,15 +2259,15 @@ var syntaxes = { color: { syntax: " | currentColor | | | " }, + "color()": { + syntax: "color( [ from ]? [ / [ | none ] ]? )" + }, "color-base": { syntax: " | | | | transparent" }, "color-function": { syntax: " | | | | | | | | | " }, - "color()": { - syntax: "color( [from ]? [ / [ | none ] ]? )" - }, "color-interpolation-method": { syntax: "in [ | ? | ]" }, @@ -2364,6 +2376,9 @@ var syntaxes = { dasharray: { syntax: "[ [ | ]+ ]#" }, + "dashndashdigit-ident": { + syntax: "" + }, "deprecated-system-color": { syntax: "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonHighlight | ButtonShadow | CaptionText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, @@ -2404,7 +2419,7 @@ var syntaxes = { syntax: "element( )" }, "ellipse()": { - syntax: "ellipse( [ {2} ]? [ at ]? )" + syntax: "ellipse( ? [ at ]? )" }, "ending-shape": { syntax: "circle | ellipse" @@ -2445,7 +2460,7 @@ var syntaxes = { "filter-function": { syntax: " | | | | | | | | | " }, - "filter-function-list": { + "filter-value-list": { syntax: "[ | ]+" }, "final-bg-layer": { @@ -2500,10 +2515,10 @@ var syntaxes = { syntax: "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { - syntax: "hsl( [ / ]? ) | hsl( , , , ? )" + syntax: "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hsla()": { - syntax: "hsla( [ / ]? ) | hsla( , , , ? )" + syntax: "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, hue: { syntax: " | " @@ -2515,7 +2530,7 @@ var syntaxes = { syntax: "hue-rotate( [ | ]? )" }, "hwb()": { - syntax: "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + syntax: "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hypot()": { syntax: "hypot( # )" @@ -2523,6 +2538,9 @@ var syntaxes = { "id-selector": { syntax: "" }, + integer: { + syntax: "" + }, image: { syntax: " | | | | | | " }, @@ -2688,6 +2706,18 @@ var syntaxes = { "mod()": { syntax: "mod( , )" }, + "n-dimension": { + syntax: "" + }, + "ndash-dimension": { + syntax: "" + }, + "ndashdigit-dimension": { + syntax: "" + }, + "ndashdigit-ident": { + syntax: "" + }, "name-repeat": { syntax: "repeat( [ | auto-fill ], + )" }, @@ -2700,9 +2730,6 @@ var syntaxes = { "ns-prefix": { syntax: "[ | '*' ]? '|'" }, - nth: { - syntax: " | even | odd" - }, "number-percentage": { syntax: " | " }, @@ -2811,9 +2838,15 @@ var syntaxes = { quote: { syntax: "open-quote | close-quote | no-open-quote | no-close-quote" }, + "radial-extent": { + syntax: "closest-corner | closest-side | farthest-corner | farthest-side" + }, "radial-gradient()": { syntax: "radial-gradient( [ || ]? [ at ]? , )" }, + "radial-size": { + syntax: " | | {2}" + }, ratio: { syntax: " [ / ]?" }, @@ -2835,6 +2868,9 @@ var syntaxes = { "relative-size": { syntax: "larger | smaller" }, + "rect()": { + syntax: "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, "rem()": { syntax: "rem( , )" }, @@ -2854,10 +2890,10 @@ var syntaxes = { syntax: "reversed( )" }, "rgb()": { - syntax: "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + syntax: "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, "rgba()": { - syntax: "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + syntax: "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, "rotate()": { syntax: "rotate( [ | ] )" @@ -2931,15 +2967,18 @@ var syntaxes = { "shape-box": { syntax: " | margin-box" }, - "shape-radius": { - syntax: " | closest-side | farthest-side" - }, "side-or-corner": { syntax: "[ left | right ] || [ top | bottom ]" }, "sign()": { syntax: "sign( )" }, + "signed-integer": { + syntax: "" + }, + "signless-integer": { + syntax: "" + }, "sin()": { syntax: "sin( )" }, @@ -3012,6 +3051,12 @@ var syntaxes = { symbol: { syntax: " | | " }, + "symbols()": { + syntax: "symbols( ? [ | ]+ )" + }, + "symbols-type": { + syntax: "cyclic | numeric | alphabetic | symbolic | fixed" + }, "system-color": { syntax: "AccentColor | AccentColorText | ActiveText | ButtonBorder | ButtonFace | ButtonText | Canvas | CanvasText | Field | FieldText | GrayText | Highlight | HighlightText | LinkText | Mark | MarkText | SelectedItem | SelectedItemText | VisitedText" }, @@ -3102,6 +3147,9 @@ var syntaxes = { "wq-name": { syntax: "? " }, + "xywh()": { + syntax: "xywh( {2} {2} [ round <'border-radius'> ]? )" + }, xyz: { syntax: "xyz | xyz-d50 | xyz-d65" }, @@ -3237,16 +3285,16 @@ var selectors = { syntax: ":not( )" }, ":nth-child()": { - syntax: ":nth-child( [ of ]? )" + syntax: ":nth-child( [ of ]? )" }, ":nth-last-child()": { - syntax: ":nth-last-child( [ of ]? )" + syntax: ":nth-last-child( [ of ]? )" }, ":nth-last-of-type()": { - syntax: ":nth-last-of-type( )" + syntax: ":nth-last-of-type( )" }, ":nth-of-type()": { - syntax: ":nth-of-type( )" + syntax: ":nth-of-type( )" }, ":only-child": { syntax: ":only-child" @@ -3529,7 +3577,7 @@ var atRules = { syntax: "normal | " }, "font-display": { - syntax: "[ auto | block | swap | fallback | optional ]" + syntax: "auto | block | swap | fallback | optional" }, "font-family": { syntax: "" diff --git a/dist/lib/validation/declaration.js b/dist/lib/validation/declaration.js index 95aa34a2..3e435937 100644 --- a/dist/lib/validation/declaration.js +++ b/dist/lib/validation/declaration.js @@ -5,7 +5,7 @@ import '../parser/parse.js'; import '../renderer/color/utils/constants.js'; import '../renderer/sourcemap/lib/encode.js'; import '../parser/utils/config.js'; -import { getParsedSyntax, getSyntaxConfig } from './config.js'; +import { getSyntaxConfig, getParsedSyntax } from './config.js'; import { validateSyntax } from './syntax.js'; function validateDeclaration(declaration, options, root) { @@ -23,7 +23,6 @@ function validateDeclaration(declaration, options, root) { if (root?.typ == EnumToken.AtRuleNodeType) { // const syntax = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, '@' + root.nam)?.[0]; - // console.error({syntax}); if (syntax != null) { if (!('chi' in syntax)) { return { @@ -52,7 +51,7 @@ function validateDeclaration(declaration, options, root) { valid: ValidationLevel.Drop, node: declaration, syntax: `<${declaration.nam}>`, - error: ` declaration <${declaration.nam}> is not allowed in <@${root.nam}>` + error: `declaration <${declaration.nam}> is not allowed in <@${root.nam}>` }; } const syntax = getParsedSyntax("atRules" /* ValidationSyntaxGroupEnum.AtRules */, ['@' + root.nam, 'descriptors', name]); @@ -89,13 +88,6 @@ function validateDeclaration(declaration, options, root) { error: `unknown declaration "${declaration.nam}"` }; } - // return { - // - // valid: ValidationLevel.Valid, - // node: declaration, - // syntax: null, - // error: '' - // } return validateSyntax(getParsedSyntax("declarations" /* ValidationSyntaxGroupEnum.Declarations */, name), declaration.val); } diff --git a/dist/lib/validation/parser/parse.js b/dist/lib/validation/parser/parse.js index 2e089bfa..74ee3288 100644 --- a/dist/lib/validation/parser/parse.js +++ b/dist/lib/validation/parser/parse.js @@ -949,100 +949,6 @@ function move(position, chr) { } return position; } -function renderSyntax(token, parent) { - let glue; - switch (token.typ) { - case ValidationTokenEnum.Root: - return token.chi.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Whitespace: - return ' '; - case ValidationTokenEnum.ValidationFunctionDefinition: - return '<' + token.val + '()>'; - case ValidationTokenEnum.HashMark: - return '#'; - case ValidationTokenEnum.Pipe: - return '|'; - case ValidationTokenEnum.Column: - return '||'; - case ValidationTokenEnum.PipeToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '|' : '') + curr.reduce((acc, curr) => acc + renderSyntax(curr), ''), ''); - case ValidationTokenEnum.ColumnToken: - case ValidationTokenEnum.AmpersandToken: - glue = token.typ == ValidationTokenEnum.ColumnToken ? '||' : '&&'; - return token.l.reduce((acc, curr) => acc + renderSyntax(curr), '') + - glue + - token.r.reduce((acc, curr) => acc + renderSyntax(curr), ''); - case ValidationTokenEnum.Function: - case ValidationTokenEnum.PseudoClassFunctionToken: - case ValidationTokenEnum.Parens: - return token.val + '(' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ')' + renderAttributes(token); - case ValidationTokenEnum.Comma: - return ','; - case ValidationTokenEnum.Keyword: - return token.val + renderAttributes(token); - case ValidationTokenEnum.OpenBracket: - return '['; - case ValidationTokenEnum.Ampersand: - return '&&'; - case ValidationTokenEnum.QuestionMark: - return '?'; - case ValidationTokenEnum.Separator: - return '/'; - case ValidationTokenEnum.Bracket: - return '[' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '') + ']' + renderAttributes(token); - case ValidationTokenEnum.PropertyType: - return '<' + token.val + '>' + renderAttributes(token); - case ValidationTokenEnum.DeclarationType: - return "<'" + token.val + "'>" + renderAttributes(token); - case ValidationTokenEnum.Number: - case ValidationTokenEnum.PseudoClassToken: - case ValidationTokenEnum.StringToken: - return token.val + ''; - case ValidationTokenEnum.SemiColon: - return ';'; - case ValidationTokenEnum.AtRule: - return '@' + token.val; - case ValidationTokenEnum.AtRuleDefinition: - return '@' + token.val + - (token.prelude == null ? '' : ' ' + token.prelude.reduce((acc, curr) => acc + renderSyntax(curr), '')) + - (token.chi == null ? '' : ' {\n' + token.chi.reduce((acc, curr) => acc + renderSyntax(curr), '')).slice(1, -1) + '\n}'; - case ValidationTokenEnum.Block: - return '{' + token.chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}'; - case ValidationTokenEnum.DeclarationDefinitionToken: - return token.nam + ': ' + renderSyntax(token.val); - case ValidationTokenEnum.ColumnArrayToken: - return token.chi.reduce((acc, curr) => acc + (acc.trim().length > 0 ? '||' : '') + renderSyntax(curr), ''); - default: - throw new Error('Unhandled token: ' + JSON.stringify({ token })); - } -} -function renderAttributes(token) { - let result = ''; - if (token.isList) { - result += '#'; - } - if (token.isOptional) { - result += '?'; - } - if (token.isRepeatableGroup) { - result += '!'; - } - if (token.isRepeatable) { - result += '*'; - } - if (token.atLeastOnce) { - result += '+'; - } - if (token.occurence != null) { - if (token.occurence.max == 0 || token.occurence.max == token.occurence.min || Number.isNaN(token.occurence.max)) { - result += '{' + token.occurence.min + '}'; - } - else { - result += '{' + token.occurence.min + ',' + token.occurence.max + '}'; - } - } - return result; -} function minify(ast) { if (Array.isArray(ast)) { // @ts-ignore @@ -1143,4 +1049,4 @@ function* walkValidationToken(token, parent, callback, key) { } } -export { WalkValidationTokenEnum, WalkValidationTokenKeyTypeEnum, parseSyntax, renderSyntax, walkValidationToken }; +export { WalkValidationTokenEnum, WalkValidationTokenKeyTypeEnum, parseSyntax, walkValidationToken }; diff --git a/dist/lib/validation/parser/types.js b/dist/lib/validation/parser/types.js index 1c60d73b..64d87385 100644 --- a/dist/lib/validation/parser/types.js +++ b/dist/lib/validation/parser/types.js @@ -1,4 +1,3 @@ -const specialValues = ['inherit', 'initial', 'unset', 'revert', 'revert-layer']; var ValidationTokenEnum; (function (ValidationTokenEnum) { ValidationTokenEnum[ValidationTokenEnum["Root"] = 0] = "Root"; @@ -52,4 +51,4 @@ var ValidationSyntaxGroupEnum; ValidationSyntaxGroupEnum["AtRules"] = "atRules"; })(ValidationSyntaxGroupEnum || (ValidationSyntaxGroupEnum = {})); -export { ValidationSyntaxGroupEnum, ValidationTokenEnum, specialValues }; +export { ValidationSyntaxGroupEnum, ValidationTokenEnum }; diff --git a/dist/lib/validation/syntax.js b/dist/lib/validation/syntax.js index a6ebd7b2..c47a1999 100644 --- a/dist/lib/validation/syntax.js +++ b/dist/lib/validation/syntax.js @@ -6,8 +6,7 @@ import '../ast/walk.js'; import '../parser/parse.js'; import { isLength } from '../syntax/syntax.js'; import '../parser/utils/config.js'; -import '../renderer/color/utils/constants.js'; -import '../renderer/sourcemap/lib/encode.js'; +import { renderToken } from '../renderer/render.js'; import { getSyntaxConfig, getParsedSyntax } from './config.js'; import { validateSelector } from './selector.js'; import './syntaxes/complex-selector.js'; @@ -33,9 +32,9 @@ function splice(tokens, matches) { } function validateSyntax(syntaxes, tokens, root, options, context = { level: 0 }) { console.error(JSON.stringify({ - syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''), - syntaxes, - tokens, + syntax: syntaxes?.reduce?.((acc, curr) => acc + renderSyntax(curr), ''), + // syntaxes, + tokens: tokens.reduce((acc, curr) => acc + renderToken(curr), ''), s: new Error('bar').stack }, null, 1)); if (syntaxes == null) { @@ -1391,6 +1390,41 @@ function doValidateSyntax(syntax, token, tokens, root, options, context) { tokens }; break; + case ValidationTokenEnum.ColumnArrayToken: + { + matches = []; + queue = []; + const children = syntax.chi; + let child; + while (child = children.shift()) { + result = validateSyntax([child], tokens, root, options, context); + if (result.valid == ValidationLevel.Valid) { + matches.push(child); + consumeToken(tokens); + token = tokens[0]; + if (queue.length > 0) { + children.unshift(...queue); + queue = []; + } + if (token == null) { + break; + } + } + else { + queue.push(child); + } + } + valid = matches.length > 0; + result = { + valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, + matches: valid ? [token] : [], + node: valid ? null : token, + syntax, + error: valid ? '' : 'expecting token', + tokens + }; + } + break; case ValidationTokenEnum.ColumnToken: children = [...syntax.l.slice(), ...syntax.r.slice()]; matches = []; diff --git a/dist/lib/validation/syntaxes/layer-name.js b/dist/lib/validation/syntaxes/layer-name.js index 0e7b7333..f93a1240 100644 --- a/dist/lib/validation/syntaxes/layer-name.js +++ b/dist/lib/validation/syntaxes/layer-name.js @@ -15,7 +15,7 @@ function validateLayerName(tokens) { acc[acc.length - 1].push(curr); } return acc; - }, [[]]).slice(1); + }, [[]]); for (let i = 0; i < slice.length; i++) { if (slice[i].length == 0) { // @ts-ignore @@ -28,26 +28,15 @@ function validateLayerName(tokens) { tokens }; } - if (slice[i][0].typ != EnumToken.IdenTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: tokens, - node: slice[i][0], - syntax: 'ident', - error: 'expecting ident', - tokens - }; - } - for (let j = 1; j < slice[i].length; j++) { - if (slice[i][j].typ != EnumToken.ClassSelectorTokenType) { + for (let j = 0; j < slice[i].length; j++) { + if (slice[i][j].typ != EnumToken.IdenTokenType && slice[i][j].typ != EnumToken.ClassSelectorTokenType) { // @ts-ignore return { valid: ValidationLevel.Drop, matches: tokens, node: slice[i][j], - syntax: 'layer-name', - error: 'expecting class selector', + syntax: '', + error: 'expecting ident or class selector', tokens }; } diff --git a/jsr.json b/jsr.json index 42af0939..defc0aa2 100644 --- a/jsr.json +++ b/jsr.json @@ -1,6 +1,6 @@ { "name": "@tbela99/css-parser", - "version": "0.9.1-alpha1", + "version": "0.9.1", "publish": { "include": [ "src", diff --git a/package.json b/package.json index e3375ba4..34140a6c 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "@tbela99/css-parser", "description": "CSS parser for node and the browser", - "version": "v0.9.1-alpah1", + "version": "v0.9.1", "exports": { ".": "./dist/node/index.js", "./node": "./dist/node/index.js", @@ -18,8 +18,8 @@ "build": "rollup -c;./build.sh dist/index.d.ts 'declare interface' 'declare type'", "test": "web-test-runner \"test/**/web.spec.js\" --node-resolve --playwright --browsers chromium firefox webkit --root-dir=.; mocha --reporter-options='maxDiffSize=1801920' \"test/**/node.spec.js\"", "test:node": "mocha --reporter-options='maxDiffSize=1801920' \"test/**/node.spec.js\"", - "test:cov": "c8 --reporter=html --reporter=text --reporter=json-summary mocha --reporter-options='maxDiffSize=1801920' \"test/**/node.spec.js\"", - "test:web-cov": "web-test-runner \"test/**/web.spec.js\" --node-resolve --playwright --browsers chromium firefox webkit --root-dir=. --coverage", + "test:cov": "c8 -x dist/lib/validation/syntax.js -x 'dist/lib/validation/parser/*.js' --reporter=html --reporter=text --reporter=json-summary mocha --reporter-options='maxDiffSize=1801920' \"test/**/node.spec.js\"", + "test:web-cov": "web-test-runner -x dist/lib/validation/syntax.js,dist/lib/validation/parser \"test/**/web.spec.js\" --node-resolve --playwright --browsers chromium firefox webkit --root-dir=. --coverage", "profile": "node --enable-source-maps --inspect-brk test/inspect.js", "syntax-update": "esno tools/validation.ts", "debug": "web-test-runner \"test/**/web.spec.js\" --manual --open --node-resolve --root-dir=." diff --git a/src/@types/index.d.ts b/src/@types/index.d.ts index 63955c89..dac0210c 100644 --- a/src/@types/index.d.ts +++ b/src/@types/index.d.ts @@ -1,6 +1,6 @@ import {VisitorNodeMap} from "./visitor.d.ts"; import {AstAtRule, AstDeclaration, AstRule, AstRuleStyleSheet, Position} from "./ast.d.ts"; -import {SourceMap} from "../lib/renderer/sourcemap"; +import {SourceMap} from "../lib/renderer/sourcemap/index.ts"; import {PropertyListOptions} from "./parse.d.ts"; import {EnumToken} from "../lib"; diff --git a/src/@types/token.d.ts b/src/@types/token.d.ts index 83620160..0e686128 100644 --- a/src/@types/token.d.ts +++ b/src/@types/token.d.ts @@ -1,4 +1,4 @@ -import type {AstDeclaration, BaseToken} from "./ast"; +import type {AstDeclaration, BaseToken} from "./ast.d.ts"; import {EnumToken} from "../lib"; export declare interface LiteralToken extends BaseToken { diff --git a/src/@types/validation.d.ts b/src/@types/validation.d.ts index 190f5b3b..a5f7caa7 100644 --- a/src/@types/validation.d.ts +++ b/src/@types/validation.d.ts @@ -1,8 +1,8 @@ -import {ValidationLevel, ValidationSyntaxGroupEnum} from "../lib"; -import {AstNode} from "./ast.d.ts"; -import {Token} from "./token.d.ts"; -import type {ValidationToken} from "../lib/validation/parser"; -import type {ValidationOptions} from "./index"; +import {ValidationLevel, ValidationSyntaxGroupEnum} from "../lib/index.ts"; +import type {AstNode} from "./ast.d.ts"; +import type {Token} from "./token.d.ts"; +import type {ValidationToken} from "../lib/validation/parser/index.ts"; +import type {ValidationOptions} from "./index.d.ts"; export declare interface ValidationSyntaxNode { diff --git a/src/@types/walker.d.ts b/src/@types/walker.d.ts index 4c2c1ca2..ce431538 100644 --- a/src/@types/walker.d.ts +++ b/src/@types/walker.d.ts @@ -1,6 +1,6 @@ import {AstNode, AstRuleList} from "./ast.d.ts"; import {BinaryExpressionToken, FunctionToken, ParensToken, Token} from "./token.d.ts"; -import {WalkerValueEvent} from '../lib/ast/walk'; +import {WalkerValueEvent} from '../lib/ast/walk.ts'; export declare type WalkerOption = 'ignore' | 'stop' | 'children' | 'ignore-children' | Token | null; /** diff --git a/src/lib/ast/expand.ts b/src/lib/ast/expand.ts index 3aec0021..7ee0ddd4 100644 --- a/src/lib/ast/expand.ts +++ b/src/lib/ast/expand.ts @@ -1,9 +1,9 @@ -import {combinators, splitRule} from "./minify"; -import {parseString} from "../parser"; -import {walkValues} from "./walk"; -import {renderToken} from "../renderer"; -import type {AstAtRule, AstNode, AstRule, AstRuleStyleSheet, Token} from "../../@types"; -import {EnumToken} from "./types"; +import {combinators, splitRule} from "./minify.ts"; +import {parseString} from "../parser/index.ts"; +import {walkValues} from "./walk.ts"; +import {renderToken} from "../renderer/index.ts"; +import type {AstAtRule, AstNode, AstRule, AstRuleStyleSheet, Token} from "../../@types/index.d.ts"; +import {EnumToken} from "./types.ts"; /** * expand nested css ast @@ -91,13 +91,13 @@ function expandRule(node: AstRule): Array { if (selRule.length > 1) { const r: string = ':is(' + selRule.map(a => a.join('')).join(',') + ')'; - rule.sel = splitRule(ast.sel).reduce((a, b) => a.concat([b.join('') + r]), []).join(','); + rule.sel = splitRule(ast.sel).reduce((a: string[], b: string[]): string[] => a.concat([b.join('') + r]), []).join(','); } else { // selRule = splitRule(selRule.reduce((acc, curr) => acc + (acc.length > 0 ? ',' : '') + curr.join(''), '')); - const arSelf = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc, curr) => acc.concat([curr.join('')]), []).join(','); + const arSelf: string = splitRule(ast.sel).filter((r: string[]): boolean => r.every((t: string): boolean => t != ':before' && t != ':after' && !t.startsWith('::'))).reduce((acc: string[], curr: string[]): string[] => acc.concat([curr.join('')]), []).join(','); if (arSelf.length == 0) { @@ -124,7 +124,7 @@ function expandRule(node: AstRule): Array { // pseudo elements cannot be used with '&' // https://www.w3.org/TR/css-nesting-1/#example-7145ff1e - const rules: string[][] = splitRule(ast.sel).filter(r => r.every(t => t != ':before' && t != ':after' && !t.startsWith('::'))); + const rules: string[][] = splitRule(ast.sel).filter((r: string[]): boolean => r.every((t: string): boolean => t != ':before' && t != ':after' && !t.startsWith('::'))); const parentSelector: boolean = !node.sel.includes('&'); if (rules.length == 0) { @@ -323,7 +323,7 @@ export function replaceCompound(input: string, replace: string): string { if (tokens[1].typ == EnumToken.IdenTokenType) { - t.value.val = replacement.length == 1 || (!replace.includes(' ') && replace.charAt(0).match(/[:.]/)) ? tokens[1].val + replace : replaceCompoundLiteral(tokens[1].val + '&', replace); + t.value.val = (replacement as Token[]).length == 1 || (!replace.includes(' ') && replace.charAt(0).match(/[:.]/)) ? tokens[1].val + replace : replaceCompoundLiteral(tokens[1].val + '&', replace); tokens.splice(1, 1); } else { diff --git a/src/lib/ast/features/calc.ts b/src/lib/ast/features/calc.ts index 2f3fa06d..8ebc2c4b 100644 --- a/src/lib/ast/features/calc.ts +++ b/src/lib/ast/features/calc.ts @@ -12,10 +12,10 @@ import type { WalkerOption } from "../../../@types/index.d.ts"; import {EnumToken} from "../types"; -import {WalkerValueEvent, walkValues} from "../walk"; -import {evaluate} from "../math"; -import {renderToken} from "../../renderer"; -import {mathFuncs} from "../../syntax"; +import {WalkerValueEvent, walkValues} from "../walk.ts"; +import {evaluate} from "../math/index.ts"; +import {renderToken} from "../../renderer/index.ts"; +import {mathFuncs} from "../../syntax/index.ts"; export class ComputeCalcExpressionFeature { @@ -110,7 +110,7 @@ export class ComputeCalcExpressionFeature { } )) { - if (value != null && value.typ == EnumToken.FunctionTokenType && mathFuncs.includes(value.val)) { + if (value != null && value.typ == EnumToken.FunctionTokenType && mathFuncs.includes((value as FunctionToken).val)) { if (!set.has(value)) { @@ -129,12 +129,12 @@ export class ComputeCalcExpressionFeature { if (parent.typ == EnumToken.BinaryExpressionTokenType) { - if (parent.l == value) { + if ((parent as BinaryExpressionToken).l == value) { - parent.l = values[0]; + (parent as BinaryExpressionToken).l = values[0]; } else { - parent.r = values[0]; + (parent as BinaryExpressionToken).r = values[0]; } } else { @@ -159,7 +159,7 @@ export class ComputeCalcExpressionFeature { if (children[i] == value) { - if (parent.typ == EnumToken.FunctionTokenType && parent.val == 'calc') { + if (parent.typ == EnumToken.FunctionTokenType && (parent as FunctionToken).val == 'calc') { children.splice(i, 1, ...values); } else { diff --git a/src/lib/ast/features/index.ts b/src/lib/ast/features/index.ts index ee8dbb0c..0ca3622d 100644 --- a/src/lib/ast/features/index.ts +++ b/src/lib/ast/features/index.ts @@ -1,4 +1,4 @@ -export * from './prefix'; -export * from './inlinecssvariables'; -export * from './shorthand'; -export * from './calc' \ No newline at end of file +export * from './prefix.ts'; +export * from './inlinecssvariables.ts'; +export * from './shorthand.ts'; +export * from './calc.ts' \ No newline at end of file diff --git a/src/lib/ast/features/inlinecssvariables.ts b/src/lib/ast/features/inlinecssvariables.ts index 00bbdbbf..03560fe1 100644 --- a/src/lib/ast/features/inlinecssvariables.ts +++ b/src/lib/ast/features/inlinecssvariables.ts @@ -6,14 +6,16 @@ import type { AstRuleList, AstRuleStyleSheet, CommentToken, + DashedIdentToken, FunctionToken, MinifyFeatureOptions, ParserOptions, + Token, VariableScopeInfo -} from "../../../@types"; -import {EnumToken} from "../types"; -import {walkValues} from "../walk"; -import {renderToken} from "../../renderer"; +} from "../../../@types/index"; +import {EnumToken} from "../types.ts"; +import {walkValues} from "../walk.ts"; +import {renderToken} from "../../renderer/index.ts"; function replace(node: AstDeclaration | AstRule | AstComment | AstRuleList, variableScope: Map) { @@ -21,9 +23,9 @@ function replace(node: AstDeclaration | AstRule | AstComment | AstRuleList, vari if (value?.typ == EnumToken.FunctionTokenType && (value).val == 'var') { - if (value.chi.length == 1 && value.chi[0].typ == EnumToken.DashedIdenTokenType) { + if ((value as FunctionToken).chi.length == 1 && (value as FunctionToken).chi[0].typ == EnumToken.DashedIdenTokenType) { - const info: VariableScopeInfo = variableScope.get(value.chi[0].val); + const info: VariableScopeInfo = variableScope.get(((value as FunctionToken).chi[0] as DashedIdentToken).val); if (info?.replaceable) { @@ -186,7 +188,7 @@ export class InlineCssVariablesFeature { // @ts-ignore (parent.chi).splice(i++, 1, { typ: EnumToken.CommentTokenType, - val: `/* ${info.node.nam}: ${info.node.val.reduce((acc, curr) => acc + renderToken(curr), '')} */` + val: `/* ${info.node.nam}: ${info.node.val.reduce((acc: string, curr: Token): string => acc + renderToken(curr), '')} */` } as CommentToken); } } diff --git a/src/lib/ast/features/shorthand.ts b/src/lib/ast/features/shorthand.ts index 41f34af9..2768f315 100644 --- a/src/lib/ast/features/shorthand.ts +++ b/src/lib/ast/features/shorthand.ts @@ -1,6 +1,12 @@ -import {PropertyList} from "../../parser/declaration"; -import {EnumToken} from "../types"; -import type {AstAtRule, AstRule, AstRuleStyleSheet, MinifyFeatureOptions, PropertyListOptions} from "../../../@types"; +import {PropertyList} from "../../parser/declaration/index.ts"; +import {EnumToken} from "../types.ts"; +import type { + AstAtRule, + AstRule, + AstRuleStyleSheet, + MinifyFeatureOptions, + PropertyListOptions +} from "../../../@types/index.d.ts"; export class ComputeShorthandFeature { diff --git a/src/lib/ast/index.ts b/src/lib/ast/index.ts index fdc913d1..bac81e2a 100644 --- a/src/lib/ast/index.ts +++ b/src/lib/ast/index.ts @@ -1,5 +1,5 @@ -export * from './types'; -export * from './minify'; -export * from './walk'; -export * from './expand'; \ No newline at end of file +export * from './types.ts'; +export * from './minify.ts'; +export * from './walk.ts'; +export * from './expand.ts'; \ No newline at end of file diff --git a/src/lib/ast/math/expression.ts b/src/lib/ast/math/expression.ts index 883706fe..d8185e4d 100644 --- a/src/lib/ast/math/expression.ts +++ b/src/lib/ast/math/expression.ts @@ -15,11 +15,11 @@ import type { TimeToken, Token } from "../../../@types/index.d.ts"; -import {EnumToken} from "../types"; -import {compute, rem} from "./math"; -import {reduceNumber} from "../../renderer"; +import {EnumToken} from "../types.ts"; +import {compute, rem} from "./math.ts"; +import {reduceNumber} from "../../renderer/index.ts"; -import {mathFuncs} from "../../syntax"; +import {mathFuncs} from "../../syntax/index.ts"; /** * evaluate an array of tokens @@ -31,7 +31,7 @@ export function evaluate(tokens: Token[]): Token[] { if (tokens.length == 1 && tokens[0].typ == EnumToken.FunctionTokenType && (tokens[0]).val != 'calc' && mathFuncs.includes((tokens[0]).val)) { - const chi: Token[][] = tokens[0].chi.reduce((acc: Token[][], t: Token): Token[][] => { + const chi: Token[][] = (tokens[0] as FunctionToken).chi.reduce((acc: Token[][], t: Token): Token[][] => { if (acc.length == 0 || t.typ == EnumToken.CommaTokenType) { @@ -52,7 +52,7 @@ export function evaluate(tokens: Token[]): Token[] { chi[i] = evaluate(chi[i]); } - tokens[0].chi = chi.reduce((acc: Token[], t: Token[]): Token[] => { + (tokens[0] as FunctionToken).chi = chi.reduce((acc: Token[], t: Token[]): Token[] => { if (acc.length > 0) { @@ -64,7 +64,7 @@ export function evaluate(tokens: Token[]): Token[] { return acc; }); - return evaluateFunc(tokens[0]); + return evaluateFunc(tokens[0] as FunctionToken); } try { @@ -172,7 +172,7 @@ function doEvaluate(l: Token, r: Token, op: EnumToken.Add | EnumToken.Sub | Enum if (l.typ == EnumToken.FunctionTokenType) { - const val: Token[] = evaluateFunc(l); + const val: Token[] = evaluateFunc(l as FunctionToken); if (val.length == 1) { @@ -185,7 +185,7 @@ function doEvaluate(l: Token, r: Token, op: EnumToken.Add | EnumToken.Sub | Enum if (r.typ == EnumToken.FunctionTokenType) { - const val = evaluateFunc(r); + const val = evaluateFunc(r as FunctionToken); if (val.length == 1) { @@ -198,7 +198,7 @@ function doEvaluate(l: Token, r: Token, op: EnumToken.Add | EnumToken.Sub | Enum if (l.typ == EnumToken.FunctionTokenType) { - const val = evaluateFunc(l); + const val = evaluateFunc(l as FunctionToken); if (val.length == 1) { @@ -278,7 +278,7 @@ function getValue(t: NumberToken | IdentToken | FunctionToken): number | null { if (t.typ == EnumToken.FunctionTokenType) { - v1 = evaluateFunc(t); + v1 = evaluateFunc(t as FunctionToken); if (v1.length != 1 || v1[0].typ == EnumToken.BinaryExpressionTokenType) { @@ -596,15 +596,15 @@ function inlineExpression(token: Token): Token[] { if (token.typ == EnumToken.ParensTokenType && token.chi.length == 1) { - result.push(token.chi[0]); + result.push((token as ParensToken).chi[0]); } else if (token.typ == EnumToken.BinaryExpressionTokenType) { - if ([EnumToken.Mul, EnumToken.Div].includes(token.op)) { + if ([EnumToken.Mul, EnumToken.Div].includes((token as BinaryExpressionToken).op)) { result.push(token); } else { - result.push(...inlineExpression(token.l), {typ: token.op}, ...inlineExpression(token.r)); + result.push(...inlineExpression((token as BinaryExpressionToken).l), {typ: (token as BinaryExpressionToken).op}, ...inlineExpression((token as BinaryExpressionToken).r)); } } else { @@ -625,17 +625,17 @@ function evaluateExpression(token: Token): Token { return token; } - if (token.r.typ == EnumToken.BinaryExpressionTokenType) { + if ((token as BinaryExpressionToken).r.typ == EnumToken.BinaryExpressionTokenType) { - token.r = evaluateExpression(token.r); + (token as BinaryExpressionToken).r = evaluateExpression((token as BinaryExpressionToken).r); } - if (token.l.typ == EnumToken.BinaryExpressionTokenType) { + if ((token as BinaryExpressionToken).l.typ == EnumToken.BinaryExpressionTokenType) { - token.l = evaluateExpression(token.l); + (token as BinaryExpressionToken).l = evaluateExpression((token as BinaryExpressionToken).l); } - return doEvaluate(token.l, token.r, token.op); + return doEvaluate((token as BinaryExpressionToken).l, (token as BinaryExpressionToken).r, (token as BinaryExpressionToken).op); } function isScalarToken(token: Token): boolean { diff --git a/src/lib/ast/math/index.ts b/src/lib/ast/math/index.ts index d9afc58e..2a8eb330 100644 --- a/src/lib/ast/math/index.ts +++ b/src/lib/ast/math/index.ts @@ -1,2 +1,2 @@ -export * from './expression'; \ No newline at end of file +export * from './expression.ts'; \ No newline at end of file diff --git a/src/lib/ast/math/math.ts b/src/lib/ast/math/math.ts index 9bb3023c..79aea797 100644 --- a/src/lib/ast/math/math.ts +++ b/src/lib/ast/math/math.ts @@ -112,7 +112,7 @@ export function compute(a: number | FractionToken, b: number | FractionToken, op } - const a2: [number, number] = simplify(l2, r2); + const a2: [number, number] = simplify(l2 as number, r2 as number); if (a2[1] == 1) { diff --git a/src/lib/ast/minify.ts b/src/lib/ast/minify.ts index b0f29194..a9a98c33 100644 --- a/src/lib/ast/minify.ts +++ b/src/lib/ast/minify.ts @@ -1,9 +1,9 @@ -import {parseString} from "../parser"; -import {eq} from "../parser/utils/eq"; -import {replaceCompound} from './expand'; -import {doRender, renderToken} from "../renderer"; -import * as allFeatures from "./features"; -import {walkValues} from "./walk"; +import {parseString} from "../parser/index.ts"; +import {eq} from "../parser/utils/eq.ts"; +import {replaceCompound} from './expand.ts'; +import {doRender, renderToken} from "../renderer/index.ts"; +import * as allFeatures from "./features/index.ts"; +import {walkValues} from "./walk.ts"; import type { AstAtRule, AstDeclaration, @@ -17,11 +17,12 @@ import type { MinifyFeatureOptions, OptimizedSelector, ParserOptions, + PseudoClassFunctionToken, RawSelectorTokens, Token -} from "../../@types"; -import {EnumToken} from "./types"; -import {isFunction, isIdent, isIdentStart, isWhiteSpace} from "../syntax"; +} from "../../@types/index.d.ts"; +import {EnumToken} from "./types.ts"; +import {isFunction, isIdent, isIdentStart, isWhiteSpace} from "../syntax/index.ts"; export const combinators: string[] = ['+', '>', '~', '||', '|']; export const definedPropertySettings = {configurable: true, enumerable: false, writable: true}; @@ -1094,9 +1095,9 @@ function fixSelector(node: AstRule) { for (const attr of walkValues(attributes)) { - if (attr.value.typ == EnumToken.PseudoClassFuncTokenType && attr.value.val == ':is') { + if (attr.value.typ == EnumToken.PseudoClassFuncTokenType && (attr.value as PseudoClassFunctionToken).val == ':is') { - let i = attr.value.chi.length; + let i = (attr.value as PseudoClassFunctionToken).chi.length; while (i--) { diff --git a/src/lib/ast/walk.ts b/src/lib/ast/walk.ts index dfea988a..4993c49b 100644 --- a/src/lib/ast/walk.ts +++ b/src/lib/ast/walk.ts @@ -11,7 +11,7 @@ import type { WalkerValueFilter, WalkResult } from "../../@types/index.d.ts"; -import {EnumToken} from "./types"; +import {EnumToken} from "./types.ts"; export enum WalkerValueEvent { Enter, @@ -167,10 +167,10 @@ export function* walkValues(values: Token[], root: AstNode | Token | null = null } else if (value.typ == EnumToken.BinaryExpressionTokenType) { - map.set(value.l, map.get(value) ?? root as FunctionToken | ParensToken); - map.set(value.r, map.get(value) ?? root as FunctionToken | ParensToken); + map.set( (value as BinaryExpressionToken).l, map.get(value) ?? root as FunctionToken | ParensToken); + map.set( (value as BinaryExpressionToken).r, map.get(value) ?? root as FunctionToken | ParensToken); - stack.unshift(value.l, value.r); + stack.unshift( (value as BinaryExpressionToken).l, (value as BinaryExpressionToken).r); } if (filter.event == WalkerValueEvent.Leave && filter.fn != null) { diff --git a/src/lib/fs/index.ts b/src/lib/fs/index.ts index e025708d..541418b0 100644 --- a/src/lib/fs/index.ts +++ b/src/lib/fs/index.ts @@ -1,2 +1,2 @@ -export * from './resolve'; \ No newline at end of file +export * from './resolve.ts'; \ No newline at end of file diff --git a/src/lib/index.ts b/src/lib/index.ts index e15da0ca..62d93adc 100644 --- a/src/lib/index.ts +++ b/src/lib/index.ts @@ -1,4 +1,4 @@ -export * from './ast'; -export * from './renderer'; -export * from './parser'; -export * from './validation'; \ No newline at end of file +export * from './ast/index.ts'; +export * from './renderer/index.ts'; +export * from './parser/index.ts'; +export * from './validation/index.ts'; \ No newline at end of file diff --git a/src/lib/parser/declaration/index.ts b/src/lib/parser/declaration/index.ts index 0118b0f3..f71bd389 100644 --- a/src/lib/parser/declaration/index.ts +++ b/src/lib/parser/declaration/index.ts @@ -1,4 +1,4 @@ -export * from './list'; -export * from './set'; -export * from './map'; \ No newline at end of file +export * from './list.ts'; +export * from './set.ts'; +export * from './map.ts'; \ No newline at end of file diff --git a/src/lib/parser/declaration/list.ts b/src/lib/parser/declaration/list.ts index fe9d20ad..71db3511 100644 --- a/src/lib/parser/declaration/list.ts +++ b/src/lib/parser/declaration/list.ts @@ -1,17 +1,17 @@ import type { AstDeclaration, AstNode, + PropertiesConfig, PropertyListOptions, ShorthandMapType, ShorthandPropertyType, - PropertiesConfig, Token -} from "../../../@types"; -import {PropertySet} from "./set"; -import {getConfig} from "../utils"; -import {PropertyMap} from "./map"; -import {parseString} from "../parse"; -import {EnumToken} from "../../ast"; +} from "../../../@types/index"; +import {PropertySet} from "./set.ts"; +import {getConfig} from "../utils/index.ts"; +import {PropertyMap} from "./map.ts"; +import {parseString} from "../parse.ts"; +import {EnumToken} from "../../ast/index.ts"; const config: PropertiesConfig = getConfig(); diff --git a/src/lib/parser/declaration/map.ts b/src/lib/parser/declaration/map.ts index 022d5928..272cf212 100644 --- a/src/lib/parser/declaration/map.ts +++ b/src/lib/parser/declaration/map.ts @@ -8,13 +8,13 @@ import type { StringToken, Token, WhitespaceToken -} from "../../../@types"; -import {eq} from "../utils/eq"; -import {getConfig, matchType} from "../utils"; -import {renderToken} from "../../renderer"; -import {parseString} from "../parse"; -import {PropertySet} from "./set"; -import {EnumToken} from "../../ast"; +} from "../../../@types/index.d.ts"; +import {eq} from "../utils/eq.ts"; +import {getConfig, matchType} from "../utils/index.ts"; +import {renderToken} from "../../renderer/index.ts"; +import {parseString} from "../parse.ts"; +import {PropertySet} from "./set.ts"; +import {EnumToken} from "../../ast/index.ts"; const propertiesConfig: PropertiesConfig = getConfig(); diff --git a/src/lib/parser/declaration/set.ts b/src/lib/parser/declaration/set.ts index 7cd2d1dd..23b469d5 100644 --- a/src/lib/parser/declaration/set.ts +++ b/src/lib/parser/declaration/set.ts @@ -6,12 +6,12 @@ import type { ShorthandPropertyType, Token, WhitespaceToken -} from "../../../@types"; -import {eq} from "../utils/eq"; -import {EnumToken} from "../../ast"; -import {isLength} from "../../syntax"; +} from "../../../@types/index.d.ts"; +import {eq} from "../utils/eq.ts"; +import {EnumToken} from "../../ast/index.ts"; +import {isLength} from "../../syntax/index.ts"; -function dedup(values: Token[][]) { +function dedup(values: Token[][]): Token[][] { for (const value of values) { diff --git a/src/lib/parser/index.ts b/src/lib/parser/index.ts index 8690c427..6f4a366c 100644 --- a/src/lib/parser/index.ts +++ b/src/lib/parser/index.ts @@ -1,4 +1,4 @@ -export * from './parse'; -export * from './tokenize'; -export * from './utils'; \ No newline at end of file +export * from './parse.ts'; +export * from './tokenize.ts'; +export * from './utils/index.ts'; \ No newline at end of file diff --git a/src/lib/parser/parse.ts b/src/lib/parser/parse.ts index d9f1ea28..fb24fa69 100644 --- a/src/lib/parser/parse.ts +++ b/src/lib/parser/parse.ts @@ -14,11 +14,12 @@ import { mathFuncs, mediaTypes, parseDimension, + pseudoElements, webkitPseudoAliasMap -} from "../syntax"; -import {parseDeclarationNode} from './utils'; -import {renderToken} from "../renderer"; -import {COLORS_NAMES} from "../renderer/color"; +} from "../syntax/index.ts"; +import {parseDeclarationNode} from './utils/index.ts'; +import {renderToken} from "../renderer/index.ts"; +import {COLORS_NAMES} from "../renderer/color/index.ts"; import { combinators, definedPropertySettings, @@ -29,9 +30,9 @@ import { ValidationLevel, walk, walkValues -} from "../ast"; -import {tokenize} from "./tokenize"; -import { +} from "../ast/index.ts"; +import {tokenize} from "./tokenize.ts"; +import type { AstAtRule, AstComment, AstDeclaration, @@ -46,6 +47,7 @@ import { AtRuleVisitorHandler, AttrEndToken, AttrStartToken, + AttrToken, BlockEndToken, BlockStartToken, ChildCombinatorToken, @@ -100,9 +102,9 @@ import { UniversalSelectorToken, UrlToken, WhitespaceToken -} from "../../@types"; -import {deprecatedSystemColors, systemColors} from "../renderer/color/utils"; -import {validateAtRule, validateSelector} from "../validation"; +} from "../../@types/index.d.ts"; +import {deprecatedSystemColors, systemColors} from "../renderer/color/utils/index.ts"; +import {validateAtRule, validateSelector} from "../validation/index.ts"; import type {ValidationResult} from "../../@types/validation.d.ts"; export const urlTokenMatcher: RegExp = /^(["']?)[a-zA-Z0-9_/.-][a-zA-Z0-9_/:.#?-]+(\1)$/; @@ -304,7 +306,7 @@ export async function doParse(iterator: string, options: ParserOptions = {}): Pr if (context != null && context.typ == EnumToken.InvalidRuleTokenType) { - const index: number = context.chi.findIndex(node => node == context); + const index: number = context.chi.findIndex((node: AstNode): boolean => node == context); if (index > -1) { @@ -445,7 +447,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn importedBytesIn: number; }, options: ParserOptions, errors: ErrorDescription[], src: string, map: Map, rawTokens: TokenizeResult[]): Promise { - let tokens: Token[] = []; + let tokens: Token[] = [] as Token[]; for (const t of results) { @@ -542,8 +544,16 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn continue; } if (type != EnumToken.AtRuleNodeType) { - errors.push({action: 'drop', message: 'invalid @import', location: {src, ...position}}); - return null; + + // @ts-ignore + if (!(type == EnumToken.InvalidAtRuleTokenType && + // @ts-ignore + ['charset', 'layer', 'import'].includes((context.chi[i]).nam as string) )) { + + errors.push({action: 'drop', message: 'invalid @import', location: {src, ...position}}); + return null; + } + } // @ts-ignore @@ -592,13 +602,25 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn tokens.shift(); - if (tokens[1].typ == EnumToken.UrlTokenTokenType) { + if ((tokens[0] as Token)?.typ == EnumToken.UrlTokenTokenType) { // @ts-ignore tokens[0].typ = EnumToken.StringTokenType; // @ts-ignore tokens[0].val = `"${tokens[0].val}"`; } + + // @ts-ignore + while (tokens[1]?.typ == EnumToken.WhitespaceTokenType || tokens[1]?.typ == EnumToken.CommentTokenType) { + + tokens.splice(1, 1); + } + + // @ts-ignore + if (tokens[1]?.typ == EnumToken.EndParensTokenType) { + + tokens.splice(1, 1); + } } } @@ -644,6 +666,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn } } } + // https://www.w3.org/TR/css-nesting-1/#conditionals // allowed nesting at-rules // there must be a top level rule in the stack @@ -1027,7 +1050,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn // // const valid: ValidationResult = validateDeclaration(result, options, context); // - // console.error({valid}); + // // console.error({valid}); // // if (valid.valid == ValidationLevel.Drop) { // @@ -1096,7 +1119,7 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn if (value.typ == EnumToken.IdenTokenType) { - if (parent == null && mediaTypes.some((t) => { + if (parent == null && mediaTypes.some((t: string) => { if (value.val.localeCompare(t, 'en', {sensitivity: 'base'}) == 0) { @@ -1171,12 +1194,12 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn for (let i = 0; i < value.chi.length; i++) { - if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) { + if ((value as FunctionToken | ParensToken).chi[i].typ == EnumToken.CommentTokenType || (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.WhitespaceTokenType) { continue; } - if ((dashedIdent && value.chi[i].typ == EnumToken.DashedIdenTokenType) || value.chi[i].typ == EnumToken.IdenTokenType || value.chi[i].typ == EnumToken.FunctionTokenType || value.chi[i].typ == EnumToken.ColorTokenType) { + if ((dashedIdent && (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.DashedIdenTokenType) || (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.IdenTokenType || (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.FunctionTokenType || (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.ColorTokenType) { nameIndex = i; } @@ -1189,9 +1212,9 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn continue; } - for (let i = nameIndex + 1; i < value.chi.length; i++) { + for (let i = nameIndex + 1; i <(value as FunctionToken | ParensToken).chi.length; i++) { - if (value.chi[i].typ == EnumToken.CommentTokenType || value.chi[i].typ == EnumToken.WhitespaceTokenType) { + if ((value as FunctionToken | ParensToken).chi[i].typ == EnumToken.CommentTokenType || (value as FunctionToken | ParensToken).chi[i].typ == EnumToken.WhitespaceTokenType) { continue; } @@ -1208,16 +1231,16 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn // return tokens; } - for (i = nameIndex + 1; i < value.chi.length; i++) { + for (i = nameIndex + 1; i < (value as FunctionToken | ParensToken).chi.length; i++) { if ([ EnumToken.GtTokenType, EnumToken.LtTokenType, EnumToken.GteTokenType, EnumToken.LteTokenType, EnumToken.ColonTokenType - ].includes(value.chi[valueIndex].typ)) { + ].includes((value as FunctionToken | ParensToken).chi[valueIndex].typ)) { - const val = value.chi.splice(valueIndex, 1)[0] as Token; - const node = value.chi.splice(nameIndex, 1)[0] as IdentToken; + const val = (value as FunctionToken | ParensToken).chi.splice(valueIndex, 1)[0] as Token; + const node = (value as FunctionToken | ParensToken).chi.splice(nameIndex, 1)[0] as IdentToken; // 'background' // @ts-ignore @@ -1228,20 +1251,20 @@ async function parseNode(results: TokenizeResult[], context: AstRuleList | AstIn node.typ = EnumToken.IdenTokenType; } - while (value.chi[0]?.typ == EnumToken.WhitespaceTokenType) { + while ((value as FunctionToken | ParensToken).chi[0]?.typ == EnumToken.WhitespaceTokenType) { - value.chi.shift(); + (value as FunctionToken | ParensToken).chi.shift(); } const t: Token[] = [{ typ: EnumToken.MediaQueryConditionTokenType, l: node, op: {typ: val.typ}, - r: value.chi.slice() + r: (value as FunctionToken | ParensToken).chi.slice() }]; - value.chi.length = 0; - value.chi.push(...t); + (value as FunctionToken | ParensToken).chi.length = 0; + (value as FunctionToken | ParensToken).chi.push(...t); } } } @@ -1379,11 +1402,11 @@ export function parseSelector(tokens: Token[]): Token[] { } else if (value.typ == EnumToken.ColorTokenType) { - if (value.kin == 'lit' || value.kin == 'hex' || value.kin == 'sys' || value.kin == 'dpsys') { + if ((value as ColorToken).kin == 'lit' || (value as ColorToken).kin == 'hex' || (value as ColorToken).kin == 'sys' || (value as ColorToken).kin == 'dpsys') { - if (value.kin == 'hex') { + if ((value as ColorToken).kin == 'hex') { - if (!isIdent(value.val.slice(1))) { + if (!isIdent((value as ColorToken).val.slice(1))) { continue; } @@ -1540,7 +1563,7 @@ function getTokenType(val: string, hint?: EnumToken): Token { } : ( // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - val.startsWith('::') || [':before', ':after', ':first-line', ':first-letter'].includes(val) ? { + val.startsWith('::') || pseudoElements.includes(val) ? { typ: EnumToken.PseudoElementTokenType, val } : @@ -1711,7 +1734,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T if (t.val.slice(1) in webkitPseudoAliasMap) { - t.val = ':' + webkitPseudoAliasMap[t.val.slice(1)]; + (t as PseudoClassToken).val = ':' + webkitPseudoAliasMap[t.val.slice(1)]; } } @@ -1770,30 +1793,30 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T } } - Object.assign(t, { + const attr: AttrToken = Object.assign(t, { typ: inAttr == 0 ? EnumToken.AttrTokenType : EnumToken.InvalidAttrTokenType, chi: tokens.splice(i + 1, k - i) - }); + } as AttrToken) as AttrToken; // @ts-ignore - if (t.chi.at(-1).typ == EnumToken.AttrEndTokenType) { + if (attr.chi.at(-1).typ == EnumToken.AttrEndTokenType) { // @ts-ignore - t.chi.pop(); + attr.chi.pop(); } // @ts-ignore - if (t.chi.length > 1) { + if (attr.chi.length > 1) { /*(t).chi =*/ // @ts-ignore - parseTokens(t.chi, t.typ, options); + parseTokens(attr.chi, (t as AttrToken).typ, options); } - let m: number = (t.chi).length; + let m: number = (attr.chi).length; let val: Token; - for (m = 0; m < (t.chi).length; m++) { + for (m = 0; m < (attr.chi).length; m++) { - val = (t.chi)[m]; + val = (attr.chi)[m]; if (val.typ == EnumToken.StringTokenType) { const slice = val.val.slice(1, -1); @@ -1805,9 +1828,9 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T let upper: number = m; let lower: number = m; - while (++upper < (t.chi).length) { + while (++upper < (attr.chi).length) { - if ((t.chi)[upper].typ == EnumToken.CommentTokenType) { + if ((attr.chi)[upper].typ == EnumToken.CommentTokenType) { continue; } @@ -1817,7 +1840,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T while (lower-- > 0) { - if ((t.chi)[lower].typ == EnumToken.CommentTokenType) { + if ((attr.chi)[lower].typ == EnumToken.CommentTokenType) { continue; } @@ -1826,29 +1849,29 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T } // @ts-ignore - (t.chi)[m] = { + (attr.chi)[m] = { typ: EnumToken.NameSpaceAttributeTokenType, - l: (t.chi)[lower], - r: (t.chi)[upper] + l: (attr.chi)[lower], + r: (attr.chi)[upper] }; - (t.chi).splice(upper, 1); + (attr.chi).splice(upper, 1); if (lower >= 0) { - (t.chi).splice(lower, 1); + (attr.chi).splice(lower, 1); m--; } } else if ([ EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType, EnumToken.DelimTokenType - ].includes((t.chi)[m].typ)) { + ].includes((attr.chi)[m].typ)) { let upper: number = m; let lower: number = m; - while (++upper < (t.chi).length) { + while (++upper < (attr.chi).length) { - if ((t.chi)[upper].typ == EnumToken.CommentTokenType) { + if ((attr.chi)[upper].typ == EnumToken.CommentTokenType) { continue; } @@ -1858,7 +1881,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T while (lower-- > 0) { - if ((t.chi)[lower].typ == EnumToken.CommentTokenType) { + if ((attr.chi)[lower].typ == EnumToken.CommentTokenType) { continue; } @@ -1866,7 +1889,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T break; } - val = (t.chi)[lower]; + val = (attr.chi)[lower]; if (val.typ == EnumToken.StringTokenType) { const slice: string = val.val.slice(1, -1); @@ -1875,7 +1898,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T } } - val = (t.chi)[upper]; + val = (attr.chi)[upper]; if (val.typ == EnumToken.StringTokenType) { const slice: string = val.val.slice(1, -1); @@ -2030,73 +2053,76 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T // @ts-ignore t.typ = EnumToken.ColorTokenType; // @ts-ignore - t.kin = t.val; + (t as ColorToken).kin = t.val; - if (t.chi[0].typ == EnumToken.IdenTokenType) { + // @ts-ignore + if (((t as ColorToken).chi as Token[])[0].typ == EnumToken.IdenTokenType) { - if (t.chi[0].val == 'from') { + // @ts-ignore + if (((t as ColorToken).chi as Token[])[0].val == 'from') { // @ts-ignore - t.cal = 'rel'; + (t as ColorToken).cal = 'rel'; } // @ts-ignore - else if (t.val == 'color-mix' && t.chi[0].val == 'in') { + else if ((t as ColorToken).val == 'color-mix' && ((t as ColorToken).chi as Token[])[0].val == 'in') { // @ts-ignore - t.cal = 'mix'; - } else if (t.val == 'color') { - // @ts-ignore - t.cal = 'col'; - // t.chi = t.chi.filter((t: Token) => [EnumToken.IdenTokenType, EnumToken.NumberTokenType, EnumToken.PercentageTokenType].includes(t.typ)); + (t as ColorToken).cal = 'mix'; + } else { // @ts-ignore + if ((t as ColorToken).val == 'color') { + // @ts-ignore + (t as ColorToken).cal = 'col'; + } } } - const filter = [EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType]; + const filter: EnumToken[] = [EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType]; - if (t.val != 'light-dark') { + if ((t as FunctionToken).val != 'light-dark') { filter.push(EnumToken.CommaTokenType); } - t.chi = t.chi.filter((t: Token) => !filter.includes(t.typ)); + (t as FunctionToken).chi = (t as FunctionToken).chi.filter((t: Token): boolean => !filter.includes(t.typ)); continue; } if (t.typ == EnumToken.UrlFunctionTokenType) { // @ts-ignore - if (t.chi[0]?.typ == EnumToken.StringTokenType) { + if ((t as FunctionURLToken).chi[0]?.typ == EnumToken.StringTokenType) { // @ts-ignore const value = t.chi[0].val.slice(1, -1); // @ts-ignore - if (t.chi[0].val.slice(1, 5) != 'data:' && urlTokenMatcher.test(value)) { + if ((t as FunctionURLToken).chi[0].val.slice(1, 5) != 'data:' && urlTokenMatcher.test(value)) { // @ts-ignore - t.chi[0].typ = EnumToken.UrlTokenTokenType; + (t as FunctionURLToken).chi[0].typ = EnumToken.UrlTokenTokenType; // @ts-ignore - t.chi[0].val = options.src !== '' && options.resolveUrls ? options.resolve(value, options.src).absolute : value; + (t as FunctionURLToken).chi[0].val = options.src !== '' && options.resolveUrls ? options.resolve(value, options.src).absolute : value; } } - if (t.chi[0]?.typ == EnumToken.UrlTokenTokenType) { + if ((t as FunctionURLToken).chi[0]?.typ == EnumToken.UrlTokenTokenType) { if (options.src !== '' && options.resolveUrls) { // @ts-ignore - t.chi[0].val = options.resolve(t.chi[0].val, options.src, options.cwd).relative; + (t as FunctionURLToken).chi[0].val = options.resolve((t as FunctionURLToken).chi[0].val, options.src, options.cwd).relative; } } } // @ts-ignore if (t.chi.length > 0) { - if (t.typ == EnumToken.PseudoClassFuncTokenType && t.val == ':is' && options.minify) { + if (t.typ == EnumToken.PseudoClassFuncTokenType && (t as PseudoClassFunctionToken).val == ':is' && options.minify) { // - const count = t.chi.filter(t => t.typ != EnumToken.CommentTokenType).length; + const count: number = (t as PseudoClassFunctionToken).chi.filter((t: Token): boolean => t.typ != EnumToken.CommentTokenType).length; if (count == 1 || (i == 0 && (tokens[i + 1]?.typ == EnumToken.CommaTokenType || tokens.length == i + 1)) || (tokens[i - 1]?.typ == EnumToken.CommaTokenType && (tokens[i + 1]?.typ == EnumToken.CommaTokenType || tokens.length == i + 1))) { - tokens.splice(i, 1, ...t.chi); - i = Math.max(0, i - t.chi.length); + tokens.splice(i, 1, ...(t as PseudoClassFunctionToken).chi); + i = Math.max(0, i - (t as PseudoClassFunctionToken).chi.length); } } } @@ -2108,7 +2134,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T if (t.typ == EnumToken.IdenTokenType) { // named color - const value: string = t.val.toLowerCase(); + const value: string = (t as IdentToken).val.toLowerCase(); if (value in COLORS_NAMES) { Object.assign(t, { @@ -2121,7 +2147,7 @@ export function parseTokens(tokens: Token[], options: ParseTokenOptions = {}): T continue; } - if (t.typ == EnumToken.HashTokenType && isHexColor(t.val)) { + if (t.typ == EnumToken.HashTokenType && isHexColor((t as HashToken).val)) { // hex color // @ts-ignore t.typ = EnumToken.ColorTokenType; diff --git a/src/lib/parser/utils/declaration.ts b/src/lib/parser/utils/declaration.ts index d5edb4de..4737adc1 100644 --- a/src/lib/parser/utils/declaration.ts +++ b/src/lib/parser/utils/declaration.ts @@ -1,6 +1,15 @@ -import type {AstDeclaration, ErrorDescription, FunctionToken, ParensToken, Position, Token} from "../../../@types/index.d.ts"; -import {EnumToken, walkValues} from "../../ast"; -import {isWhiteSpace} from "../../syntax/syntax"; +import type { + AstDeclaration, + AttrToken, + ErrorDescription, + FunctionToken, + ParensToken, + Position, + StringToken, + Token +} from "../../../@types/index.d.ts"; +import {EnumToken, walkValues} from "../../ast/index.ts"; +import {isWhiteSpace} from "../../syntax/syntax.ts"; export function parseDeclarationNode(node: AstDeclaration, errors: ErrorDescription[], src: string, position: Position): AstDeclaration | null { @@ -21,14 +30,14 @@ export function parseDeclarationNode(node: AstDeclaration, errors: ErrorDescript for (const {value: val, parent} of walkValues(node.val, node)) { - if (val.typ == EnumToken.AttrTokenType && val.chi.every((t: Token) => [EnumToken.IdenTokenType, EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ))) { + if (val.typ == EnumToken.AttrTokenType && (val as AttrToken).chi.every((t: Token) => [EnumToken.IdenTokenType, EnumToken.WhitespaceTokenType, EnumToken.CommentTokenType].includes(t.typ))) { // @ts-ignore val.typ = EnumToken.IdenListTokenType; } else if (val.typ == EnumToken.StringTokenType && (node.nam == 'grid' || node.nam == 'grid-template-areas' || node.nam == 'grid-template-rows' || node.nam == 'grid-template-columns')) { - val.val = val.val.at(0) + parseGridTemplate(val.val.slice(1, -1)) + val.val.at(-1); + (val as StringToken).val = (val as StringToken).val.at(0) + parseGridTemplate((val as StringToken).val.slice(1, -1)) + (val as StringToken).val.at(-1); // @ts-ignore const array: Token[] = (parent)?.chi ?? node.val; diff --git a/src/lib/parser/utils/index.ts b/src/lib/parser/utils/index.ts index a679e82f..9b9d8fbb 100644 --- a/src/lib/parser/utils/index.ts +++ b/src/lib/parser/utils/index.ts @@ -1,4 +1,4 @@ -export * from './config'; -export * from './type'; -export * from './declaration'; \ No newline at end of file +export * from './config.ts'; +export * from './type.ts'; +export * from './declaration.ts'; \ No newline at end of file diff --git a/src/lib/parser/utils/type.ts b/src/lib/parser/utils/type.ts index 545b72d5..c57b0e97 100644 --- a/src/lib/parser/utils/type.ts +++ b/src/lib/parser/utils/type.ts @@ -1,5 +1,5 @@ import {EnumToken} from "../../ast"; -import type {IdentToken, PropertyMapType, Token} from "../../../@types/index.d.ts"; +import type {FunctionToken, IdentToken, NumberToken, PropertyMapType, Token} from "../../../@types/index.d.ts"; import {mathFuncs} from "../../syntax"; @@ -12,22 +12,22 @@ export function matchType(val: Token, properties: PropertyMapType): boolean { return true; } - if (val.typ == EnumToken.NumberTokenType && val.val == '0') { + if (val.typ == EnumToken.NumberTokenType && (val as NumberToken).val == '0') { // @ts-ignore return properties.types.some((type: keyof EnumToken) => { // @ts-ignore - const typ = EnumToken[type]; + const typ = EnumToken[type] as EnumToken; return typ == EnumToken.LengthTokenType || typ == EnumToken.AngleTokenType }) } if (val.typ == EnumToken.FunctionTokenType) { - if (mathFuncs.includes(val.val)) { + if (mathFuncs.includes((val as FunctionToken).val)) { - return val.chi.every(((t: Token) => [EnumToken.Add,EnumToken.Mul,EnumToken.Div,EnumToken.Sub,EnumToken.LiteralTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.DimensionTokenType, EnumToken.NumberTokenType, EnumToken.LengthTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.ResolutionTokenType, EnumToken.TimeTokenType, EnumToken.BinaryExpressionTokenType].includes(t.typ) || matchType(t, properties))); + return (val as FunctionToken).chi.every(((t: Token): boolean => [EnumToken.Add,EnumToken.Mul,EnumToken.Div,EnumToken.Sub,EnumToken.LiteralTokenType, EnumToken.CommaTokenType, EnumToken.WhitespaceTokenType, EnumToken.DimensionTokenType, EnumToken.NumberTokenType, EnumToken.LengthTokenType, EnumToken.AngleTokenType, EnumToken.PercentageTokenType, EnumToken.ResolutionTokenType, EnumToken.TimeTokenType, EnumToken.BinaryExpressionTokenType].includes(t.typ) || matchType(t, properties))); } // match type defined like function 'symbols()', 'url()', 'attr()' etc. diff --git a/src/lib/renderer/color/color.ts b/src/lib/renderer/color/color.ts index 07e5ed87..d9d78bdf 100644 --- a/src/lib/renderer/color/color.ts +++ b/src/lib/renderer/color/color.ts @@ -25,15 +25,16 @@ import { lch2srgb, lsrgb2srgbvalues, oklab2srgb, - rgb2srgb, srgb2lsrgbvalues, + rgb2srgb, + srgb2lsrgbvalues, xyz2srgb } from "./srgb"; import {prophotorgb2srgbvalues, srgb2prophotorgbvalues} from "./prophotorgb"; import {a98rgb2srgbvalues, srgb2a98values} from "./a98rgb"; import {rec20202srgb, srgb2rec2020values} from "./rec2020"; -import {srgb2xyz, xyzd502srgb} from "./xyz"; +import {srgb2xyz} from "./xyz"; import {p32srgbvalues, srgb2p3values} from "./p3"; -import {XYZ_D65_to_D50} from "./xyzd50"; +import {XYZ_D65_to_D50, xyzd502srgb} from "./xyzd50"; export function convert(token: ColorToken, to: ColorKind | ColorSpace): ColorToken | null { diff --git a/src/lib/renderer/color/index.ts b/src/lib/renderer/color/index.ts index 90ffb5fe..9f3e7736 100644 --- a/src/lib/renderer/color/index.ts +++ b/src/lib/renderer/color/index.ts @@ -1,18 +1,18 @@ -export * from './color'; -export * from './rgb'; -export * from './hex'; -export * from './hwb'; -export * from './hsl'; -export * from './colormix'; -export * from './oklab'; -export * from './oklch'; -export * from './srgb'; -export * from './xyz'; -export * from './lab'; -export * from './lch'; -export * from './relativecolor'; -export * from './xyzd50'; -export * from './prophotorgb'; -export * from './a98rgb'; -export * from './rec2020'; -export {NAMES_COLORS, COLORS_NAMES} from "./utils"; \ No newline at end of file +export * from './color.ts'; +export * from './rgb.ts'; +export * from './hex.ts'; +export * from './hwb.ts'; +export * from './hsl.ts'; +export * from './colormix.ts'; +export * from './oklab.ts'; +export * from './oklch.ts'; +export * from './srgb.ts'; +export * from './xyz.ts'; +export * from './lab.ts'; +export * from './lch.ts'; +export * from './relativecolor.ts'; +export * from './xyzd50.ts'; +export * from './prophotorgb.ts'; +export * from './a98rgb.ts'; +export * from './rec2020.ts'; +export {NAMES_COLORS, COLORS_NAMES} from "./utils/index.ts"; \ No newline at end of file diff --git a/src/lib/renderer/color/lab.ts b/src/lib/renderer/color/lab.ts index 997bf180..fed69afc 100644 --- a/src/lib/renderer/color/lab.ts +++ b/src/lib/renderer/color/lab.ts @@ -1,11 +1,12 @@ import {D50, e, getComponents, k} from "./utils"; -import {srgb2xyz, xyzd502srgb} from "./xyz"; +import {srgb2xyz} from "./xyz"; import type {ColorToken, NumberToken, PercentageToken, Token} from "../../../@types/index.d.ts"; import {hex2srgb, hsl2srgb, hwb2srgb, oklch2srgb, rgb2srgb} from "./srgb"; import {getLCHComponents} from "./lch"; import {getOKLABComponents, OKLab_to_XYZ} from "./oklab"; import {getNumber} from "./color"; import {EnumToken} from "../../ast"; +import {xyzd502srgb} from "./xyzd50"; // L: 0% = 0.0, 100% = 100.0 // for a and b: -100% = -125, 100% = 125 diff --git a/src/lib/renderer/color/prophotorgb.ts b/src/lib/renderer/color/prophotorgb.ts index e999c478..f77ac9b8 100644 --- a/src/lib/renderer/color/prophotorgb.ts +++ b/src/lib/renderer/color/prophotorgb.ts @@ -1,5 +1,5 @@ -import {srgb2xyz, xyzd502srgb} from "./xyz"; -import {XYZ_D65_to_D50} from "./xyzd50"; +import {srgb2xyz} from "./xyz"; +import {XYZ_D65_to_D50, xyzd502srgb} from "./xyzd50"; export function prophotorgb2srgbvalues(r: number, g: number, b: number, a: number | null = null): number[] { diff --git a/src/lib/renderer/color/relativecolor.ts b/src/lib/renderer/color/relativecolor.ts index 6b4159b2..cd80e9b4 100644 --- a/src/lib/renderer/color/relativecolor.ts +++ b/src/lib/renderer/color/relativecolor.ts @@ -12,7 +12,6 @@ import {EnumToken, walkValues} from "../../ast"; import {reduceNumber} from "../render"; import {evaluate, evaluateFunc} from "../../ast/math"; import {colorRange} from "./utils"; -import {eq} from "../../parser/utils/eq"; import {mathFuncs} from "../../syntax"; type RGBKeyType = 'r' | 'g' | 'b' | 'alpha'; @@ -164,9 +163,9 @@ function computeComponentValue(expr: Record, converte expr[key] = values[exp.val]; } - } else if (exp.typ == EnumToken.FunctionTokenType && mathFuncs.includes(exp.val)) { + } else if (exp.typ == EnumToken.FunctionTokenType && mathFuncs.includes((exp as FunctionToken).val)) { - for (let {value, parent} of walkValues(exp.chi, exp)) { + for (let {value, parent} of walkValues((exp as FunctionToken).chi, exp)) { if (parent == null) { @@ -194,7 +193,7 @@ function computeComponentValue(expr: Record, converte } } - const result: Token[] = exp.typ == EnumToken.FunctionTokenType && mathFuncs.includes(exp.val) && exp.val != 'calc' ? evaluateFunc(exp) : evaluate(exp.chi); + const result: Token[] = exp.typ == EnumToken.FunctionTokenType && mathFuncs.includes((exp as FunctionToken).val) && (exp as FunctionToken).val != 'calc' ? evaluateFunc(exp as FunctionToken) : evaluate((exp as FunctionToken).chi); if (result.length == 1 && result[0].typ != EnumToken.BinaryExpressionTokenType) { @@ -212,32 +211,32 @@ function computeComponentValue(expr: Record, converte function replaceValue(parent: FunctionToken | ParensToken | BinaryExpressionToken, value: Token, newValue: Token) { if (parent.typ == EnumToken.BinaryExpressionTokenType) { - if (parent.l == value) { + if ((parent as BinaryExpressionToken).l == value) { - parent.l = newValue; + (parent as BinaryExpressionToken).l = newValue; } else { - parent.r = newValue; + (parent as BinaryExpressionToken).r = newValue; } } else { - for (let i = 0; i < parent.chi.length; i++) { + for (let i = 0; i < (parent as FunctionToken | ParensToken).chi.length; i++) { - if (parent.chi[i] == value) { + if ((parent as FunctionToken | ParensToken).chi[i] == value) { - parent.chi.splice(i, 1, newValue); + (parent as FunctionToken | ParensToken).chi.splice(i, 1, newValue); break; } - if (parent.chi[i].typ == EnumToken.BinaryExpressionTokenType) { + if ((parent as FunctionToken | ParensToken).chi[i].typ == EnumToken.BinaryExpressionTokenType) { - if ((parent.chi[i] as BinaryExpressionToken).l == value) { + if (((parent as FunctionToken | ParensToken).chi[i] as BinaryExpressionToken).l == value) { - (parent.chi[i] as BinaryExpressionToken).l = newValue; + ((parent as FunctionToken | ParensToken).chi[i] as BinaryExpressionToken).l = newValue; break; - } else if ((parent.chi[i] as BinaryExpressionToken).r == value) { + } else if (((parent as FunctionToken | ParensToken).chi[i] as BinaryExpressionToken).r == value) { - (parent.chi[i] as BinaryExpressionToken).r = newValue; + ((parent as FunctionToken | ParensToken).chi[i] as BinaryExpressionToken).r = newValue; break } } diff --git a/src/lib/renderer/color/srgb.ts b/src/lib/renderer/color/srgb.ts index c154cfd1..69783c7d 100644 --- a/src/lib/renderer/color/srgb.ts +++ b/src/lib/renderer/color/srgb.ts @@ -1,16 +1,23 @@ // from https://www.w3.org/TR/css-color-4/#color-conversion-code // srgb-linear -> srgb // 0 <= r, g, b <= 1 -import {COLORS_NAMES, getComponents} from "./utils"; -import type {ColorToken, DimensionToken, IdentToken, NumberToken, PercentageToken, Token} from "../../../@types/index.d.ts"; -import {color2srgbvalues, getAngle, getNumber} from "./color"; -import {EnumToken} from "../../ast"; -import {getLABComponents, Lab_to_sRGB, lch2labvalues} from "./lab"; -import {expandHexValue} from "./hex"; -import {getOKLABComponents, OKLab_to_sRGB} from "./oklab"; -import {getLCHComponents} from "./lch"; -import {getOKLCHComponents} from "./oklch"; -import {XYZ_to_lin_sRGB} from "./xyz"; +import {COLORS_NAMES, getComponents} from "./utils/index.ts"; +import type { + ColorToken, + DimensionToken, + IdentToken, + NumberToken, + PercentageToken, + Token +} from "../../../@types/index.d.ts"; +import {color2srgbvalues, getAngle, getNumber} from "./color.ts"; +import {EnumToken} from "../../ast/index.ts"; +import {getLABComponents, Lab_to_sRGB, lch2labvalues} from "./lab.ts"; +import {expandHexValue} from "./hex.ts"; +import {getOKLABComponents, OKLab_to_sRGB} from "./oklab.ts"; +import {getLCHComponents} from "./lch.ts"; +import {getOKLCHComponents} from "./oklch.ts"; +import {XYZ_to_lin_sRGB} from "./xyz.ts"; export function srgbvalues(token: ColorToken): number[] | null { @@ -53,7 +60,7 @@ export function srgbvalues(token: ColorToken): number[] | null { export function rgb2srgb(token: ColorToken): number[] { - return getComponents(token).map((t: Token, index: number) => index == 3 ? ((t.typ == EnumToken.IdenTokenType && t.val == 'none') ? 1 : getNumber(t)) : (t.typ == EnumToken.PercentageTokenType ? 255 : 1) * getNumber(t) / 255); + return getComponents(token).map((t: Token, index: number): number => index == 3 ? ((t.typ == EnumToken.IdenTokenType && (t as IdentToken).val == 'none') ? 1 : getNumber(t)) : (t.typ == EnumToken.PercentageTokenType ? 255 : 1) * getNumber(t) / 255); } export function hex2srgb(token: ColorToken): number[] { diff --git a/src/lib/renderer/color/utils/components.ts b/src/lib/renderer/color/utils/components.ts index 3fb8f899..c593fb60 100644 --- a/src/lib/renderer/color/utils/components.ts +++ b/src/lib/renderer/color/utils/components.ts @@ -1,7 +1,7 @@ import type {ColorToken, NumberToken, Token} from "../../../../@types/index.d.ts"; -import {EnumToken} from "../../../ast"; -import {COLORS_NAMES} from "./constants"; -import {expandHexValue} from "../hex"; +import {EnumToken} from "../../../ast/index.ts"; +import {COLORS_NAMES} from "./constants.ts"; +import {expandHexValue} from "../hex.ts"; export function getComponents(token: ColorToken): Token[] { diff --git a/src/lib/renderer/color/utils/index.ts b/src/lib/renderer/color/utils/index.ts index e0acfe7e..67f59fc4 100644 --- a/src/lib/renderer/color/utils/index.ts +++ b/src/lib/renderer/color/utils/index.ts @@ -1,4 +1,4 @@ -export * from './matrix'; -export * from './constants'; -export * from './components'; +export * from './matrix.ts'; +export * from './constants.ts'; +export * from './components.ts'; diff --git a/src/lib/renderer/color/xyz.ts b/src/lib/renderer/color/xyz.ts index 086c4274..c12dd028 100644 --- a/src/lib/renderer/color/xyz.ts +++ b/src/lib/renderer/color/xyz.ts @@ -1,5 +1,5 @@ import {multiplyMatrices} from "./utils"; -import {lsrgb2srgbvalues, srgb2lsrgbvalues} from "./srgb"; +import {srgb2lsrgbvalues} from "./srgb"; import {Lab_to_XYZ} from "./lab"; export function lab2xyz(l: number, a: number, b: number, alpha?: number): number[] { @@ -15,24 +15,6 @@ export function lch2xyz(l: number, c: number, h: number, alpha?: number): number } -export function xyzd502srgb(x: number, y: number, z: number): number[] { - - // @ts-ignore - return lsrgb2srgbvalues( - /* r: */ - x * 3.1341359569958707 - - y * 1.6173863321612538 - - 0.4906619460083532 * z, - /* g: */ - x * -0.978795502912089 + - y * 1.916254567259524 + - 0.03344273116131949 * z, - /* b: */ - x * 0.07195537988411677 - - y * 0.2289768264158322 + - 1.405386058324125 * z); -} - export function XYZ_to_lin_sRGB(x: number, y: number, z: number): number[] { // convert XYZ to linear-light sRGB diff --git a/src/lib/renderer/color/xyzd50.ts b/src/lib/renderer/color/xyzd50.ts index ce45e80e..f85fd13e 100644 --- a/src/lib/renderer/color/xyzd50.ts +++ b/src/lib/renderer/color/xyzd50.ts @@ -1,14 +1,17 @@ +import {lsrgb2srgbvalues} from "./srgb"; import {multiplyMatrices} from "./utils"; import {xyz2lab} from "./lab"; -import {lab2lchvalues} from "./lch"; import {XYZ_D50_to_D65} from "./xyz"; +import {lab2lchvalues} from "./lch"; + +/* +*/ export function xyzd502lch(x: number, y: number, z: number, alpha?: number): number[] { // @ts-ignore const [l, a, b] = xyz2lab(...XYZ_D50_to_D65(x, y, z)); // L in range [0,100]. For use in CSS, add a percent - // @ts-ignore return lab2lchvalues(l, a, b, alpha); } @@ -28,3 +31,21 @@ export function XYZ_D65_to_D50(x: number, y: number, z: number): number[] { return multiplyMatrices(M, [x, y, z]); } + +export function xyzd502srgb(x: number, y: number, z: number): number[] { + + // @ts-ignore + return lsrgb2srgbvalues( + /* r: */ + x * 3.1341359569958707 - + y * 1.6173863321612538 - + 0.4906619460083532 * z, + /* g: */ + x * -0.978795502912089 + + y * 1.916254567259524 + + 0.03344273116131949 * z, + /* b: */ + x * 0.07195537988411677 - + y * 0.2289768264158322 + + 1.405386058324125 * z); +} \ No newline at end of file diff --git a/src/lib/renderer/index.ts b/src/lib/renderer/index.ts index c25e1ba7..fe099b3b 100644 --- a/src/lib/renderer/index.ts +++ b/src/lib/renderer/index.ts @@ -1,2 +1,2 @@ -export * from './render'; \ No newline at end of file +export * from './render.ts'; \ No newline at end of file diff --git a/src/lib/renderer/render.ts b/src/lib/renderer/render.ts index b9d45efa..5065c5f4 100644 --- a/src/lib/renderer/render.ts +++ b/src/lib/renderer/render.ts @@ -47,7 +47,7 @@ import { import {EnumToken, expand} from "../ast"; import {SourceMap} from "./sourcemap"; import {colorFuncColorSpace, getComponents} from "./color/utils"; -import {isColor, isNewLine, mathFuncs} from "../syntax"; +import {isColor, isNewLine, mathFuncs, pseudoElements} from "../syntax"; export const colorsFunc: string[] = ['rgb', 'rgba', 'hsl', 'hsla', 'hwb', 'device-cmyk', 'color-mix', 'color', 'oklab', 'lab', 'oklch', 'lch', 'light-dark']; @@ -271,7 +271,7 @@ function renderAstNode(data: AstNode, options: RenderOptions, sourcemap: SourceM case EnumToken.StyleSheetNodeType: - return (data).chi.reduce((css: string, node) => { + return (data).chi.reduce((css: string, node: AstRuleList | AstComment) => { const str: string = renderAstNode(node, options, sourcemap, {...position}, errors, reducer, cache, level, indents); @@ -926,7 +926,7 @@ export function renderToken(token: Token, options: RenderOptions = {}, cache: { case EnumToken.PseudoElementTokenType: // https://www.w3.org/TR/selectors-4/#single-colon-pseudos - if (token.typ == EnumToken.PseudoElementTokenType && ['::before', '::after', '::first-line', '::first-letter'].includes(token.val)) { + if (token.typ == EnumToken.PseudoElementTokenType && pseudoElements.includes(token.val.slice(1))) { return token.val.slice(1); } @@ -982,7 +982,7 @@ export function renderToken(token: Token, options: RenderOptions = {}, cache: { case EnumToken.InvalidAttrTokenType: - return '[' + (token).chi.reduce((acc, curr) => acc + renderToken(curr, options, cache), ''); + return '[' + (token).chi.reduce((acc: string, curr: Token): string => acc + renderToken(curr, options, cache), ''); case EnumToken.InvalidClassSelectorTokenType: diff --git a/src/lib/renderer/sourcemap/index.ts b/src/lib/renderer/sourcemap/index.ts index f8a20e15..843e95f6 100644 --- a/src/lib/renderer/sourcemap/index.ts +++ b/src/lib/renderer/sourcemap/index.ts @@ -1 +1 @@ -export * from './sourcemap'; +export * from './sourcemap.ts'; diff --git a/src/lib/renderer/sourcemap/lib/index.ts b/src/lib/renderer/sourcemap/lib/index.ts index cb17a3da..082de791 100644 --- a/src/lib/renderer/sourcemap/lib/index.ts +++ b/src/lib/renderer/sourcemap/lib/index.ts @@ -1,3 +1,3 @@ -export * from './encode'; \ No newline at end of file +export * from './encode.ts'; \ No newline at end of file diff --git a/src/lib/renderer/sourcemap/sourcemap.ts b/src/lib/renderer/sourcemap/sourcemap.ts index af74634f..e2b577a4 100644 --- a/src/lib/renderer/sourcemap/sourcemap.ts +++ b/src/lib/renderer/sourcemap/sourcemap.ts @@ -1,14 +1,13 @@ -import type {Location, SourceMapObject} from "../../../@types"; -import {encode} from "./lib"; +import type {Location, SourceMapObject} from "../../../@types/index.d.ts"; +import {encode} from "./lib/index.ts"; export class SourceMap { + lastLocation: Location | null = null; #version: number = 3; #sources: string[] = []; - #map: Map = new Map; #line: number = -1; - lastLocation: Location | null = null; add(source: Location, original: Location) { diff --git a/src/lib/syntax/index.ts b/src/lib/syntax/index.ts index ab11247c..d50b4541 100644 --- a/src/lib/syntax/index.ts +++ b/src/lib/syntax/index.ts @@ -1,2 +1,2 @@ -export * from './syntax'; \ No newline at end of file +export * from './syntax.ts'; \ No newline at end of file diff --git a/src/lib/syntax/syntax.ts b/src/lib/syntax/syntax.ts index ded42dcf..03df6430 100644 --- a/src/lib/syntax/syntax.ts +++ b/src/lib/syntax/syntax.ts @@ -36,6 +36,7 @@ export const mediaTypes: string[] = ['all', 'print', 'screen', // https://www.w3.org/TR/css-values-4/#math-function export const mathFuncs: string[] = ['calc', 'clamp', 'min', 'max', 'round', 'mod', 'rem', 'sin', 'cos', 'tan', 'asin', 'acos', 'atan', 'atan2', 'pow', 'sqrt', 'hypot', 'log', 'exp', 'abs', 'sign']; +export const pseudoElements: string[] = [':before', ':after', ':first-line', ':first-letter']; export const webkitPseudoAliasMap: Record = { '-webkit-autofill': 'autofill', '-webkit-any': 'is', diff --git a/src/lib/validation/at-rules/document.ts b/src/lib/validation/at-rules/document.ts index d28a57ca..6ab49bd8 100644 --- a/src/lib/validation/at-rules/document.ts +++ b/src/lib/validation/at-rules/document.ts @@ -1,7 +1,7 @@ import type {AstAtRule, AstNode, FunctionToken, Token, ValidationOptions} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; import {EnumToken, ValidationLevel} from "../../ast"; -import {consumeWhitespace} from "../utils"; +import {consumeWhitespace, splitTokenList} from "../utils"; import {validateURL} from "../syntaxes/url"; @@ -38,90 +38,65 @@ export function validateAtRuleDocument(atRule: AstAtRule, options: ValidationOpt } as ValidationSyntaxResult; } - if (tokens[0].typ == EnumToken.CommaTokenType) { + for (const t of splitTokenList(tokens)) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - } - } - - while (tokens.length > 0) { + if (t.length != 1) { - if (tokens[0].typ == EnumToken.CommentTokenType) { - - tokens.shift(); - consumeWhitespace(tokens); + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'unexpected token', + tokens + }; } - result = validateURL(tokens[0]); - - if (result.valid == ValidationLevel.Valid) { - tokens.shift(); - consumeWhitespace(tokens); - continue; + // @ts-ignore + if ((t[0].typ != EnumToken.FunctionTokenType && t[0].typ != EnumToken.UrlFunctionTokenType) || !['url', 'url-prefix', 'domain', 'media-document', 'regexp'].some((f) => f.localeCompare((t[0] as FunctionToken).val, undefined, {sensitivity: 'base'}) == 0)) { + + return { + valid: ValidationLevel.Drop, + matches: [], + node: t[0] ?? atRule, + syntax: '@document', + error: 'expecting any of url-prefix(), domain(), media-document(), regexp() but found ' + (t[0] as FunctionToken).val, + tokens + } } - if (tokens[0].typ == EnumToken.FunctionTokenType) { - - if (!['url-prefix', 'domain', 'media-document', 'regexp'].some((t) => t.localeCompare((tokens[0] as FunctionToken).val, undefined, {sensitivity: 'base'}) == 0)) { + if (t[0].typ == EnumToken.UrlFunctionTokenType) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'unexpected token', - tokens - } - } + result = validateURL(t[0]); - const children = (tokens[0] as FunctionToken).chi.slice() as Token[]; + if (result.valid == ValidationLevel.Drop) { - consumeWhitespace(children); + return result; + } - if (children.length == 0) { + continue; + } - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@document', - error: 'expecting string argument', - tokens - } - } + const children = (t[0] as FunctionToken).chi.slice() as Token[]; - if (children[0].typ == EnumToken.StringTokenType) { + consumeWhitespace(children); - children.shift(); - consumeWhitespace(children); - } + if (children.length != 1 || (children[0].typ != EnumToken.StringTokenType && children[0].typ != EnumToken.UrlTokenTokenType)) { - if (children.length > 0) { - - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: children[0], - syntax: '@document', - error: 'unexpected token', - tokens - } + // @ts-ignore + return { + valid: ValidationLevel.Drop, + matches: [], + node: tokens[0], + syntax: '@document', + error: 'expecting string argument', + tokens } - - tokens.shift(); - consumeWhitespace(tokens); } + + tokens.shift(); + consumeWhitespace(tokens); } // @ts-ignore diff --git a/src/lib/validation/at-rules/import.ts b/src/lib/validation/at-rules/import.ts index 0e039081..1e217055 100644 --- a/src/lib/validation/at-rules/import.ts +++ b/src/lib/validation/at-rules/import.ts @@ -1,10 +1,10 @@ -import type {AstAtRule, AstNode, Token, ValidationOptions} from "../../../@types"; +import type {AstAtRule, AstNode, FunctionToken, Token, ValidationOptions} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; import {EnumToken, ValidationLevel} from "../../ast"; -import {validateAtRuleSupports} from "./supports"; import {validateAtRuleMediaQueryList} from "./media"; import {consumeWhitespace} from "../utils"; import {validateLayerName} from "../syntaxes"; +import {validateAtRuleSupportsConditions} from "./supports"; export function validateAtRuleImport(atRule: AstAtRule, options: ValidationOptions, root?: AstNode): ValidationSyntaxResult { @@ -86,6 +86,11 @@ export function validateAtRuleImport(atRule: AstAtRule, options: ValidationOptio } as ValidationSyntaxResult; } } + + tokens.shift(); + // @ts-ignore + consumeWhitespace(tokens); + } else { // @ts-ignore @@ -129,89 +134,81 @@ export function validateAtRuleImport(atRule: AstAtRule, options: ValidationOptio else if (tokens[0].typ == EnumToken.FunctionTokenType) { // @ts-ignore - if ('layer'.localeCompare(tokens[0].val, undefined, {sensitivity: 'base'}) != 0) { - - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting layer()', - tokens - } - } - - // @ts-ignore - const result: ValidationSyntaxResult = validateLayerName(tokens[0].chi); - - if (result.valid == ValidationLevel.Drop) { - - return result; - } + if ('layer'.localeCompare(tokens[0].val, undefined, {sensitivity: 'base'}) == 0) { - tokens.shift(); + const result = validateLayerName((tokens[0] as FunctionToken).chi); - // @ts-ignore - if (!consumeWhitespace(tokens)) { + if (result.valid == ValidationLevel.Drop) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens + return result; } - } - } - } - - if (tokens.length > 0) { - - // @ts-ignore - if (tokens[0].typ == EnumToken.AtRuleTokenType) { - - if ((tokens[0] as AstAtRule).nam != 'supports') { + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting @supports or media query list', - tokens - } + consumeWhitespace(tokens); } // @ts-ignore - const result: ValidationSyntaxResult = validateAtRuleSupports(tokens[0] as AstAtRule, options, atRule); + if ('supports'.localeCompare(tokens[0]?.val, undefined, {sensitivity: 'base'}) == 0) { - if (result.valid == ValidationLevel.Drop) { + const result = validateAtRuleSupportsConditions(atRule, (tokens[0] as FunctionToken).chi) as ValidationSyntaxResult; - return result; - } - - tokens.shift(); + if (result.valid == ValidationLevel.Drop) { - // @ts-ignore - if (!consumeWhitespace(tokens)) { + return result; + } + tokens.shift(); // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: [], - node: tokens[0], - syntax: '@' + atRule.nam, - error: 'expecting whitespace', - tokens - } + consumeWhitespace(tokens); } } } + // if (tokens.length > 0) { + // + // // @ts-ignore + // if (tokens[0].typ == EnumToken.AtRuleTokenType) { + // + // if ((tokens[0] as AstAtRule).nam != 'supports') { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting @supports or media query list', + // tokens + // } + // } + // + // // @ts-ignore + // const result: ValidationSyntaxResult = validateAtRuleSupports(tokens[0] as AstAtRule, options, atRule); + // + // if (result.valid == ValidationLevel.Drop) { + // + // return result; + // } + // + // tokens.shift(); + // + // // @ts-ignore + // if (!consumeWhitespace(tokens)) { + // + // // @ts-ignore + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0], + // syntax: '@' + atRule.nam, + // error: 'expecting whitespace', + // tokens + // } + // } + // } + // } + if (tokens.length > 0) { return validateAtRuleMediaQueryList(tokens, atRule); diff --git a/src/lib/validation/at-rules/media.ts b/src/lib/validation/at-rules/media.ts index bb19bc26..05651c50 100644 --- a/src/lib/validation/at-rules/media.ts +++ b/src/lib/validation/at-rules/media.ts @@ -305,7 +305,7 @@ export function validateMediaCondition(token: Token, atRule: AstAtRule): boolean return validateMediaCondition(token.val, atRule); } - if (token.typ != EnumToken.ParensTokenType && !(['when', 'else'].includes(atRule.nam) && token.typ == EnumToken.FunctionTokenType && ['media', 'supports'].includes(token.val))) { + if (token.typ != EnumToken.ParensTokenType && !(['when', 'else', 'import'].includes(atRule.nam) && token.typ == EnumToken.FunctionTokenType && ['media', 'supports', 'selector'].includes(token.val))) { return false; } @@ -332,6 +332,8 @@ export function validateMediaCondition(token: Token, atRule: AstAtRule): boolean return chi[0].l.typ == EnumToken.IdenTokenType; } + console.error(chi[0].parent); + return false; } diff --git a/src/lib/validation/at-rules/supports.ts b/src/lib/validation/at-rules/supports.ts index aab4a503..a03121da 100644 --- a/src/lib/validation/at-rules/supports.ts +++ b/src/lib/validation/at-rules/supports.ts @@ -2,10 +2,9 @@ import type {AstAtRule, AstNode, IdentToken, MediaQueryConditionToken, Token, Va import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; import {EnumToken, ValidationLevel} from "../../ast"; import {consumeWhitespace, splitTokenList} from "../utils"; -import {validateSyntax} from "../syntax"; -import {getParsedSyntax} from "../config"; -import {ValidationSyntaxGroupEnum, ValidationToken} from "../parser"; import {colorFontTech, fontFeaturesTech, fontFormat} from "../../syntax"; +import {validateComplexSelector} from "../syntaxes/complex-selector"; +import {parseSelector} from "../../parser"; export function validateAtRuleSupports(atRule: AstAtRule, options: ValidationOptions, root?: AstNode): ValidationSyntaxResult { @@ -59,7 +58,9 @@ export function validateAtRuleSupports(atRule: AstAtRule, options: ValidationOpt } } -export function validateAtRuleSupportsConditions(atRule: AstAtRule, tokenList: Token[]): ValidationSyntaxResult | null { +export function validateAtRuleSupportsConditions(atRule: AstAtRule, tokenList: Token[]): ValidationSyntaxResult { + + let result: ValidationSyntaxResult | null = null; for (const tokens of splitTokenList(tokenList)) { @@ -77,14 +78,13 @@ export function validateAtRuleSupportsConditions(atRule: AstAtRule, tokenList: T } let previousToken: Token | null = null; - let result: ValidationSyntaxResult | null = null; while (tokens.length > 0) { result = validateSupportCondition(atRule, tokens[0]); // supports-condition - if (result == null || result.valid == ValidationLevel.Valid) { + if (result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); @@ -92,13 +92,46 @@ export function validateAtRuleSupportsConditions(atRule: AstAtRule, tokenList: T result = validateSupportFeature(tokens[0]); - if (result == null || result.valid == ValidationLevel.Valid) { + if (/*result == null || */ result.valid == ValidationLevel.Valid) { previousToken = tokens[0]; tokens.shift(); } else { - return result; + if (tokens[0].typ == EnumToken.ParensTokenType) { + + result = validateAtRuleSupportsConditions(atRule, tokens[0].chi); + + if (/* result == null || */ result.valid == ValidationLevel.Valid) { + + previousToken = tokens[0]; + tokens.shift(); + // continue; + } + + else { + + return result; + } + } + + else { + + return result; + } + + // if (result!= null && result.valid == ValidationLevel.Drop) { + // + // return { + // valid: ValidationLevel.Drop, + // matches: [], + // node: tokens[0] ?? atRule, + // syntax: '@' + atRule.nam, + // // @ts-ignore + // error: result.error as string ?? 'unexpected token', + // tokens: [] + // }; + // } } } @@ -166,10 +199,17 @@ export function validateAtRuleSupportsConditions(atRule: AstAtRule, tokenList: T } } - return null; + return { + valid: ValidationLevel.Valid, + matches: [], + node: atRule, + syntax: '@' + atRule.nam, + error: '', + tokens: [] + } } -export function validateSupportCondition(atRule: AstAtRule, token: Token): ValidationSyntaxResult | null { +export function validateSupportCondition(atRule: AstAtRule, token: Token): ValidationSyntaxResult{ if (token.typ == EnumToken.MediaFeatureNotTokenType) { @@ -252,7 +292,7 @@ function validateSupportFeature(token: Token): ValidationSyntaxResult { if (token.val.localeCompare('selector', undefined, {sensitivity: 'base'}) == 0) { - return validateSyntax(getParsedSyntax(ValidationSyntaxGroupEnum.Syntaxes, 'complex-selector') as ValidationToken[], token.chi); + return validateComplexSelector(parseSelector(token.chi)); } if (token.val.localeCompare('font-tech', undefined, {sensitivity: 'base'}) == 0) { diff --git a/src/lib/validation/config.json b/src/lib/validation/config.json index 7191701b..2b1e92e4 100644 --- a/src/lib/validation/config.json +++ b/src/lib/validation/config.json @@ -373,7 +373,7 @@ "syntax": "auto || " }, "backdrop-filter": { - "syntax": "none | " + "syntax": "none | " }, "backface-visibility": { "syntax": "visible | hidden" @@ -787,7 +787,7 @@ "syntax": "nonzero | evenodd" }, "filter": { - "syntax": "none | " + "syntax": "none | " }, "flex": { "syntax": "none | [ <'flex-grow'> <'flex-shrink'>? || <'flex-basis'> ]" @@ -1243,7 +1243,7 @@ "syntax": "" }, "outline": { - "syntax": "[ <'outline-width'> || <'outline-style'> || <'outline-color'> ]" + "syntax": "<'outline-width'> || <'outline-style'> || <'outline-color'>" }, "outline-color": { "syntax": "auto | " @@ -1672,7 +1672,7 @@ "syntax": "space-all | normal | space-first | trim-start" }, "text-transform": { - "syntax": "none | capitalize | uppercase | lowercase | full-width | full-size-kana" + "syntax": "none | [ capitalize | uppercase | lowercase ] || full-width || full-size-kana | math-auto" }, "text-underline-offset": { "syntax": "auto | | " @@ -1762,7 +1762,7 @@ "syntax": "visible | hidden | collapse" }, "white-space": { - "syntax": "normal | pre | nowrap | pre-wrap | pre-line | break-spaces | [ <'white-space-collapse'> || <'text-wrap'> ]" + "syntax": "normal | pre | pre-wrap | pre-line | <'white-space-collapse'> || <'text-wrap-mode'>" }, "white-space-collapse": { "syntax": "collapse | preserve | preserve-breaks | preserve-spaces | break-spaces" @@ -1798,7 +1798,7 @@ "syntax": "auto | " }, "zoom": { - "syntax": "normal | reset | | " + "syntax": "normal | reset | || " } }, "functions": { @@ -1839,7 +1839,7 @@ "syntax": "calc-size( , )" }, "circle": { - "syntax": "circle( [ ]? [ at ]? )" + "syntax": "circle( ? [ at ]? )" }, "clamp": { "syntax": "clamp( #{3} )" @@ -1875,7 +1875,7 @@ "syntax": "element( )" }, "ellipse": { - "syntax": "ellipse( [ {2} ]? [ at ]? )" + "syntax": "ellipse( ? [ at ]? )" }, "env": { "syntax": "env( , ? )" @@ -1890,16 +1890,16 @@ "syntax": "grayscale( [ | ]? )" }, "hsl": { - "syntax": "hsl( [ / ]? ) | hsl( , , , ? )" + "syntax": "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hsla": { - "syntax": "hsla( [ / ]? ) | hsla( , , , ? )" + "syntax": "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hue-rotate": { "syntax": "hue-rotate( [ | ]? )" }, "hwb": { - "syntax": "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + "syntax": "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hypot": { "syntax": "hypot( # )" @@ -1988,6 +1988,9 @@ "ray": { "syntax": "ray( && ? && contain? && [at ]? )" }, + "rect": { + "syntax": "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, "rem": { "syntax": "rem( , )" }, @@ -2001,10 +2004,10 @@ "syntax": "repeating-radial-gradient( [ || ]? [ at ]? , )" }, "rgb": { - "syntax": "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + "syntax": "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, "rgba": { - "syntax": "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + "syntax": "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, "rotate": { "syntax": "rotate( [ | ] )" @@ -2066,6 +2069,9 @@ "sqrt": { "syntax": "sqrt( )" }, + "symbols": { + "syntax": "symbols( ? [ | ]+ )" + }, "tan": { "syntax": "tan( )" }, @@ -2098,6 +2104,9 @@ }, "view": { "syntax": "view([ || <'view-timeline-inset'>]?)" + }, + "xywh": { + "syntax": "xywh( {2} {2} [ round <'border-radius'> ]? )" } }, "syntaxes": { @@ -2113,6 +2122,9 @@ "alpha-value": { "syntax": " | " }, + "an+b": { + "syntax": "odd | even | | | '+'?† n | -n | | '+'?† | | | '+'?† n | -n | | '+'?† n- | -n- | ['+' | '-'] | '+'?† n ['+' | '-'] | -n ['+' | '-'] " + }, "anchor()": { "syntax": "anchor( ? && , ? )" }, @@ -2234,7 +2246,7 @@ "syntax": "? && " }, "circle()": { - "syntax": "circle( [ ]? [ at ]? )" + "syntax": "circle( ? [ at ]? )" }, "clamp()": { "syntax": "clamp( #{3} )" @@ -2248,15 +2260,15 @@ "color": { "syntax": " | currentColor | | | " }, + "color()": { + "syntax": "color( [ from ]? [ / [ | none ] ]? )" + }, "color-base": { "syntax": " | | | | transparent" }, "color-function": { "syntax": " | | | | | | | | | " }, - "color()": { - "syntax": "color( [from ]? [ / [ | none ] ]? )" - }, "color-interpolation-method": { "syntax": "in [ | ? | ]" }, @@ -2365,6 +2377,9 @@ "dasharray": { "syntax": "[ [ | ]+ ]#" }, + "dashndashdigit-ident": { + "syntax": "" + }, "deprecated-system-color": { "syntax": "ActiveBorder | ActiveCaption | AppWorkspace | Background | ButtonHighlight | ButtonShadow | CaptionText | InactiveBorder | InactiveCaption | InactiveCaptionText | InfoBackground | InfoText | Menu | MenuText | Scrollbar | ThreeDDarkShadow | ThreeDFace | ThreeDHighlight | ThreeDLightShadow | ThreeDShadow | Window | WindowFrame | WindowText" }, @@ -2405,7 +2420,7 @@ "syntax": "element( )" }, "ellipse()": { - "syntax": "ellipse( [ {2} ]? [ at ]? )" + "syntax": "ellipse( ? [ at ]? )" }, "ending-shape": { "syntax": "circle | ellipse" @@ -2446,7 +2461,7 @@ "filter-function": { "syntax": " | | | | | | | | | " }, - "filter-function-list": { + "filter-value-list": { "syntax": "[ | ]+" }, "final-bg-layer": { @@ -2501,10 +2516,10 @@ "syntax": "[ historical-ligatures | no-historical-ligatures ]" }, "hsl()": { - "syntax": "hsl( [ / ]? ) | hsl( , , , ? )" + "syntax": "hsl( , , , ? ) | hsl( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hsla()": { - "syntax": "hsla( [ / ]? ) | hsla( , , , ? )" + "syntax": "hsla( , , , ? ) | hsla( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hue": { "syntax": " | " @@ -2516,7 +2531,7 @@ "syntax": "hue-rotate( [ | ]? )" }, "hwb()": { - "syntax": "hwb( [ | none] [ | none] [ | none] [ / [ | none] ]? )" + "syntax": "hwb( [ | none ] [ | | none ] [ | | none ] [ / [ | none ] ]? )" }, "hypot()": { "syntax": "hypot( # )" @@ -2524,6 +2539,9 @@ "id-selector": { "syntax": "" }, + "integer": { + "syntax": "" + }, "image": { "syntax": " | | | | | | " }, @@ -2689,6 +2707,18 @@ "mod()": { "syntax": "mod( , )" }, + "n-dimension": { + "syntax": "" + }, + "ndash-dimension": { + "syntax": "" + }, + "ndashdigit-dimension": { + "syntax": "" + }, + "ndashdigit-ident": { + "syntax": "" + }, "name-repeat": { "syntax": "repeat( [ | auto-fill ], + )" }, @@ -2701,9 +2731,6 @@ "ns-prefix": { "syntax": "[ | '*' ]? '|'" }, - "nth": { - "syntax": " | even | odd" - }, "number-percentage": { "syntax": " | " }, @@ -2812,9 +2839,15 @@ "quote": { "syntax": "open-quote | close-quote | no-open-quote | no-close-quote" }, + "radial-extent": { + "syntax": "closest-corner | closest-side | farthest-corner | farthest-side" + }, "radial-gradient()": { "syntax": "radial-gradient( [ || ]? [ at ]? , )" }, + "radial-size": { + "syntax": " | | {2}" + }, "ratio": { "syntax": " [ / ]?" }, @@ -2836,6 +2869,9 @@ "relative-size": { "syntax": "larger | smaller" }, + "rect()": { + "syntax": "rect( [ | auto ]{4} [ round <'border-radius'> ]? )" + }, "rem()": { "syntax": "rem( , )" }, @@ -2855,10 +2891,10 @@ "syntax": "reversed( )" }, "rgb()": { - "syntax": "rgb( {3} [ / ]? ) | rgb( {3} [ / ]? ) | rgb( #{3} , ? ) | rgb( #{3} , ? )" + "syntax": "rgb( #{3} , ? ) | rgb( #{3} , ? ) | rgb( [ | | none ]{3} [ / [ | none ] ]? )" }, "rgba()": { - "syntax": "rgba( {3} [ / ]? ) | rgba( {3} [ / ]? ) | rgba( #{3} , ? ) | rgba( #{3} , ? )" + "syntax": "rgba( #{3} , ? ) | rgba( #{3} , ? ) | rgba( [ | | none ]{3} [ / [ | none ] ]? )" }, "rotate()": { "syntax": "rotate( [ | ] )" @@ -2932,15 +2968,18 @@ "shape-box": { "syntax": " | margin-box" }, - "shape-radius": { - "syntax": " | closest-side | farthest-side" - }, "side-or-corner": { "syntax": "[ left | right ] || [ top | bottom ]" }, "sign()": { "syntax": "sign( )" }, + "signed-integer": { + "syntax": "" + }, + "signless-integer": { + "syntax": "" + }, "sin()": { "syntax": "sin( )" }, @@ -3013,6 +3052,12 @@ "symbol": { "syntax": " | | " }, + "symbols()": { + "syntax": "symbols( ? [ | ]+ )" + }, + "symbols-type": { + "syntax": "cyclic | numeric | alphabetic | symbolic | fixed" + }, "system-color": { "syntax": "AccentColor | AccentColorText | ActiveText | ButtonBorder | ButtonFace | ButtonText | Canvas | CanvasText | Field | FieldText | GrayText | Highlight | HighlightText | LinkText | Mark | MarkText | SelectedItem | SelectedItemText | VisitedText" }, @@ -3103,6 +3148,9 @@ "wq-name": { "syntax": "? " }, + "xywh()": { + "syntax": "xywh( {2} {2} [ round <'border-radius'> ]? )" + }, "xyz": { "syntax": "xyz | xyz-d50 | xyz-d65" }, @@ -3238,16 +3286,16 @@ "syntax": ":not( )" }, ":nth-child()": { - "syntax": ":nth-child( [ of ]? )" + "syntax": ":nth-child( [ of ]? )" }, ":nth-last-child()": { - "syntax": ":nth-last-child( [ of ]? )" + "syntax": ":nth-last-child( [ of ]? )" }, ":nth-last-of-type()": { - "syntax": ":nth-last-of-type( )" + "syntax": ":nth-last-of-type( )" }, ":nth-of-type()": { - "syntax": ":nth-of-type( )" + "syntax": ":nth-of-type( )" }, ":only-child": { "syntax": ":only-child" @@ -3530,7 +3578,7 @@ "syntax": "normal | " }, "font-display": { - "syntax": "[ auto | block | swap | fallback | optional ]" + "syntax": "auto | block | swap | fallback | optional" }, "font-family": { "syntax": "" diff --git a/src/lib/validation/declaration.ts b/src/lib/validation/declaration.ts index b7a88862..a9328b9c 100644 --- a/src/lib/validation/declaration.ts +++ b/src/lib/validation/declaration.ts @@ -1,9 +1,9 @@ -import type {AstAtRule, AstDeclaration, AstNode, ValidationOptions} from "../../@types"; +import type {AstAtRule, AstDeclaration, AstNode, ValidationOptions} from "../../@types/index.d.ts"; import type {ValidationConfiguration, ValidationResult} from "../../@types/validation"; -import {EnumToken, ValidationLevel} from "../ast"; -import {getParsedSyntax, getSyntaxConfig} from "./config"; -import {ParsedSyntax, ValidationSyntaxGroupEnum, ValidationToken} from "./parser"; -import {validateSyntax} from "./syntax"; +import {EnumToken, ValidationLevel} from "../ast/index.ts"; +import {getParsedSyntax, getSyntaxConfig} from "./config.ts"; +import {ParsedSyntax, ValidationSyntaxGroupEnum, ValidationToken} from "./parser/index.ts"; +import {validateSyntax} from "./syntax.ts"; export function validateDeclaration(declaration: AstDeclaration, options: ValidationOptions, root?: AstNode): ValidationResult { diff --git a/src/lib/validation/index.ts b/src/lib/validation/index.ts index b6d35e8d..f3350c23 100644 --- a/src/lib/validation/index.ts +++ b/src/lib/validation/index.ts @@ -1,7 +1,7 @@ -export * from './config'; -export * from './parser'; -export * from './selector'; -export * from './atrule'; -export * from './declaration'; +export * from './config.ts'; +export * from './parser/index.ts'; +export * from './selector.ts'; +export * from './atrule.ts'; +export * from './declaration.ts'; diff --git a/src/lib/validation/parser/index.ts b/src/lib/validation/parser/index.ts index 7f3b1932..6fe2468b 100644 --- a/src/lib/validation/parser/index.ts +++ b/src/lib/validation/parser/index.ts @@ -1,3 +1,3 @@ -export * from './types'; -export * from './parse'; \ No newline at end of file +export * from './types.ts'; +export * from './parse.ts'; \ No newline at end of file diff --git a/src/lib/validation/parser/parse.ts b/src/lib/validation/parser/parse.ts index 632cfd27..bdf05ab0 100644 --- a/src/lib/validation/parser/parse.ts +++ b/src/lib/validation/parser/parse.ts @@ -43,8 +43,8 @@ import { ValidationToken, ValidationTokenEnum, ValidationWhitespaceToken -} from "./index"; -import {isIdent, isPseudo} from '../../syntax'; +} from "./index.ts"; +import {isIdent, isPseudo} from '../../syntax/index.ts'; export enum WalkValidationTokenEnum { @@ -1517,7 +1517,7 @@ export function renderSyntax(token: ValidationToken, parent?: ValidationToken): case ValidationTokenEnum.Block: - return '{' + (token as ValidationBlockToken).chi.reduce((acc, t) => acc + renderSyntax(t), '') + '}'; + return '{' + (token as ValidationBlockToken).chi.reduce((acc: string, t: ValidationToken): string => acc + renderSyntax(t), '') + '}'; case ValidationTokenEnum.DeclarationDefinitionToken: diff --git a/src/lib/validation/selector.ts b/src/lib/validation/selector.ts index 742ca1e4..52d84ca1 100644 --- a/src/lib/validation/selector.ts +++ b/src/lib/validation/selector.ts @@ -1,8 +1,8 @@ -import type {AstAtRule, AstRule, AstRuleStyleSheet, Token, ValidationOptions} from "../../@types"; -import {EnumToken} from "../ast"; -import {validateKeyframeBlockList, validateRelativeSelectorList} from "./syntaxes"; -import type {ValidationResult} from "../../@types/validation"; -import {validateSelectorList} from "./syntaxes/selector-list"; +import type {AstAtRule, AstRule, AstRuleStyleSheet, Token, ValidationOptions} from "../../@types/index.d.ts"; +import {EnumToken} from "../ast/index.ts"; +import {validateKeyframeBlockList, validateRelativeSelectorList} from "./syntaxes/index.ts"; +import type {ValidationResult} from "../../@types/validation.d.ts"; +import {validateSelectorList} from "./syntaxes/selector-list.ts"; export function validateSelector(selector: Token[], options: ValidationOptions, root?: AstAtRule | AstRule | AstRuleStyleSheet): ValidationResult { diff --git a/src/lib/validation/syntax.ts b/src/lib/validation/syntax.ts index d27e417f..afd4f611 100644 --- a/src/lib/validation/syntax.ts +++ b/src/lib/validation/syntax.ts @@ -6,6 +6,7 @@ import { ValidationAtRuleDefinitionToken, ValidationAtRuleToken, ValidationBracketToken, + ValidationColumnArrayToken, ValidationColumnToken, ValidationDeclarationDefinitionToken, ValidationDeclarationToken, @@ -42,9 +43,10 @@ import type { import {EnumToken, funcLike, ValidationLevel} from "../ast"; import {getParsedSyntax, getSyntaxConfig} from "./config"; import type {ValidationConfiguration, ValidationSyntaxResult} from "../../@types/validation"; -import {isLength} from "../syntax"; -import {validateSelector} from "./selector"; -import {validateImage} from "./syntaxes"; +import {isLength} from "../syntax/index.ts"; +import {validateSelector} from "./selector.ts"; +import {validateImage} from "./syntaxes/index.ts"; +import {renderToken} from "../../web/index.ts"; const config: ValidationConfiguration = getSyntaxConfig(); @@ -83,14 +85,15 @@ export interface ValidationContext { cache?: WeakMap>; } -export function validateSyntax(syntaxes: ValidationToken[], tokens: Token[] | AstNode[], root?: AstNode, options?: ValidationOptions, context: ValidationContext = {level: 0}): ValidationSyntaxResult { +export function validateSyntax(syntaxes: ValidationToken[] | null, tokens: Token[] | AstNode[], root?: AstNode, options?: ValidationOptions, context: ValidationContext = {level: 0}): ValidationSyntaxResult { console.error(JSON.stringify({ - syntax: syntaxes.reduce((acc, curr) => acc + renderSyntax(curr), ''), - syntaxes, - tokens, + syntax: syntaxes?.reduce?.((acc, curr) => acc + renderSyntax(curr), ''), + // syntaxes, + tokens: tokens.reduce((acc, curr) => acc + renderToken(curr as Token), ''), s: new Error('bar').stack }, null, 1)); + if (syntaxes == null) { // @ts-ignore @@ -1205,7 +1208,7 @@ function doValidateSyntax(syntax: ValidationToken, token: Token | AstNode, token if (valid) { - const children: Token[] = (token as AttrToken).chi.filter(t => t.typ != EnumToken.WhitespaceTokenType && t.typ != EnumToken.CommaTokenType) + const children: Token[] = (token as AttrToken).chi.filter((t: Token): boolean => t.typ != EnumToken.WhitespaceTokenType && t.typ != EnumToken.CommaTokenType) valid = children.length == 1 && [ EnumToken.IdenTokenType, @@ -1913,9 +1916,56 @@ function doValidateSyntax(syntax: ValidationToken, token: Token | AstNode, token break; - case - ValidationTokenEnum.ColumnToken - : + case ValidationTokenEnum.ColumnArrayToken: { + + matches = [] as ValidationToken[]; + queue = [] as ValidationToken[]; + const children = (syntax as ValidationColumnArrayToken).chi; + let child: ValidationToken; + + while (child = children.shift() as ValidationColumnToken) { + + result = validateSyntax([child], tokens, root as AstNode, options, context); + + if (result.valid == ValidationLevel.Valid) { + + matches.push(child); + + consumeToken(tokens); + token = tokens[0]; + + if (queue.length > 0) { + + children.unshift(...queue); + queue = []; + } + + if (token == null) { + + break; + } + + } else { + + queue.push(child); + } + } + + valid = matches.length > 0; + result = { + + valid: valid ? ValidationLevel.Valid : ValidationLevel.Drop, + matches: valid ? [token] as Token[] : [], + node: valid ? null : token, + syntax, + error: valid ? '' : 'expecting token', + tokens + } as ValidationSyntaxResult + } + + break; + + case ValidationTokenEnum.ColumnToken: children = [...(syntax as ValidationColumnToken).l.slice(), ...(syntax as ValidationColumnToken).r.slice()] as ValidationToken[]; matches = [] as ValidationToken[]; diff --git a/src/lib/validation/syntaxes/bg-layer.ts b/src/lib/validation/syntaxes/bg-layer.ts new file mode 100644 index 00000000..ddf5161d --- /dev/null +++ b/src/lib/validation/syntaxes/bg-layer.ts @@ -0,0 +1,18 @@ +// [ ? ]* +import type {AstAtRule, AstRule, Token} from "../../../@types"; +import type {ValidationSelectorOptions, ValidationSyntaxResult} from "../../../@types/validation"; +import {ValidationLevel} from "../../ast"; + +export function validateBGLayers(tokens: Token[], root?: AstAtRule | AstRule, options?: ValidationSelectorOptions): ValidationSyntaxResult { + + return { + valid: ValidationLevel.Valid, + matches: [], + // @ts-ignore + node: root, + // @ts-ignore + syntax: null, + error: '', + tokens + } +} diff --git a/src/lib/validation/syntaxes/complex-selector-list.ts b/src/lib/validation/syntaxes/complex-selector-list.ts index a4226548..4350b129 100644 --- a/src/lib/validation/syntaxes/complex-selector-list.ts +++ b/src/lib/validation/syntaxes/complex-selector-list.ts @@ -1,8 +1,8 @@ -import type {AstAtRule, AstRule, Token} from "../../../@types"; +import type {AstAtRule, AstRule, Token} from "../../../@types/index.d.ts"; import type {ValidationSelectorOptions, ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {ValidationLevel} from "../../ast"; -import {validateSelector} from "./selector"; -import {consumeWhitespace, splitTokenList} from "../utils"; +import {ValidationLevel} from "../../ast/index.ts"; +import {validateSelector} from "./selector.ts"; +import {consumeWhitespace, splitTokenList} from "../utils/index.ts"; export function validateComplexSelectorList(tokens: Token[], root?: AstAtRule | AstRule, options?: ValidationSelectorOptions): ValidationSyntaxResult { @@ -28,7 +28,7 @@ export function validateComplexSelectorList(tokens: Token[], root?: AstAtRule | for (const t of splitTokenList(tokens)) { - result = validateSelector(t, root, options); + result = validateSelector(t, root, options) as ValidationSyntaxResult; if (result.valid == ValidationLevel.Drop) { diff --git a/src/lib/validation/syntaxes/complex-selector.ts b/src/lib/validation/syntaxes/complex-selector.ts index a33f43d2..7240029a 100644 --- a/src/lib/validation/syntaxes/complex-selector.ts +++ b/src/lib/validation/syntaxes/complex-selector.ts @@ -1,8 +1,8 @@ import type {AstAtRule, AstRule, Token} from "../../../@types"; import type {ValidationSelectorOptions, ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {consumeWhitespace, splitTokenList} from "../utils"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {validateCompoundSelector} from "./compound-selector"; +import {consumeWhitespace, splitTokenList} from "../utils/index.ts"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {validateCompoundSelector} from "./compound-selector.ts"; export const combinatorsTokens: EnumToken[] = [EnumToken.ChildCombinatorTokenType, EnumToken.ColumnCombinatorTokenType, // EnumToken.DescendantCombinatorTokenType, @@ -38,7 +38,7 @@ export function validateComplexSelector(tokens: Token[], root?: AstAtRule | AstR for (const t of splitTokenList(tokens, combinatorsTokens)) { - result = validateCompoundSelector(t, root, options); + result = validateCompoundSelector(t, root, options) as ValidationSyntaxResult; if (result.valid == ValidationLevel.Drop) { diff --git a/src/lib/validation/syntaxes/compound-selector.ts b/src/lib/validation/syntaxes/compound-selector.ts index 6f1942f5..21abdaef 100644 --- a/src/lib/validation/syntaxes/compound-selector.ts +++ b/src/lib/validation/syntaxes/compound-selector.ts @@ -1,13 +1,22 @@ -import type {AstAtRule, AstRule, Token} from "../../../@types"; +import type { + AstAtRule, + AstRule, + AttrToken, + MatchExpressionToken, + PseudoClassFunctionToken, + PseudoClassToken, + PseudoElementToken, + Token +} from "../../../@types/index.d.ts"; import type { ValidationConfiguration, ValidationSelectorOptions, ValidationSyntaxResult -} from "../../../@types/validation"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {consumeWhitespace} from "../utils"; -import {mozExtensions, webkitExtensions} from "../../syntax"; -import {getSyntaxConfig} from "../config"; +} from "../../../@types/validation.d.ts"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {consumeWhitespace} from "../utils/index.ts"; +import {mozExtensions, webkitExtensions} from "../../syntax/index.ts"; +import {getSyntaxConfig} from "../config.ts"; export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | AstRule, options?: ValidationSelectorOptions): ValidationSyntaxResult { @@ -75,12 +84,12 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast while (tokens.length > 0 && tokens[0].typ == EnumToken.PseudoClassFuncTokenType) { if ( - !mozExtensions.has(tokens[0].val + '()') && - !webkitExtensions.has(tokens[0].val + '()') && - !((tokens[0].val + '()') in config.selectors) + !mozExtensions.has((tokens[0] as PseudoClassFunctionToken).val + '()') && + !webkitExtensions.has((tokens[0] as PseudoClassFunctionToken).val + '()') && + !(((tokens[0] as PseudoClassFunctionToken).val + '()') in config.selectors) ) { - if (!options?.lenient || /^(:?)-webkit-/.test(tokens[0].val)) { + if (!options?.lenient || /^(:?)-webkit-/.test((tokens[0] as PseudoClassFunctionToken).val)) { // @ts-ignore return { @@ -89,7 +98,7 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast // @ts-ignore node: tokens[0], syntax: null, - error: 'unknown pseudo-class: ' + tokens[0].val + '()', + error: 'unknown pseudo-class: ' + (tokens[0] as PseudoClassFunctionToken).val + '()', tokens } } @@ -106,15 +115,15 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast if ( // https://developer.mozilla.org/en-US/docs/Web/CSS/WebKit_Extensions#pseudo-elements - !(isPseudoElement && tokens[0].val.startsWith('::-webkit-')) && - !mozExtensions.has(tokens[0].val) && - !webkitExtensions.has(tokens[0].val) && - !(tokens[0].val in config.selectors) && + !(isPseudoElement && (tokens[0] as PseudoClassToken | PseudoElementToken).val.startsWith('::-webkit-')) && + !mozExtensions.has((tokens[0] as PseudoClassToken | PseudoElementToken).val) && + !webkitExtensions.has((tokens[0] as PseudoClassToken | PseudoElementToken).val) && + !((tokens[0] as PseudoClassToken | PseudoElementToken).val in config.selectors) && !(!isPseudoElement && - (':' + tokens[0].val) in config.selectors) + (':' +(tokens[0] as PseudoClassToken | PseudoElementToken).val) in config.selectors) ) { - if (!options?.lenient || /^(:?)-webkit-/.test(tokens[0].val)) { + if (!options?.lenient || /^(:?)-webkit-/.test((tokens[0] as PseudoClassToken | PseudoElementToken).val)) { // @ts-ignore return { @@ -123,7 +132,7 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast // @ts-ignore node: tokens[0], syntax: null, - error: 'unknown pseudo-class: ' + tokens[0].val, + error: 'unknown pseudo-class: ' + (tokens[0] as PseudoClassToken | PseudoElementToken).val, tokens } } @@ -136,7 +145,7 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast while (tokens.length > 0 && tokens[0].typ == EnumToken.AttrTokenType) { - const children: Token[] = tokens[0].chi.slice() as Token[]; + const children: Token[] = (tokens[0] as AttrToken).chi.slice() as Token[]; consumeWhitespace(children); @@ -187,15 +196,15 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast if (![ EnumToken.IdenTokenType, EnumToken.NameSpaceAttributeTokenType - ].includes(children[0].l.typ) || + ].includes((children[0] as MatchExpressionToken).l.typ) || ![ EnumToken.EqualMatchTokenType, EnumToken.DashMatchTokenType, EnumToken.StartMatchTokenType, EnumToken.ContainMatchTokenType, - EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType].includes(children[0].op.typ) || + EnumToken.EndMatchTokenType, EnumToken.IncludeMatchTokenType].includes((children[0] as MatchExpressionToken).op.typ) || ![ EnumToken.StringTokenType, EnumToken.IdenTokenType - ].includes(children[0].r.typ)) { + ].includes((children[0] as MatchExpressionToken).r.typ)) { // @ts-ignore return { @@ -208,7 +217,7 @@ export function validateCompoundSelector(tokens: Token[], root?: AstAtRule | Ast } } - if (children[0].attr != null && !['i', 's'].includes(children[0].attr)) { + if ((children[0] as MatchExpressionToken).attr != null && !['i', 's'].includes((children[0] as MatchExpressionToken).attr as string)) { // @ts-ignore return { diff --git a/src/lib/validation/syntaxes/family-name.ts b/src/lib/validation/syntaxes/family-name.ts index 118c2de9..ed24f4ab 100644 --- a/src/lib/validation/syntaxes/family-name.ts +++ b/src/lib/validation/syntaxes/family-name.ts @@ -1,7 +1,7 @@ import type {AstAtRule, Token} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {consumeWhitespace} from "../utils"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {consumeWhitespace} from "../utils/index.ts"; export function validateFamilyName(tokens: Token[], atRule: AstAtRule): ValidationSyntaxResult { diff --git a/src/lib/validation/syntaxes/forgiving-relative-selector-list.ts b/src/lib/validation/syntaxes/forgiving-relative-selector-list.ts index 16193719..77ff4527 100644 --- a/src/lib/validation/syntaxes/forgiving-relative-selector-list.ts +++ b/src/lib/validation/syntaxes/forgiving-relative-selector-list.ts @@ -1,4 +1,4 @@ -import {validateRelativeSelectorList} from "./relative-selector-list"; +import {validateRelativeSelectorList} from "./relative-selector-list.ts"; export const validateForgivingRelativeSelectorList = validateRelativeSelectorList; \ No newline at end of file diff --git a/src/lib/validation/syntaxes/image.ts b/src/lib/validation/syntaxes/image.ts index 1a3a33f5..c16478d2 100644 --- a/src/lib/validation/syntaxes/image.ts +++ b/src/lib/validation/syntaxes/image.ts @@ -1,10 +1,10 @@ import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; import type {FunctionImageToken, Token} from "../../../@types/index.d.ts"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {validateSyntax} from "../syntax"; -import {getParsedSyntax} from "../config"; -import {ValidationSyntaxGroupEnum, ValidationToken} from "../parser"; -import {validateURL} from "./url"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {validateSyntax} from "../syntax.ts"; +import {getParsedSyntax} from "../config.ts"; +import {ValidationSyntaxGroupEnum, ValidationToken} from "../parser/index.ts"; +import {validateURL} from "./url.ts"; export function validateImage(token: Token): ValidationSyntaxResult { diff --git a/src/lib/validation/syntaxes/index.ts b/src/lib/validation/syntaxes/index.ts index 8c157b29..385068a3 100644 --- a/src/lib/validation/syntaxes/index.ts +++ b/src/lib/validation/syntaxes/index.ts @@ -1,10 +1,11 @@ -export * from './layer-name'; -export * from './family-name'; -export * from './forgiving-relative-selector-list'; -export * from './relative-selector-list'; -export * from './relative-selector'; -export * from './complex-selector-list'; -export * from './selector'; -export * from './keyframe-block-list'; -export * from './keyframe-selector'; -export * from './image'; \ No newline at end of file +export * from './layer-name.ts'; +export * from './family-name.ts'; +export * from './forgiving-relative-selector-list.ts'; +export * from './relative-selector-list.ts'; +export * from './relative-selector.ts'; +export * from './complex-selector-list.ts'; +export * from './selector.ts'; +export * from './keyframe-block-list.ts'; +export * from './keyframe-selector.ts'; +export * from './image.ts'; +export * from './bg-layer.ts'; \ No newline at end of file diff --git a/src/lib/validation/syntaxes/keyframe-block-list.ts b/src/lib/validation/syntaxes/keyframe-block-list.ts index 91e17e33..805236a6 100644 --- a/src/lib/validation/syntaxes/keyframe-block-list.ts +++ b/src/lib/validation/syntaxes/keyframe-block-list.ts @@ -1,7 +1,7 @@ import type {AstAtRule, Token, ValidationOptions} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {validateKeyframeSelector} from "./keyframe-selector"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {validateKeyframeSelector} from "./keyframe-selector.ts"; export function validateKeyframeBlockList(tokens: Token[], atRule: AstAtRule, options: ValidationOptions): ValidationSyntaxResult { @@ -14,11 +14,11 @@ export function validateKeyframeBlockList(tokens: Token[], atRule: AstAtRule, op if (tokens[++i].typ == EnumToken.CommaTokenType) { - result = validateKeyframeSelector(tokens.slice(j, i), atRule, options); + result = validateKeyframeSelector(tokens.slice(j, i), atRule, options) as ValidationSyntaxResult; if (result.valid == ValidationLevel.Drop) { - return result; + return result as ValidationSyntaxResult; } j = i + 1; diff --git a/src/lib/validation/syntaxes/keyframe-selector.ts b/src/lib/validation/syntaxes/keyframe-selector.ts index dd1b3d07..432942c7 100644 --- a/src/lib/validation/syntaxes/keyframe-selector.ts +++ b/src/lib/validation/syntaxes/keyframe-selector.ts @@ -1,7 +1,7 @@ import type {AstNode, Token, ValidationOptions} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {consumeWhitespace} from "../utils"; -import {EnumToken, ValidationLevel} from "../../ast"; +import {consumeWhitespace} from "../utils/index.ts"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; export function validateKeyframeSelector(tokens: Token[], atRule: AstNode, options: ValidationOptions): ValidationSyntaxResult { diff --git a/src/lib/validation/syntaxes/layer-name.ts b/src/lib/validation/syntaxes/layer-name.ts index cebf1355..60297d50 100644 --- a/src/lib/validation/syntaxes/layer-name.ts +++ b/src/lib/validation/syntaxes/layer-name.ts @@ -15,7 +15,7 @@ export function validateLayerName(tokens: Token[]): ValidationSyntaxResult { } return acc - }, [[]] as Token[][]).slice(1); + }, [[]] as Token[][]); for (let i = 0; i < slice.length; i++) { @@ -32,30 +32,17 @@ export function validateLayerName(tokens: Token[]): ValidationSyntaxResult { } as ValidationSyntaxResult } - if (slice[i][0].typ != EnumToken.IdenTokenType) { + for (let j = 0; j < slice[i].length; j++) { - // @ts-ignore - return { - valid: ValidationLevel.Drop, - matches: tokens, - node: slice[i][0], - syntax: 'ident', - error: 'expecting ident', - tokens - } as ValidationSyntaxResult - } - - for (let j = 1; j < slice[i].length; j++) { - - if (slice[i][j].typ != EnumToken.ClassSelectorTokenType) { + if (slice[i][j].typ != EnumToken.IdenTokenType &&slice[i][j].typ != EnumToken.ClassSelectorTokenType) { // @ts-ignore return { valid: ValidationLevel.Drop, matches: tokens, node: slice[i][j], - syntax: 'layer-name', - error: 'expecting class selector', + syntax: '', + error: 'expecting ident or class selector', tokens } as ValidationSyntaxResult } diff --git a/src/lib/validation/syntaxes/relative-selector-list.ts b/src/lib/validation/syntaxes/relative-selector-list.ts index e00122af..27a4750e 100644 --- a/src/lib/validation/syntaxes/relative-selector-list.ts +++ b/src/lib/validation/syntaxes/relative-selector-list.ts @@ -1,8 +1,8 @@ import type {AstAtRule, AstRule, Token} from "../../../@types"; import type {ValidationSelectorOptions, ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {ValidationLevel} from "../../ast"; -import {validateRelativeSelector} from "./relative-selector"; -import {consumeWhitespace, splitTokenList} from "../utils"; +import {ValidationLevel} from "../../ast/index.ts"; +import {validateRelativeSelector} from "./relative-selector.ts"; +import {consumeWhitespace, splitTokenList} from "../utils/index.ts"; export function validateRelativeSelectorList(tokens: Token[], root?: AstAtRule | AstRule, options?: ValidationSelectorOptions): ValidationSyntaxResult { diff --git a/src/lib/validation/syntaxes/relative-selector.ts b/src/lib/validation/syntaxes/relative-selector.ts index f3e8aa45..4e05da32 100644 --- a/src/lib/validation/syntaxes/relative-selector.ts +++ b/src/lib/validation/syntaxes/relative-selector.ts @@ -1,9 +1,9 @@ -import type {AstAtRule, AstRule, Token} from "../../../@types"; +import type {AstAtRule, AstRule, Token} from "../../../@types/index.d.ts"; import type {ValidationSelectorOptions, ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {consumeWhitespace} from "../utils"; -import {ValidationLevel} from "../../ast"; -import {validateSelector} from "./selector"; -import {combinatorsTokens} from "./complex-selector"; +import {consumeWhitespace} from "../utils/index.ts"; +import {ValidationLevel} from "../../ast/index.ts"; +import {validateSelector} from "./selector.ts"; +import {combinatorsTokens} from "./complex-selector.ts"; export function validateRelativeSelector(tokens: Token[], root?: AstAtRule | AstRule, options?: ValidationSelectorOptions): ValidationSyntaxResult { diff --git a/src/lib/validation/syntaxes/selector-list.ts b/src/lib/validation/syntaxes/selector-list.ts index 3bac6d55..9f0b1803 100644 --- a/src/lib/validation/syntaxes/selector-list.ts +++ b/src/lib/validation/syntaxes/selector-list.ts @@ -1,4 +1,4 @@ -import {validateComplexSelectorList} from "./complex-selector-list"; +import {validateComplexSelectorList} from "./complex-selector-list.ts"; export const validateSelectorList = validateComplexSelectorList; \ No newline at end of file diff --git a/src/lib/validation/syntaxes/selector.ts b/src/lib/validation/syntaxes/selector.ts index 89fbbadf..ef6d68e6 100644 --- a/src/lib/validation/syntaxes/selector.ts +++ b/src/lib/validation/syntaxes/selector.ts @@ -1,4 +1,4 @@ -import {validateComplexSelector} from "./complex-selector"; +import {validateComplexSelector} from "./complex-selector.ts"; export const validateSelector = validateComplexSelector; \ No newline at end of file diff --git a/src/lib/validation/syntaxes/url.ts b/src/lib/validation/syntaxes/url.ts index 57c65258..54059949 100644 --- a/src/lib/validation/syntaxes/url.ts +++ b/src/lib/validation/syntaxes/url.ts @@ -1,7 +1,7 @@ import type {Token} from "../../../@types"; import type {ValidationSyntaxResult} from "../../../@types/validation.d.ts"; -import {EnumToken, ValidationLevel} from "../../ast"; -import {consumeWhitespace} from "../utils"; +import {EnumToken, ValidationLevel} from "../../ast/index.ts"; +import {consumeWhitespace} from "../utils/index.ts"; export function validateURL(token: Token): ValidationSyntaxResult { diff --git a/src/lib/validation/utils/index.ts b/src/lib/validation/utils/index.ts index 87977a20..93996233 100644 --- a/src/lib/validation/utils/index.ts +++ b/src/lib/validation/utils/index.ts @@ -1,3 +1,3 @@ -export * from './whitespace'; -export * from './list'; +export * from './whitespace.ts'; +export * from './list.ts'; diff --git a/src/node/index.ts b/src/node/index.ts index 190c4a32..8b2f007d 100644 --- a/src/node/index.ts +++ b/src/node/index.ts @@ -1,4 +1,3 @@ - import type { AstNode, ParseResult, @@ -9,11 +8,11 @@ import type { TransformResult } from "../@types/index.d.ts"; import process from 'node:process'; -import {doParse, doRender} from "../lib"; -import {resolve, dirname} from "../lib/fs"; -import {load} from "./load"; +import {doParse, doRender} from "../lib/index.ts"; +import {dirname, resolve} from "../lib/fs/index.ts"; +import {load} from "./load.ts"; -export {minify, expand, parseString, parseTokens, renderToken, walk, walkValues, EnumToken} from '../lib'; +export {minify, expand, parseString, parseTokens, renderToken, walk, walkValues, EnumToken} from '../lib/index.ts'; export {dirname, resolve, load}; /** diff --git a/src/node/load.ts b/src/node/load.ts index 1df774bd..fc83e081 100644 --- a/src/node/load.ts +++ b/src/node/load.ts @@ -1,5 +1,5 @@ import {readFile} from "node:fs/promises"; -import {resolve, matchUrl} from "../lib/fs"; +import {matchUrl, resolve} from "../lib/fs/index.ts"; function parseResponse(response: Response) { diff --git a/src/web/index.ts b/src/web/index.ts index a0355f3d..60739a68 100644 --- a/src/web/index.ts +++ b/src/web/index.ts @@ -1,4 +1,3 @@ - import type { AstNode, ParseResult, @@ -9,11 +8,11 @@ import type { TransformResult } from "../@types/index.d.ts"; -import {doParse, doRender} from "../lib"; -import {resolve, dirname} from "../lib/fs"; -import {load} from "./load"; +import {doParse, doRender} from "../lib/index.ts"; +import {dirname, resolve} from "../lib/fs/index.ts"; +import {load} from "./load.ts"; -export {minify, expand, parseString, parseTokens, renderToken, walk, walkValues, EnumToken} from '../lib'; +export {minify, expand, parseString, parseTokens, renderToken, walk, walkValues, EnumToken} from '../lib/index.ts'; export {dirname, resolve, load}; /** diff --git a/test/specs/code/at-rules.js b/test/specs/code/at-rules.js index 65dd1e70..f3639fb9 100644 --- a/test/specs/code/at-rules.js +++ b/test/specs/code/at-rules.js @@ -368,4 +368,113 @@ export function run(describe, expect, transform, parse, render, dirname) { }); }); + describe('@import', function () { + it('import #24', function () { + return transform(` +@import "custom.css +"; +@import url("chrome://communicator/skin/ +"); + +`).then((result) => expect(result.code).equals(``)); + }); + it('import #25', function () { + return transform(` + +@import url("landscape.css") screen and (orientation: landscape); + +`).then((result) => expect(result.code).equals(`@import "landscape.css" screen and (orientation:landscape);`)); + }); + + it('import #26', function () { + return transform(` + +@import url("gridy.css") supports((not (display: grid)) and (display: flex)) + screen and (max-width: 400px) + +`).then((result) => expect(result.code).equals(`@import "gridy.css" supports((not (display:grid)) and (display:flex)) screen and (max-width:400px);`)); + }); + + it('import #27', function () { + return transform(` + + +@import url("whatever.css") +supports((selector(h2 > p)) and (font-tech(color-COLRv1))); + + +`).then((result) => expect(result.code).equals(`@import "whatever.css" supports((selector(h2>p)) and (font-tech(color-COLRv1)));`)); + }); + + it('import #27', function () { + return transform(` + + +@import url("whatever.css") +supports((selector(h2 > p)) and (font-tech(color-COLRv1))) { + +} + +`).then((result) => expect(result.code).equals(``)); + }); + + it('import #28', function () { + return transform(` + +@import "theme.css" layer("bar"); +@import "theme.css" layer(); +@import "style.css" layer; + +`, {beautify: true}).then((result) => expect(result.code).equals(`@import "style.css" layer;`)); + }); + }); + + + describe('@document', function () { + it('document #29', function () { + return transform(` +@document url("https://www.example.com/") +{ + h1 { + color: green; + } +} + +`, {beautify: true}).then((result) => expect(result.code).equals(`@document url(https://www.example.com/) { + h1 { + color: green + } +}`)); + }); + it('document #30', function () { + return transform(` + +@document url("http://www.w3.org/"), + url-prefix("http://www.w3.org/Style/"), + domain("mozilla.org"), + media-document("video"), + regexp("https:.*") { + /* CSS rules here apply to: + - The page "http://www.w3.org/" + - Any page whose URL begins with "http://www.w3.org/Style/" + - Any page whose URL's host is "mozilla.org" + or ends with ".mozilla.org" + - Any standalone video + - Any page whose URL starts with "https:" */ + + /* Make the above-mentioned pages really ugly */ + body { + color: purple; + background: yellow; + } +} + +`, {beautify: true}).then((result) => expect(result.code).equals(`@document url(http://www.w3.org/),url-prefix("http://www.w3.org/Style/"),domain("mozilla.org"),media-document("video"),regexp("https:.*") { + body { + color: purple; + background: #ff0 + } +}`)); + }); + }); } diff --git a/test/specs/code/color.js b/test/specs/code/color.js index ac8a7fcc..7e93a5ac 100644 --- a/test/specs/code/color.js +++ b/test/specs/code/color.js @@ -10,13 +10,18 @@ export function run(describe, expect, transform, parse, render) { }); it('hsl #2', function () { - return parse(`.hsl { color: hsla(195, 100%, 50%, 50%); }`).then(result => expect(render(result.ast, {minify: false}).code).equals(`.hsl { - color: #00bfff80 + return parse(`.hsl { color: hsla(195, 100%, 50%, 50%); + background-color: color(xyz-d50 0.3 80 0.3);}`).then(result => expect(render(result.ast, {minify: false}).code).equals(`.hsl { + color: #00bfff80; + background-color: lime }`)); }); it('hwb #3', function () { - return parse(`.hwb { color: hwb(195, 0%, 0%); }`).then(result => expect(render(result.ast, {minify: false}).code).equals(`.hwb { - color: #00bfff + return parse(`.hwb { color: hwb(195, 0%, 0%); + background-color: color-mix(in xyz-d50, #FF7F50 50%, #00FFFF 50%) ; + }`).then(result => expect(render(result.ast, {minify: false}).code).equals(`.hwb { + color: #00bfff; + background-color: #bcccc2 }`)); }); diff --git a/tsconfig.json b/tsconfig.json index dbb02d4f..c343f0a6 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -40,7 +40,7 @@ // "types": [], /* Specify type package names to be included without being referenced in a source file. */ // "allowUmdGlobfalAccess": true, /* Allow accessing UMD globals from modules. */ // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ - // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */