diff --git a/custom/css.json b/custom/css.json index e1ffd5777..febfebbac 100644 --- a/custom/css.json +++ b/custom/css.json @@ -64,6 +64,9 @@ "-webkit-transform-origin-y": {}, "-webkit-transform-origin-z": {}, "-webkit-user-drag": {}, + "alignment-baseline": { + "__values": ["text-after-edge", "text-before-edge"] + }, "alt": {}, "animation-timing-function": { "__additional_values": { @@ -92,9 +95,6 @@ "multiple_backgrounds": "fixed, scroll" } }, - "background-clip": { - "__values": ["text", "border-area"] - }, "background-image": { "__additional_values": { "element": "element(#foo)", @@ -126,12 +126,14 @@ "multiple_backgrounds": "repeat, no-repeat" } }, + "baseline-shift": { + "__values": ["baseline"] + }, "block-size": { "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "border-bottom-left-radius": { "__additional_values": { @@ -145,9 +147,6 @@ "percentages": "20%" } }, - "border-collapse": { - "__values": ["separate", "collapse"] - }, "border-image": { "__additional_values": { "fill": "url(test.png) 30 fill", @@ -200,8 +199,6 @@ }, "caption-side": { "__values": [ - "top", - "bottom", "left", "right", "inline-start", @@ -218,7 +215,7 @@ } }, "color-interpolation": { - "__values": ["linearGradient", "sRGB"] + "__values": ["linearGradient"] }, "column-progression": {}, "contain-intrinsic-size": { @@ -234,11 +231,18 @@ "url": "url(test.png)" } }, + "counter-increment": { + "__values": ["list-item"] + }, "counter-reset": { + "__values": ["list-item"], "__additional_values": { "reversed": "reversed(my-counter)" } }, + "counter-set": { + "__values": ["list-item"] + }, "cursor": { "__values": ["-moz-zoom", "-webkit-zoom"], "__additional_values": { @@ -248,14 +252,10 @@ }, "custom-property": {}, "display": { - "__values": ["math"], "__additional_values": { "multi-keyword_values": "inline flow" } }, - "empty-cells": { - "__values": ["show", "hide"] - }, "filter": { "__additional_values": { "blur": "blur(10px)", @@ -271,7 +271,7 @@ } }, "flex-basis": { - "__values": ["-webkit-auto", "fit-content", "max-content", "min-content"] + "__values": ["-webkit-auto"] }, "font": { "__additional_values": { @@ -279,16 +279,6 @@ } }, "font-display": {}, - "font-family": { - "__values": [ - "math", - "system-ui", - "ui-monospace", - "ui-rounded", - "ui-sans-serif", - "ui-serif" - ] - }, "font-size": { "__additional_values": { "rem_values": "10rem" @@ -311,12 +301,6 @@ "oblique-angle": "oblique 10deg" } }, - "font-synthesis": { - "__values": ["small-caps", "position", "style", "weight"] - }, - "font-variant": { - "__values": ["historical-forms", "sub", "super"] - }, "font-variant-alternates": { "__additional_values": { "annotation": "annotation(user-defined-ident)", @@ -372,8 +356,7 @@ "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "inset-block-end": { "__additional_values": { @@ -438,8 +421,22 @@ "afar", "amharic", "amharic-abegede", + "arabic-indic", + "armenian", "asterisks", + "bengali", "binary", + "cambodian", + "circle", + "cjk-decimal", + "cjk-earthly-branch", + "cjk-heavenly-stem", + "decimal", + "decimal-leading-zero", + "devanagari", + "disc", + "disclosure-closed", + "disclosure-open", "ethiopic", "ethiopic-abegede", "ethiopic-abegede-am-et", @@ -458,23 +455,63 @@ "ethiopic-halehame-ti-er", "ethiopic-halehame-ti-et", "ethiopic-halehame-tig", + "ethiopic-numeric", "footnotes", + "georgian", + "gujarati", + "gurmukhi", "hangul", "hangul-consonant", + "hebrew", + "hiragana", + "hiragana-iroha", + "japanese-formal", + "japanese-informal", + "kannada", + "katakana", + "katakana-iroha", + "khmer", + "korean-hangul-formal", + "korean-hanja-formal", + "korean-hanja-informal", + "lao", + "lower-alpha", + "lower-armenian", + "lower-greek", "lower-hexadecimal", + "lower-latin", "lower-norwegian", + "lower-roman", + "malayalam", + "mongolian", + "myanmar", "octal", + "oriya", "oromo", + "persian", "sidama", + "simp-chinese-formal", + "simp-chinese-informal", "somali", + "square", + "tamil", + "telugu", + "thai", + "tibetan", "tigre", "tigrinya-er", "tigrinya-er-abegede", "tigrinya-et", "tigrinya-et-abegede", + "trad-chinese-formal", + "trad-chinese-informal", + "upper-alpha", + "upper-armenian", "upper-greek", "upper-hexadecimal", + "upper-latin", "upper-norwegian", + "upper-roman", "urdu" ], "__additional_values": { @@ -483,7 +520,6 @@ } }, "margin": { - "__values": ["auto"], "__additional_values": { "anchor-size": "anchor-size(block, 10%)" } @@ -504,7 +540,6 @@ } }, "margin-bottom": { - "__values": ["auto"], "__additional_values": { "anchor-size": "anchor-size(block, 10%)" } @@ -525,19 +560,16 @@ } }, "margin-left": { - "__values": ["auto"], "__additional_values": { "anchor-size": "anchor-size(block, 10%)" } }, "margin-right": { - "__values": ["auto"], "__additional_values": { "anchor-size": "anchor-size(block, 10%)" } }, "margin-top": { - "__values": ["auto"], "__additional_values": { "anchor-size": "anchor-size(block, 10%)" } @@ -558,8 +590,7 @@ "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "max-height": { "__additional_values": { @@ -571,8 +602,7 @@ "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "max-width": { "__additional_values": { @@ -585,8 +615,7 @@ "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "min-height": { "__additional_values": { @@ -598,8 +627,7 @@ "__additional_values": { "fit-content_function": "fit-content(10px)", "anchor-size": "anchor-size(block, 10%)" - }, - "__values": ["max-content", "min-content", "fit-content"] + } }, "min-width": { "__additional_values": { @@ -608,9 +636,6 @@ } }, "min-zoom": {}, - "mix-blend-mode": { - "__values": ["plus-darker", "plus-lighter"] - }, "motion": {}, "motion-distance": {}, "motion-offset": {}, @@ -645,24 +670,21 @@ "multiple_keywords": "hidden visible" } }, + "overflow-block": { + "__values": ["overlay"] + }, "overflow-clip-box": {}, "overflow-clip-box-block": {}, "overflow-clip-box-inline": {}, - "pen-action": {}, - "place-items": { - "__values": ["anchor-center"] - }, - "place-self": { - "__values": ["anchor-center"] + "overflow-inline": { + "__values": ["overlay"] }, + "pen-action": {}, "position-try-fallbacks": { "__additional_values": { "position-area": "left center" } }, - "resize": { - "__values": ["block", "inline"] - }, "right": { "__additional_values": { "anchor": "anchor(bottom)", @@ -701,9 +723,6 @@ "length": "20px" } }, - "table-layout": { - "__values": ["auto", "fixed"] - }, "text-align": { "__additional_values": { "string": "'.'" @@ -754,9 +773,6 @@ "text-overline-mode": {}, "text-overline-style": {}, "text-overline-width": {}, - "text-rendering": { - "__values": ["auto", "geometricPrecision"] - }, "text-size-adjust": { "__additional_values": { "percentages": "50%" @@ -775,9 +791,6 @@ }, "text-underline-style": {}, "text-underline-width": {}, - "text-wrap": { - "__values": ["balance", "nowrap", "pretty", "stable", "wrap"] - }, "top": { "__additional_values": { "anchor": "anchor(bottom)", @@ -826,6 +839,9 @@ "__values": ["read-write-plaintext-only"] }, "user-zoom": {}, + "vertical-align": { + "__values": ["auto"] + }, "viewport-fit": {}, "white-space": { "__values": ["-moz-pre-wrap"] diff --git a/package-lock.json b/package-lock.json index 37b3f3251..e1a6bb6dc 100644 --- a/package-lock.json +++ b/package-lock.json @@ -63,7 +63,7 @@ "@types/superagent": "^8.1.9", "@types/webidl2": "^24.4.3", "@types/yargs": "^17.0.33", - "@webref/css": "6.23.11", + "@webref/css": "7.0.11", "@webref/elements": "^2.5.1", "@webref/idl": "3.68.1", "c8": "10.1.3", @@ -76,6 +76,7 @@ "chalk-template": "1.1.2", "cheerio": "^1.1.2", "core-js": "^3.45.1", + "css-tree": "^3.1.0", "ejs-lint": "^2.0.1", "enquirer": "2.4.1", "es-scraper": "^0.0.13", @@ -5474,9 +5475,9 @@ } }, "node_modules/@webref/css": { - "version": "6.23.11", - "resolved": "https://registry.npmjs.org/@webref/css/-/css-6.23.11.tgz", - "integrity": "sha512-RyRWiSjmSyrs+n2Qv5SVg45fay8YF76PZ3YxDmF8HndC4K9D5NQuR2AfTeqspiwJdOsfTKBDAZD0vPw4Rxpu7g==", + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@webref/css/-/css-7.0.11.tgz", + "integrity": "sha512-UDid24B3uueRSRwUNI/V3cDXIVgD0ZPk7KIVMTHGvKzmUWJbuky2pl8UJizLkN7FiwXqVMIPxkbrm6qc7EY2Hg==", "dev": true, "license": "MIT", "peerDependencies": { @@ -7573,7 +7574,6 @@ "integrity": "sha512-0eW44TGN5SQXU1mWSkKwFstI/22X2bG1nYzZTYMAWjylYURhse752YgbE4Cx46AC+bAvI+/dYTPRk1LqSUnu6w==", "dev": true, "license": "MIT", - "peer": true, "dependencies": { "mdn-data": "2.12.2", "source-map-js": "^1.0.1" @@ -12946,8 +12946,7 @@ "resolved": "https://registry.npmjs.org/mdn-data/-/mdn-data-2.12.2.tgz", "integrity": "sha512-IEn+pegP1aManZuckezWCO+XZQDplx1366JoVhTpMpBB1sPey/SbveZQUosKiKiGYjg1wH4pMlNgXbCiYgihQA==", "dev": true, - "license": "CC0-1.0", - "peer": true + "license": "CC0-1.0" }, "node_modules/media-typer": { "version": "1.1.0", diff --git a/package.json b/package.json index 5aa20d08a..4256dd711 100644 --- a/package.json +++ b/package.json @@ -97,7 +97,7 @@ "@types/superagent": "^8.1.9", "@types/webidl2": "^24.4.3", "@types/yargs": "^17.0.33", - "@webref/css": "6.23.11", + "@webref/css": "7.0.11", "@webref/elements": "^2.5.1", "@webref/idl": "3.68.1", "c8": "10.1.3", @@ -110,6 +110,7 @@ "chalk-template": "1.1.2", "cheerio": "^1.1.2", "core-js": "^3.45.1", + "css-tree": "^3.1.0", "ejs-lint": "^2.0.1", "enquirer": "2.4.1", "es-scraper": "^0.0.13", diff --git a/test-builder/css.test.ts b/test-builder/css.test.ts index 4eca9c18c..012cb5c2b 100644 --- a/test-builder/css.test.ts +++ b/test-builder/css.test.ts @@ -18,39 +18,20 @@ import {build} from "./css.js"; describe("build (CSS)", () => { it("valid input", async () => { const webrefCSS = { - "css-fonts": { - spec: { - title: "CSS Fonts Fake", - url: "", + properties: [ + {name: "font-family", href: "https://foo.bar"}, + { + name: "font-weight", + href: "https://foo.bar", + syntax: " | bolder | lighter", }, - properties: [ - {name: "font-family"}, - { - name: "font-weight", - values: [{name: "normal", value: "normal", type: "value"}], - }, - ], - selectors: [], - values: [], - }, - "css-grid": { - spec: { - title: "CSS Grid Fake", - url: "", - }, - properties: [{name: "grid"}], - selectors: [], - values: [], - }, - selectors: { - spec: { - title: "CSS Selectors Fake", - url: "", - }, - properties: [], - selectors: [{name: "+"}, {name: ":nth-of-type()"}], - values: [], - }, + {name: "grid", href: "https://foo.bar"}, + ], + selectors: [ + {name: "+", href: "https://foo.bar"}, + {name: ":nth-of-type()", href: "https://foo.bar"}, + ], + types: [], }; const customCSS = { @@ -90,8 +71,12 @@ describe("build (CSS)", () => { code: 'bcd.testCSSProperty("font-weight")', exposure: ["Window"], }, - "css.properties.font-weight.normal": { - code: 'bcd.testCSSProperty("font-weight", "normal")', + "css.properties.font-weight.bolder": { + code: 'bcd.testCSSProperty("font-weight", "bolder")', + exposure: ["Window"], + }, + "css.properties.font-weight.lighter": { + code: 'bcd.testCSSProperty("font-weight", "lighter")', exposure: ["Window"], }, "css.properties.grid": { @@ -119,15 +104,9 @@ describe("build (CSS)", () => { it("with custom test", async () => { const css = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", - }, - properties: [{name: "foo"}], - selectors: [], - values: [], - }, + properties: [{name: "foo", href: "https://foo.bar"}], + selectors: [], + types: [], }; assert.deepEqual( @@ -146,15 +125,9 @@ describe("build (CSS)", () => { it("double-defined property", async () => { const css = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", - }, - properties: [{name: "foo"}], - selectors: [], - values: [], - }, + properties: [{name: "foo", href: "https://foo.bar"}], + selectors: [], + types: [], }; await assert.isRejected( @@ -165,15 +138,15 @@ describe("build (CSS)", () => { it("double-defined property value", async () => { const css = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", + properties: [ + { + name: "foo", + href: "https://foo.bar", + syntax: "bar", }, - properties: [{name: "foo", values: [{name: "bar", value: "bar"}]}], - selectors: [], - values: [], - }, + ], + selectors: [], + types: [], }; await assert.isRejected( @@ -193,22 +166,22 @@ describe("build (CSS)", () => { }; await assert.isRejected( - build({}, customCSS), + build({properties: [], selectors: [], types: []}, customCSS), "CSS property value is double-defined in custom CSS: foo.bar", ); }); it("double-defined property value", async () => { const webrefCSS = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", + properties: [ + { + name: "foo", + href: "https://foo.bar", + syntax: "bar", }, - properties: [{name: "foo", values: [{name: "bar", value: "bar"}]}], - selectors: [], - values: [], - }, + ], + selectors: [], + types: [], }; const customCSS = { @@ -225,15 +198,15 @@ describe("build (CSS)", () => { it("__additional_values overwrites spec value", async () => { const webrefCSS = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", + properties: [ + { + name: "one", + href: "https://foo.bar", + syntax: "two", }, - properties: [{name: "one", values: [{name: "two", value: "two"}]}], - selectors: [], - values: [], - }, + ], + selectors: [], + types: [], }; const customCSS = { @@ -256,15 +229,9 @@ describe("build (CSS)", () => { it("double-defined selector", async () => { const css = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", - }, - properties: [], - selectors: [{name: "foo"}], - values: [], - }, + properties: [], + selectors: [{name: "foo", href: "https://foo.bar"}], + types: [], }; await assert.isRejected( @@ -276,15 +243,9 @@ describe("build (CSS)", () => { it("invalid import", async () => { const consoleError = sinon.stub(console, "error"); const css = { - "css-dummy": { - spec: { - title: "CSS Dummy", - url: "", - }, - properties: [{name: "bar"}], - selectors: [], - values: [], - }, + properties: [{name: "bar", href: "https://foo.bar"}], + selectors: [], + types: [], }; const error = diff --git a/test-builder/css.ts b/test-builder/css.ts index 8a394fea5..882d952d8 100644 --- a/test-builder/css.ts +++ b/test-builder/css.ts @@ -6,6 +6,8 @@ // See the LICENSE file for copyright details // +import {definitionSyntax as cssSyntaxParser} from "css-tree"; + import {getCustomTest, compileTest} from "./common.js"; const ignoredSpecs = [ @@ -13,6 +15,59 @@ const ignoredSpecs = [ "https://drafts.csswg.org/css-values-4/", // The CSS Values and Units Module just defines primitive types ]; +/** + * Parses a CSS syntax string and extracts keyword and type values. + * @param syntax - The CSS syntax string to parse. + * @param properties - The properties from the specification + * @returns A Set of extracted values from the syntax. + */ +const getValuesFromSyntax = (syntax: string, properties) => { + const ast = cssSyntaxParser.parse(syntax); + const values = new Set(); + cssSyntaxParser.walk(ast, (node) => { + if (node.type === "Keyword") { + values.add(node.name); + } else if (node.type === "Type") { + values.add("<" + node.name + ">"); + } else if (node.type === "Property") { + const prop = properties.find((p) => p.name == node.name); + const newValues = getValuesFromSyntax(prop?.syntax || "", properties); + for (const v of newValues) { + values.add(v); + } + } + }); + return values; +}; + +/** + * Recursively resolves values from types, expanding type references. + * @param values - The values to resolve. + * @param types - The map of types to their possible values. + * @returns An array of resolved values. + */ +const resolveValuesFromTypes = ( + values: string[], + types: Record, +): string[] => { + const resolved: string[] = []; + + for (const value of values) { + if (value.startsWith("<")) { + const type = value.replace(/^<(.*)>$/, "$1"); + if (type in types) { + resolved.push(...resolveValuesFromTypes(types[type], types)); + } else { + resolved.push(value); + } + } else { + resolved.push(value); + } + } + + return resolved; +}; + /** * Get the type data from Webref and flatten enumerated types * @param specCSS - The specification CSS data. @@ -21,56 +76,27 @@ const ignoredSpecs = [ const getCSSTypes = (specCSS) => { // Some types are manually defined to mitigate Webref data issues const types = { - "": new Set(["", "margin-box"]), - "": new Set(["", "fill-box", "stroke-box"]), - "": new Set(["", "view-box"]), - "": new Set([""]), - "": new Set(["auto", ""]), - " || ": new Set(["", ""]), - " | ": new Set([ - "", - "", - ]), + "layout-box": new Set(["", "margin-box"]), + "paint-box": new Set(["", "fill-box", "stroke-box"]), + "coord-box": new Set(["", "view-box"]), + "counter-style": new Set([""]), + "outline-line-style": new Set(["auto", ""]), }; // Get the type data from the spec - for (const data of Object.values(specCSS) as any[]) { - if (ignoredSpecs.includes(data.spec.url)) { + for (const val of Object.values(specCSS.types) as any[]) { + if (ignoredSpecs.some((u) => val.href.startsWith(u))) { continue; } - for (const val of data.values) { - if (!(val.name in types)) { - // Sets are used to automatically de-duplicate entries - types[val.name] = new Set(); - } + if (!(val.name in types)) { + // Sets are used to automatically de-duplicate entries + types[val.name] = new Set(); + } - for (const value of val.values || []) { - switch (value.type) { - case "function": - // Ignore functions for now - break; - case "value": - types[val.name].add(value.value); - break; - case "type": - if (value.values) { - types[val.name].add( - ...value.values - .filter((v) => v.type === "value") - .map((v) => v.value), - ); - } else if (value.value?.includes(" | ")) { - for (const v of value.value.split(" | ")) { - types[val.name].add(v); - } - } else { - types[val.name].add(value.value); - } - break; - default: - throw new Error(`Unknown value type ${value.type} found!`); - } + if ("syntax" in val) { + for (const value of getValuesFromSyntax(val.syntax, specCSS.properties)) { + types[val.name].add(value); } } } @@ -78,7 +104,7 @@ const getCSSTypes = (specCSS) => { for (const [type, values] of Object.entries(types) as any[]) { // Check for values that reference other types for (const value of values) { - if (value in types) { + if (Object.keys(types).some((t) => t === `<${value}>`)) { types[type].delete(value); for (const v of types[value]) { types[type].add(v); @@ -97,75 +123,29 @@ const getCSSTypes = (specCSS) => { * Remap the CSS property values from Webref into usable map entries * @param input - The value from Webref * @param types - The types from webref - * // @param customCSS - The custom CSS data to draw type information from * @returns A two-value array to add to a map, or null if no test should be created for the value */ -const remapPropertyValues = (input, types /*, customCSS*/) => { +const remapPropertyValues = (input, types) => { if (!input) { return []; } const values = new Map(); - for (const val of input) { - if (val.name in types) { - for (const v of types[val.name]) { - if (v.includes("<")) { - // Skip any unflattened types - continue; - } - values.set(v, v); - } - } else { - // XXX Remove me once all these have been transferred to custom/css.json - // const typeRemappings = { - // "+": ["type_multi_string", "'foo' 'bar'"], - // "auto && ": ["type_auto_and_ratio", "auto 16/9"], - // }; - - if ( - ["inherit", "initial", "revert", "revert-layer", "unset"].includes( - val.name, - ) - ) { - // Skip generic property values - continue; - } - - if (val.name.includes("<")) { - // Skip any and all types for now until we're ready to add them - continue; - - // if (val.name in typeRemappings) { - // values.set(typeRemappings[val.name][0], typeRemappings[val.name][1]); - // continue; - // } - - // for (const [type, typedata] of Object.entries( - // customCSS.types, - // ) as any[]) { - // if ( - // Array.isArray(typedata.syntax) - // ? typedata.syntax.includes(val.name) - // : val.name === typedata.syntax - // ) { - // values.set("type_" + type, typedata.value); - // continue; - // } - // } - - // console.warn(`Type ${val.name} unknown!`); - // continue; - } + for (const val of resolveValuesFromTypes(input, types)) { + if ( + ["inherit", "initial", "revert", "revert-layer", "unset"].includes(val) + ) { + // Skip generic property values + continue; + } - values.set( - val.name - .replace(/ /g, "_") - .replace("fit-content()", "fit-content_function") - .replace("()", ""), - val.value, - ); + if (val.includes("<")) { + // Skip any and all types for now until we're ready to add them + continue; } + + values.set(val.replace(/ /g, "_").replace("()", "_function"), val); } return values; @@ -183,95 +163,97 @@ const buildPropertyTests = async (specCSS, customCSS) => { const types = getCSSTypes(specCSS); - for (const data of Object.values(specCSS) as any[]) { - if (ignoredSpecs.includes(data.spec.url)) { + for (const prop of specCSS.properties) { + if (ignoredSpecs.some((u) => prop.href.startsWith(u))) { continue; } - for (const prop of data.properties) { - if ( - [ - "-webkit-appearance", - "-webkit-user-select", - "-webkit-line-clamp", - "grid-gap", - "grid-column-gap", - "grid-row-gap", - "word-wrap", - ].includes(prop.name) - ) { - // Ignore any aliases defined in specs - continue; - } + if ( + [ + "-webkit-appearance", + "-webkit-user-select", + "-webkit-line-clamp", + "grid-gap", + "grid-column-gap", + "grid-row-gap", + "word-wrap", + ].includes(prop.name) + ) { + // Ignore any aliases defined in specs + continue; + } - const additionalPropTypeValues = { - display: [ - "", - "", - "", - "", - "", - "", - ], - "border-style": [""], - "outline-style": [""], - }; - - // XXX Webref does not include these types, so we have to add them ourselves - // We don't have capabilities to parse types in custom/css.json - if (prop.name in additionalPropTypeValues) { - if (!prop.values) { - prop.values = []; - } - prop.values.push( - ...additionalPropTypeValues[prop.name].map((n) => ({ - name: n, - value: n, - type: "type", - })), - ); + const additionalPropTypeValues = { + display: [ + "", + "", + "", + "", + "", + "", + ], + "border-style": [""], + "outline-style": [""], + }; + + // XXX Webref does not include these types, so we have to add them ourselves + // We don't have capabilities to parse types in custom/css.json + if (prop.name in additionalPropTypeValues) { + if (!prop.values) { + prop.values = []; } - - const ignoredValues = { - "font-size-adjust": [ - "ex-height | cap-height | ch-width | ic-width | ic-height", - ], - "text-justify": ["distribute"], - "text-orientation": ["sideways-right"], - overflow: ["overlay"], - "overflow-x": ["overlay"], - "overflow-y": ["overlay"], - transform: [ - "matrix", - "translate", - "translateX", - "translateY", - "rotate", - "skew", - "skewX", - "skewY", - ], - // https://github.com/openwebdocs/mdn-bcd-collector/issues/2381 - "accent-color": [""], - "column-rule-color": [""], - }; - - const propertyValues = remapPropertyValues( - prop.values?.filter( - (v) => !(ignoredValues[prop.name] || []).includes(v.name), - ), - types, - // customCSS, + prop.values.push( + ...additionalPropTypeValues[prop.name].map((n) => ({ + name: n, + value: n, + type: "type", + })), ); + } - if (properties.has(prop.name)) { - properties.set( - prop.name, - new Map([...properties.get(prop.name), ...propertyValues]), - ); - } else { - properties.set(prop.name, new Map(propertyValues)); - } + const ignoredValues = { + "font-size-adjust": [ + "ex-height | cap-height | ch-width | ic-width | ic-height", + ], + "text-justify": ["distribute"], + "text-orientation": ["sideways-right"], + overflow: ["overlay"], + "overflow-x": ["overlay"], + "overflow-y": ["overlay"], + transform: [ + "matrix", + "translate", + "translateX", + "translateY", + "rotate", + "skew", + "skewX", + "skewY", + ], + // https://github.com/openwebdocs/mdn-bcd-collector/issues/2381 + "accent-color": [""], + "column-rule-color": [""], + }; + + const valuesFromSyntax = getValuesFromSyntax( + prop.syntax || "", + specCSS.properties, + ); + const propertyValues = remapPropertyValues( + Array.from(valuesFromSyntax).filter( + (v) => !(ignoredValues[prop.name] || []).includes(v), + ), + types, + // customCSS, + ); + + if (properties.has(prop.name)) { + properties.set( + prop.name, + new Map([...properties.get(prop.name), ...propertyValues]), + ); + } else { + properties.set(prop.name, new Map(propertyValues)); } } @@ -360,20 +342,17 @@ const buildSelectorTests = async (specCSS, customCSS) => { const selectors = new Map(); const tests = {}; - for (const data of Object.values(specCSS) as any[]) { - if (data.spec.url == "https://compat.spec.whatwg.org/") { - // The Compatibility Standard contains legacy prefixed aliases for properties, ignore + for (const selector of specCSS.selectors) { + if (ignoredSpecs.some((u) => selector.href.startsWith(u))) { continue; } - for (const selector of data.selectors) { - if ([":matches()"].includes(selector.name)) { - // Ignore legacy aliases - continue; - } - - selectors.set(selector.name, {}); + if ([":matches()"].includes(selector.name)) { + // Ignore legacy aliases + continue; } + + selectors.set(selector.name, {}); } for (const [name, value] of Object.entries(customCSS.selectors) as any[]) {