diff --git a/.prettierignore b/.prettierignore index 10e4e6f..9abb0b9 100644 --- a/.prettierignore +++ b/.prettierignore @@ -1,3 +1,4 @@ dist CHANGELOG.md jsr.json +src/data diff --git a/README.md b/README.md index f6566be..b3a3f68 100644 --- a/README.md +++ b/README.md @@ -56,12 +56,13 @@ export default [ -| **Rule Name** | **Description** | **Recommended** | -| :--------------------------------------------------------------- | :------------------------------- | :-------------: | -| [`no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate @import rules | yes | -| [`no-empty-blocks`](./docs/rules/no-empty-blocks.md) | Disallow empty blocks | yes | -| [`no-invalid-at-rules`](./docs/rules/no-invalid-at-rules.md) | Disallow invalid at-rules | yes | -| [`no-invalid-properties`](./docs/rules/no-invalid-properties.md) | Disallow invalid properties | yes | +| **Rule Name** | **Description** | **Recommended** | +| :--------------------------------------------------------------- | :----------------------------------- | :-------------: | +| [`baseline`](./docs/rules/baseline.md) | Enforce the use of baseline features | yes | +| [`no-duplicate-imports`](./docs/rules/no-duplicate-imports.md) | Disallow duplicate @import rules | yes | +| [`no-empty-blocks`](./docs/rules/no-empty-blocks.md) | Disallow empty blocks | yes | +| [`no-invalid-at-rules`](./docs/rules/no-invalid-at-rules.md) | Disallow invalid at-rules | yes | +| [`no-invalid-properties`](./docs/rules/no-invalid-properties.md) | Disallow invalid properties | yes | diff --git a/docs/rules/baseline.md b/docs/rules/baseline.md new file mode 100644 index 0000000..73dcbea --- /dev/null +++ b/docs/rules/baseline.md @@ -0,0 +1,64 @@ +# baseline + +Enforce the use of baseline features + +## Background + +[Baseline](https://web.dev/baseline) is an effort by the [W3C WebDX Community Group](https://github.com/web-platform-dx) to document which features are available in four core browsers: Chrome (desktop and Android), Edge, Firefox (desktop and Android), and Safari (macOS and iOS). This data allows developers to choose the technologies that are best supported for their audience. As part of this effort, Baseline tracks which CSS features are available in which browsers. + +Features are grouped into three levels: + +- **Widely available** features are those supported by all core browsers for at least 30 months. +- **Newly available** features are those supported by all core browsers for less than 30 months. +- **Limited availability** features are those supported by some but not all core browsers. + +Generally speaking, it's preferable to stick to widely available features to ensure the greatest interoperability across browsers. + +## Rule Details + +This rule warns when it finds any of the following: + +- A CSS property that isn't widely available or otherwise isn't enclosed in a `@supports` block. +- An at-rule that isn't widely available. +- A CSS property value that isn't widely available or otherwise isn't enclosed in a `@supports` block (currently limited to identifiers only). +- A CSS property function that isn't widely available. + +The data is provided via the [web-features](https://npmjs.com/package/web-features) package. + +Here are some examples: + +```css +/* invalid - accent-color is not widely available */ +a { + accent-color: red; +} + +/* invalid - abs is not widely available */ +.box { + width: abs(20% - 100px); +} + +/* invalid - property value doesn't match @supports indicator */ +@supports (accent-color: auto) { + a { + accent-color: red; + } +} + +/* valid - @supports indicates you're choosing a limited availability property */ +@supports (accent-color: auto) { + a { + accent-color: auto; + } +} +``` + +### Options + +This rule accepts an option object with the following properties: + +- `available` (default: `"widely"`) - change to `"newly"` available to allow a larger number of properties and at-rules. + +## When Not to Use It + +If your web application targets just one browser then you can safely disable this rule. diff --git a/package.json b/package.json index a88afb8..be26e90 100644 --- a/package.json +++ b/package.json @@ -35,7 +35,10 @@ "prettier --write" ], "!(*.js)": "prettier --write --ignore-unknown", - "{src/rules/*.js,tools/update-rules-docs.js}": "npm run build:update-rules-docs" + "{src/rules/*.js,tools/update-rules-docs.js}": [ + "node tools/update-rules-docs.js", + "git add README.md " + ] }, "repository": { "type": "git", @@ -51,6 +54,7 @@ "build": "rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts", "build:readme": "node tools/update-readme.js", "build:update-rules-docs": "node tools/update-rules-docs.js", + "build:baseline": "node tools/generate-baseline.js", "test:jsr": "npx jsr@latest publish --dry-run", "pretest": "npm run build", "lint": "eslint", @@ -89,6 +93,7 @@ "rollup": "^4.16.2", "rollup-plugin-copy": "^3.5.0", "typescript": "^5.4.5", + "web-features": "^2.11.0", "yorkie": "^2.0.0" }, "engines": { diff --git a/src/data/README.md b/src/data/README.md new file mode 100644 index 0000000..639ba50 --- /dev/null +++ b/src/data/README.md @@ -0,0 +1,13 @@ +# Data + +Some of the files in this directory are auto-generated and should not be modified manually. + +## baseline-data.js (autogenerated) + +Contains the aggregated data for [baseline](https://web.dev/baseline). + +To generate baseline data, run: + +```shell +npm run build:baseline +``` diff --git a/src/data/baseline-data.js b/src/data/baseline-data.js new file mode 100644 index 0000000..520cc95 --- /dev/null +++ b/src/data/baseline-data.js @@ -0,0 +1,6936 @@ +/** + * @fileoverview CSS features extracted from the web-features package. + * @author tools/generate-baseline.js + * + * THIS FILE IS AUTOGENERATED. DO NOT MODIFY DIRECTLY. + */ + +export const BASELINE_HIGH = 10; +export const BASELINE_LOW = 5; +export const BASELINE_FALSE = 0; + +export const properties = new Map([ + [ + "accent-color", + 0 + ], + [ + "alignment-baseline", + 0 + ], + [ + "all", + 10 + ], + [ + "anchor-name", + 0 + ], + [ + "anchor-scope", + 0 + ], + [ + "position-anchor", + 0 + ], + [ + "position-area", + 0 + ], + [ + "position-try", + 0 + ], + [ + "position-try-fallbacks", + 0 + ], + [ + "position-try-order", + 0 + ], + [ + "position-visibility", + 0 + ], + [ + "animation-composition", + 5 + ], + [ + "animation", + 10 + ], + [ + "animation-delay", + 10 + ], + [ + "animation-direction", + 10 + ], + [ + "animation-duration", + 10 + ], + [ + "animation-fill-mode", + 10 + ], + [ + "animation-iteration-count", + 10 + ], + [ + "animation-name", + 10 + ], + [ + "animation-play-state", + 10 + ], + [ + "animation-timing-function", + 10 + ], + [ + "appearance", + 10 + ], + [ + "aspect-ratio", + 10 + ], + [ + "backdrop-filter", + 5 + ], + [ + "background", + 10 + ], + [ + "background-attachment", + 10 + ], + [ + "background-blend-mode", + 10 + ], + [ + "background-clip", + 10 + ], + [ + "background-color", + 10 + ], + [ + "background-image", + 10 + ], + [ + "background-origin", + 10 + ], + [ + "background-position", + 10 + ], + [ + "background-position-x", + 10 + ], + [ + "background-position-y", + 10 + ], + [ + "background-repeat", + 10 + ], + [ + "background-size", + 10 + ], + [ + "baseline-shift", + 0 + ], + [ + "baseline-source", + 0 + ], + [ + "border-image", + 10 + ], + [ + "border-image-outset", + 10 + ], + [ + "border-image-repeat", + 10 + ], + [ + "border-image-slice", + 10 + ], + [ + "border-image-source", + 10 + ], + [ + "border-image-width", + 10 + ], + [ + "border-bottom-left-radius", + 10 + ], + [ + "border-bottom-right-radius", + 10 + ], + [ + "border-radius", + 10 + ], + [ + "border-top-left-radius", + 10 + ], + [ + "border-top-right-radius", + 10 + ], + [ + "border", + 10 + ], + [ + "border-bottom", + 10 + ], + [ + "border-bottom-color", + 10 + ], + [ + "border-bottom-style", + 10 + ], + [ + "border-bottom-width", + 10 + ], + [ + "border-color", + 10 + ], + [ + "border-left", + 10 + ], + [ + "border-left-color", + 10 + ], + [ + "border-left-style", + 10 + ], + [ + "border-left-width", + 10 + ], + [ + "border-right", + 10 + ], + [ + "border-right-color", + 10 + ], + [ + "border-right-style", + 10 + ], + [ + "border-right-width", + 10 + ], + [ + "border-style", + 10 + ], + [ + "border-top", + 10 + ], + [ + "border-top-color", + 10 + ], + [ + "border-top-style", + 10 + ], + [ + "border-top-width", + 10 + ], + [ + "border-width", + 10 + ], + [ + "box-decoration-break", + 0 + ], + [ + "box-shadow", + 10 + ], + [ + "box-sizing", + 10 + ], + [ + "caret-color", + 10 + ], + [ + "clip-path", + 10 + ], + [ + "color", + 10 + ], + [ + "color-scheme", + 10 + ], + [ + "column-fill", + 10 + ], + [ + "column-span", + 10 + ], + [ + "contain", + 10 + ], + [ + "contain-intrinsic-block-size", + 5 + ], + [ + "contain-intrinsic-height", + 5 + ], + [ + "contain-intrinsic-inline-size", + 5 + ], + [ + "contain-intrinsic-size", + 5 + ], + [ + "contain-intrinsic-width", + 5 + ], + [ + "container", + 5 + ], + [ + "container-name", + 5 + ], + [ + "container-type", + 5 + ], + [ + "content", + 10 + ], + [ + "content-visibility", + 5 + ], + [ + "counter-set", + 5 + ], + [ + "counter-increment", + 10 + ], + [ + "counter-reset", + 10 + ], + [ + "cursor", + 0 + ], + [ + "custom-property", + 10 + ], + [ + "display", + 10 + ], + [ + "dominant-baseline", + 10 + ], + [ + "field-sizing", + 0 + ], + [ + "filter", + 10 + ], + [ + "align-content", + 10 + ], + [ + "align-items", + 10 + ], + [ + "align-self", + 10 + ], + [ + "flex", + 10 + ], + [ + "flex-basis", + 10 + ], + [ + "flex-direction", + 10 + ], + [ + "flex-flow", + 10 + ], + [ + "flex-grow", + 10 + ], + [ + "flex-shrink", + 10 + ], + [ + "flex-wrap", + 10 + ], + [ + "justify-content", + 10 + ], + [ + "justify-items", + 10 + ], + [ + "order", + 10 + ], + [ + "place-content", + 10 + ], + [ + "place-items", + 10 + ], + [ + "place-self", + 10 + ], + [ + "clear", + 10 + ], + [ + "float", + 10 + ], + [ + "font-family", + 10 + ], + [ + "font-feature-settings", + 10 + ], + [ + "font-kerning", + 10 + ], + [ + "font-language-override", + 0 + ], + [ + "font-optical-sizing", + 10 + ], + [ + "font-palette", + 5 + ], + [ + "font", + 10 + ], + [ + "font-size", + 10 + ], + [ + "font-size-adjust", + 5 + ], + [ + "font-stretch", + 10 + ], + [ + "font-style", + 10 + ], + [ + "font-synthesis", + 10 + ], + [ + "font-synthesis-position", + 0 + ], + [ + "font-synthesis-small-caps", + 5 + ], + [ + "font-synthesis-style", + 5 + ], + [ + "font-synthesis-weight", + 5 + ], + [ + "font-variant", + 10 + ], + [ + "font-variant-alternates", + 5 + ], + [ + "font-variant-caps", + 10 + ], + [ + "font-variant-east-asian", + 10 + ], + [ + "font-variant-emoji", + 0 + ], + [ + "font-variant-ligatures", + 10 + ], + [ + "font-variant-numeric", + 10 + ], + [ + "font-variant-position", + 0 + ], + [ + "font-variation-settings", + 10 + ], + [ + "font-weight", + 10 + ], + [ + "forced-color-adjust", + 5 + ], + [ + "gap", + 10 + ], + [ + "grid", + 10 + ], + [ + "grid-area", + 10 + ], + [ + "grid-auto-columns", + 10 + ], + [ + "grid-auto-flow", + 10 + ], + [ + "grid-auto-rows", + 10 + ], + [ + "grid-column", + 10 + ], + [ + "grid-column-end", + 10 + ], + [ + "grid-column-start", + 10 + ], + [ + "grid-row", + 10 + ], + [ + "grid-row-end", + 10 + ], + [ + "grid-row-start", + 10 + ], + [ + "grid-template", + 10 + ], + [ + "grid-template-areas", + 10 + ], + [ + "grid-template-columns", + 10 + ], + [ + "grid-template-rows", + 10 + ], + [ + "justify-self", + 10 + ], + [ + "row-gap", + 10 + ], + [ + "hanging-punctuation", + 0 + ], + [ + "hyphenate-character", + 5 + ], + [ + "hyphenate-limit-chars", + 0 + ], + [ + "hyphens", + 5 + ], + [ + "image-orientation", + 10 + ], + [ + "image-rendering", + 10 + ], + [ + "rotate", + 5 + ], + [ + "scale", + 5 + ], + [ + "translate", + 5 + ], + [ + "initial-letter", + 0 + ], + [ + "interpolate-size", + 0 + ], + [ + "isolation", + 10 + ], + [ + "direction", + 10 + ], + [ + "unicode-bidi", + 10 + ], + [ + "letter-spacing", + 10 + ], + [ + "line-break", + 10 + ], + [ + "line-clamp", + 0 + ], + [ + "line-height", + 10 + ], + [ + "list-style", + 10 + ], + [ + "list-style-image", + 10 + ], + [ + "list-style-position", + 10 + ], + [ + "list-style-type", + 10 + ], + [ + "block-size", + 10 + ], + [ + "border-block", + 10 + ], + [ + "border-block-color", + 10 + ], + [ + "border-block-end", + 10 + ], + [ + "border-block-end-color", + 10 + ], + [ + "border-block-end-style", + 10 + ], + [ + "border-block-end-width", + 10 + ], + [ + "border-block-start", + 10 + ], + [ + "border-block-start-color", + 10 + ], + [ + "border-block-start-style", + 10 + ], + [ + "border-block-start-width", + 10 + ], + [ + "border-block-style", + 10 + ], + [ + "border-block-width", + 10 + ], + [ + "border-end-end-radius", + 10 + ], + [ + "border-end-start-radius", + 10 + ], + [ + "border-inline", + 10 + ], + [ + "border-inline-color", + 10 + ], + [ + "border-inline-end", + 10 + ], + [ + "border-inline-end-color", + 10 + ], + [ + "border-inline-end-style", + 10 + ], + [ + "border-inline-end-width", + 10 + ], + [ + "border-inline-start", + 10 + ], + [ + "border-inline-start-color", + 10 + ], + [ + "border-inline-start-style", + 10 + ], + [ + "border-inline-start-width", + 10 + ], + [ + "border-inline-style", + 10 + ], + [ + "border-inline-width", + 10 + ], + [ + "border-start-end-radius", + 10 + ], + [ + "border-start-start-radius", + 10 + ], + [ + "inline-size", + 10 + ], + [ + "inset", + 10 + ], + [ + "inset-block", + 10 + ], + [ + "inset-block-end", + 10 + ], + [ + "inset-block-start", + 10 + ], + [ + "inset-inline", + 10 + ], + [ + "inset-inline-end", + 10 + ], + [ + "inset-inline-start", + 10 + ], + [ + "margin-block", + 10 + ], + [ + "margin-block-end", + 10 + ], + [ + "margin-block-start", + 10 + ], + [ + "margin-inline", + 10 + ], + [ + "margin-inline-end", + 10 + ], + [ + "margin-inline-start", + 10 + ], + [ + "max-block-size", + 10 + ], + [ + "max-inline-size", + 10 + ], + [ + "min-block-size", + 10 + ], + [ + "min-inline-size", + 10 + ], + [ + "overflow-block", + 10 + ], + [ + "overflow-inline", + 10 + ], + [ + "padding-block", + 10 + ], + [ + "padding-block-end", + 10 + ], + [ + "padding-block-start", + 10 + ], + [ + "padding-inline", + 10 + ], + [ + "padding-inline-end", + 10 + ], + [ + "padding-inline-start", + 10 + ], + [ + "margin", + 10 + ], + [ + "margin-bottom", + 10 + ], + [ + "margin-left", + 10 + ], + [ + "margin-right", + 10 + ], + [ + "margin-top", + 10 + ], + [ + "margin-trim", + 0 + ], + [ + "mask-border", + 0 + ], + [ + "mask-border-outset", + 0 + ], + [ + "mask-border-repeat", + 0 + ], + [ + "mask-border-slice", + 0 + ], + [ + "mask-border-source", + 0 + ], + [ + "mask-border-width", + 0 + ], + [ + "mask-type", + 10 + ], + [ + "mask", + 5 + ], + [ + "mask-clip", + 5 + ], + [ + "mask-composite", + 5 + ], + [ + "mask-image", + 5 + ], + [ + "mask-mode", + 5 + ], + [ + "mask-origin", + 5 + ], + [ + "mask-position", + 5 + ], + [ + "mask-repeat", + 5 + ], + [ + "mask-size", + 5 + ], + [ + "math-depth", + 5 + ], + [ + "math-shift", + 5 + ], + [ + "math-style", + 5 + ], + [ + "max-height", + 10 + ], + [ + "max-width", + 10 + ], + [ + "min-height", + 10 + ], + [ + "min-width", + 10 + ], + [ + "mix-blend-mode", + 10 + ], + [ + "offset", + 5 + ], + [ + "offset-anchor", + 5 + ], + [ + "offset-distance", + 5 + ], + [ + "offset-path", + 5 + ], + [ + "offset-position", + 5 + ], + [ + "offset-rotate", + 5 + ], + [ + "column-count", + 10 + ], + [ + "column-gap", + 10 + ], + [ + "column-rule", + 10 + ], + [ + "column-rule-color", + 10 + ], + [ + "column-rule-style", + 10 + ], + [ + "column-rule-width", + 10 + ], + [ + "column-width", + 10 + ], + [ + "columns", + 10 + ], + [ + "object-fit", + 10 + ], + [ + "object-position", + 10 + ], + [ + "object-view-box", + 0 + ], + [ + "opacity", + 10 + ], + [ + "fill-opacity", + 10 + ], + [ + "stroke-opacity", + 10 + ], + [ + "outline", + 5 + ], + [ + "outline-color", + 10 + ], + [ + "outline-offset", + 10 + ], + [ + "outline-style", + 10 + ], + [ + "outline-width", + 10 + ], + [ + "overflow-anchor", + 0 + ], + [ + "overflow-clip-margin", + 0 + ], + [ + "overflow", + 5 + ], + [ + "overflow-x", + 5 + ], + [ + "overflow-y", + 5 + ], + [ + "overflow-wrap", + 10 + ], + [ + "overlay", + 0 + ], + [ + "overscroll-behavior", + 5 + ], + [ + "overscroll-behavior-block", + 5 + ], + [ + "overscroll-behavior-inline", + 5 + ], + [ + "overscroll-behavior-x", + 5 + ], + [ + "overscroll-behavior-y", + 5 + ], + [ + "padding", + 10 + ], + [ + "padding-bottom", + 10 + ], + [ + "padding-left", + 10 + ], + [ + "padding-right", + 10 + ], + [ + "padding-top", + 10 + ], + [ + "break-after", + 0 + ], + [ + "break-before", + 0 + ], + [ + "break-inside", + 0 + ], + [ + "page-break-after", + 0 + ], + [ + "page-break-before", + 0 + ], + [ + "page-break-inside", + 0 + ], + [ + "page", + 0 + ], + [ + "paint-order", + 0 + ], + [ + "bottom", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "top", + 10 + ], + [ + "pointer-events", + 10 + ], + [ + "position", + 10 + ], + [ + "print-color-adjust", + 0 + ], + [ + "quotes", + 10 + ], + [ + "reading-flow", + 0 + ], + [ + "resize", + 0 + ], + [ + "line-height-step", + 0 + ], + [ + "ruby-align", + 0 + ], + [ + "ruby-overhang", + 0 + ], + [ + "ruby-position", + 0 + ], + [ + "scroll-behavior", + 10 + ], + [ + "animation-range", + 0 + ], + [ + "animation-range-end", + 0 + ], + [ + "animation-range-start", + 0 + ], + [ + "animation-timeline", + 0 + ], + [ + "scroll-timeline", + 0 + ], + [ + "scroll-timeline-axis", + 0 + ], + [ + "scroll-timeline-name", + 0 + ], + [ + "timeline-scope", + 0 + ], + [ + "view-timeline", + 0 + ], + [ + "view-timeline-axis", + 0 + ], + [ + "view-timeline-inset", + 0 + ], + [ + "view-timeline-name", + 0 + ], + [ + "scroll-margin", + 10 + ], + [ + "scroll-margin-block", + 10 + ], + [ + "scroll-margin-block-end", + 10 + ], + [ + "scroll-margin-block-start", + 10 + ], + [ + "scroll-margin-bottom", + 10 + ], + [ + "scroll-margin-inline", + 10 + ], + [ + "scroll-margin-inline-end", + 10 + ], + [ + "scroll-margin-inline-start", + 10 + ], + [ + "scroll-margin-left", + 10 + ], + [ + "scroll-margin-right", + 10 + ], + [ + "scroll-margin-top", + 10 + ], + [ + "scroll-padding", + 10 + ], + [ + "scroll-padding-block", + 10 + ], + [ + "scroll-padding-block-end", + 10 + ], + [ + "scroll-padding-block-start", + 10 + ], + [ + "scroll-padding-bottom", + 10 + ], + [ + "scroll-padding-inline", + 10 + ], + [ + "scroll-padding-inline-end", + 10 + ], + [ + "scroll-padding-inline-start", + 10 + ], + [ + "scroll-padding-left", + 10 + ], + [ + "scroll-padding-right", + 10 + ], + [ + "scroll-padding-top", + 10 + ], + [ + "scroll-snap-align", + 10 + ], + [ + "scroll-snap-stop", + 10 + ], + [ + "scroll-snap-type", + 10 + ], + [ + "scrollbar-color", + 0 + ], + [ + "scrollbar-gutter", + 0 + ], + [ + "scrollbar-width", + 0 + ], + [ + "shape-image-threshold", + 10 + ], + [ + "shape-margin", + 10 + ], + [ + "shape-outside", + 10 + ], + [ + "speak", + 0 + ], + [ + "speak-as", + 0 + ], + [ + "clip-rule", + 10 + ], + [ + "color-interpolation", + 10 + ], + [ + "cx", + 10 + ], + [ + "cy", + 10 + ], + [ + "d", + 10 + ], + [ + "fill", + 10 + ], + [ + "fill-rule", + 10 + ], + [ + "marker", + 10 + ], + [ + "marker-end", + 10 + ], + [ + "marker-mid", + 10 + ], + [ + "marker-start", + 10 + ], + [ + "r", + 10 + ], + [ + "rx", + 10 + ], + [ + "ry", + 10 + ], + [ + "shape-rendering", + 10 + ], + [ + "stop-color", + 10 + ], + [ + "stop-opacity", + 10 + ], + [ + "stroke", + 10 + ], + [ + "stroke-color", + 10 + ], + [ + "stroke-dasharray", + 10 + ], + [ + "stroke-dashoffset", + 10 + ], + [ + "stroke-linecap", + 10 + ], + [ + "stroke-linejoin", + 10 + ], + [ + "stroke-miterlimit", + 10 + ], + [ + "stroke-width", + 10 + ], + [ + "text-anchor", + 10 + ], + [ + "text-rendering", + 10 + ], + [ + "vector-effect", + 10 + ], + [ + "x", + 10 + ], + [ + "y", + 10 + ], + [ + "color-interpolation-filters", + 10 + ], + [ + "flood-color", + 10 + ], + [ + "flood-opacity", + 10 + ], + [ + "lighting-color", + 10 + ], + [ + "tab-size", + 10 + ], + [ + "border-collapse", + 10 + ], + [ + "border-spacing", + 10 + ], + [ + "caption-side", + 10 + ], + [ + "empty-cells", + 10 + ], + [ + "table-layout", + 10 + ], + [ + "text-align", + 10 + ], + [ + "text-align-last", + 5 + ], + [ + "text-box", + 0 + ], + [ + "text-box-edge", + 0 + ], + [ + "text-box-trim", + 0 + ], + [ + "text-combine-upright", + 10 + ], + [ + "text-decoration", + 10 + ], + [ + "text-decoration-color", + 10 + ], + [ + "text-decoration-line", + 10 + ], + [ + "text-decoration-skip", + 10 + ], + [ + "text-decoration-skip-ink", + 10 + ], + [ + "text-decoration-style", + 10 + ], + [ + "text-decoration-thickness", + 10 + ], + [ + "text-emphasis", + 10 + ], + [ + "text-emphasis-color", + 10 + ], + [ + "text-emphasis-position", + 10 + ], + [ + "text-emphasis-style", + 10 + ], + [ + "text-indent", + 10 + ], + [ + "text-justify", + 0 + ], + [ + "text-orientation", + 10 + ], + [ + "text-overflow", + 10 + ], + [ + "text-shadow", + 10 + ], + [ + "text-size-adjust", + 0 + ], + [ + "text-spacing-trim", + 0 + ], + [ + "-webkit-text-fill-color", + 10 + ], + [ + "-webkit-text-stroke", + 10 + ], + [ + "-webkit-text-stroke-color", + 10 + ], + [ + "-webkit-text-stroke-width", + 10 + ], + [ + "text-transform", + 10 + ], + [ + "text-underline-offset", + 10 + ], + [ + "text-underline-position", + 10 + ], + [ + "text-wrap", + 5 + ], + [ + "text-wrap-mode", + 5 + ], + [ + "text-wrap-style", + 0 + ], + [ + "touch-action", + 10 + ], + [ + "transform-box", + 5 + ], + [ + "transform", + 10 + ], + [ + "transform-origin", + 10 + ], + [ + "backface-visibility", + 10 + ], + [ + "perspective", + 10 + ], + [ + "perspective-origin", + 10 + ], + [ + "transform-style", + 10 + ], + [ + "transition-behavior", + 5 + ], + [ + "transition", + 10 + ], + [ + "transition-delay", + 10 + ], + [ + "transition-duration", + 10 + ], + [ + "transition-property", + 10 + ], + [ + "transition-timing-function", + 10 + ], + [ + "user-select", + 0 + ], + [ + "vertical-align", + 10 + ], + [ + "view-transition-class", + 0 + ], + [ + "view-transition-name", + 0 + ], + [ + "visibility", + 10 + ], + [ + "white-space", + 10 + ], + [ + "white-space-collapse", + 5 + ], + [ + "orphans", + 0 + ], + [ + "widows", + 0 + ], + [ + "height", + 10 + ], + [ + "width", + 10 + ], + [ + "will-change", + 10 + ], + [ + "word-break", + 10 + ], + [ + "word-spacing", + 10 + ], + [ + "writing-mode", + 10 + ], + [ + "z-index", + 10 + ], + [ + "zoom", + 5 + ] +]); +export const atRules = new Map([ + [ + "position-try", + 0 + ], + [ + "keyframes", + 10 + ], + [ + "layer", + 10 + ], + [ + "charset", + 10 + ], + [ + "container", + 5 + ], + [ + "counter-style", + 5 + ], + [ + "view-transition", + 0 + ], + [ + "font-face", + 10 + ], + [ + "font-palette-values", + 5 + ], + [ + "font-feature-values", + 5 + ], + [ + "import", + 10 + ], + [ + "media", + 10 + ], + [ + "namespace", + 10 + ], + [ + "page", + 0 + ], + [ + "property", + 5 + ], + [ + "scope", + 0 + ], + [ + "starting-style", + 0 + ], + [ + "supports", + 10 + ] +]); +export const types = new Map([ + [ + "abs", + 0 + ], + [ + "sign", + 0 + ], + [ + "anchor", + 0 + ], + [ + "anchor-size", + 0 + ], + [ + "time", + 10 + ], + [ + "attr", + 10 + ], + [ + "blend-mode", + 10 + ], + [ + "line-style", + 10 + ], + [ + "calc", + 10 + ], + [ + "calc-constant", + 5 + ], + [ + "calc-size", + 0 + ], + [ + "color", + 10 + ], + [ + "string", + 10 + ], + [ + "counter", + 10 + ], + [ + "counters", + 10 + ], + [ + "easing-function", + 10 + ], + [ + "exp", + 5 + ], + [ + "hypot", + 5 + ], + [ + "log", + 5 + ], + [ + "pow", + 5 + ], + [ + "sqrt", + 5 + ], + [ + "filter-function", + 10 + ], + [ + "url", + 10 + ], + [ + "gradient", + 10 + ], + [ + "image", + 10 + ], + [ + "flex", + 10 + ], + [ + "ratio", + 10 + ], + [ + "clamp", + 10 + ], + [ + "max", + 10 + ], + [ + "min", + 10 + ], + [ + "ray", + 5 + ], + [ + "number", + 10 + ], + [ + "overflow", + 5 + ], + [ + "resolution", + 5 + ], + [ + "mod", + 5 + ], + [ + "rem", + 5 + ], + [ + "round", + 5 + ], + [ + "basic-shape", + 10 + ], + [ + "angle", + 10 + ], + [ + "angle-percentage", + 10 + ], + [ + "position", + 10 + ], + [ + "transform-function", + 10 + ], + [ + "acos", + 5 + ], + [ + "asin", + 5 + ], + [ + "atan", + 5 + ], + [ + "atan2", + 5 + ], + [ + "cos", + 5 + ], + [ + "sin", + 5 + ], + [ + "tan", + 5 + ], + [ + "dimension", + 10 + ], + [ + "length", + 10 + ], + [ + "length-percentage", + 10 + ], + [ + "percentage", + 10 + ], + [ + "integer", + 10 + ] +]); +export const selectors = new Map([ + [ + "active-view-transition", + 0 + ], + [ + "active-view-transition-type", + 0 + ], + [ + "autofill", + 5 + ], + [ + "defined", + 10 + ], + [ + "backdrop", + 10 + ], + [ + "after", + 10 + ], + [ + "before", + 10 + ], + [ + "default", + 10 + ], + [ + "details-content", + 0 + ], + [ + "dir", + 5 + ], + [ + "empty", + 10 + ], + [ + "file-selector-button", + 10 + ], + [ + "first-letter", + 10 + ], + [ + "first-line", + 10 + ], + [ + "focus-visible", + 10 + ], + [ + "focus-within", + 10 + ], + [ + "in-range", + 10 + ], + [ + "invalid", + 10 + ], + [ + "optional", + 10 + ], + [ + "out-of-range", + 10 + ], + [ + "required", + 10 + ], + [ + "valid", + 10 + ], + [ + "fullscreen", + 0 + ], + [ + "has", + 5 + ], + [ + "has-slotted", + 0 + ], + [ + "highlight", + 0 + ], + [ + "host", + 10 + ], + [ + "hostfunction", + 10 + ], + [ + "host-context", + 0 + ], + [ + "indeterminate", + 10 + ], + [ + "checked", + 10 + ], + [ + "disabled", + 10 + ], + [ + "enabled", + 10 + ], + [ + "is", + 10 + ], + [ + "lang", + 10 + ], + [ + "any-link", + 10 + ], + [ + "link", + 10 + ], + [ + "visited", + 10 + ], + [ + "marker", + 0 + ], + [ + "buffering", + 0 + ], + [ + "muted", + 0 + ], + [ + "paused", + 0 + ], + [ + "playing", + 0 + ], + [ + "seeking", + 0 + ], + [ + "stalled", + 0 + ], + [ + "volume-locked", + 0 + ], + [ + "modal", + 5 + ], + [ + "namespace", + 10 + ], + [ + "nesting", + 5 + ], + [ + "not", + 10 + ], + [ + "first-child", + 10 + ], + [ + "last-child", + 10 + ], + [ + "nth-child", + 10 + ], + [ + "nth-last-child", + 10 + ], + [ + "only-child", + 10 + ], + [ + "first-of-type", + 10 + ], + [ + "last-of-type", + 10 + ], + [ + "nth-last-of-type", + 10 + ], + [ + "nth-of-type", + 10 + ], + [ + "only-of-type", + 10 + ], + [ + "closed", + 0 + ], + [ + "open", + 0 + ], + [ + "first", + 0 + ], + [ + "left", + 0 + ], + [ + "right", + 0 + ], + [ + "picture-in-picture", + 0 + ], + [ + "placeholder", + 10 + ], + [ + "placeholder-shown", + 10 + ], + [ + "popover-open", + 0 + ], + [ + "read-only", + 10 + ], + [ + "read-write", + 10 + ], + [ + "root", + 10 + ], + [ + "scope", + 10 + ], + [ + "selection", + 0 + ], + [ + "attribute", + 10 + ], + [ + "child", + 10 + ], + [ + "class", + 10 + ], + [ + "descendant", + 10 + ], + [ + "id", + 10 + ], + [ + "list", + 10 + ], + [ + "next-sibling", + 10 + ], + [ + "subsequent-sibling", + 10 + ], + [ + "type", + 10 + ], + [ + "universal", + 10 + ], + [ + "part", + 10 + ], + [ + "slotted", + 10 + ], + [ + "grammar-error", + 0 + ], + [ + "spelling-error", + 0 + ], + [ + "state", + 5 + ], + [ + "target", + 10 + ], + [ + "target-text", + 0 + ], + [ + "future", + 0 + ], + [ + "past", + 0 + ], + [ + "active", + 10 + ], + [ + "focus", + 10 + ], + [ + "hover", + 10 + ], + [ + "user-invalid", + 5 + ], + [ + "user-valid", + 5 + ], + [ + "view-transition", + 0 + ], + [ + "view-transition-group", + 0 + ], + [ + "view-transition-image-pair", + 0 + ], + [ + "view-transition-new", + 0 + ], + [ + "view-transition-old", + 0 + ], + [ + "cue", + 10 + ], + [ + "xr-overlay", + 0 + ], + [ + "where", + 10 + ] +]); +export const propertyValues = new Map([["position", new Map([ + [ + "absolute", + 10 + ], + [ + "fixed", + 10 + ], + [ + "relative", + 10 + ], + [ + "static", + 10 + ], + [ + "sticky", + 10 + ] +])],["accent-color", new Map([ + [ + "auto", + 0 + ] +])],["alignment-baseline", new Map([ + [ + "alphabetic", + 0 + ], + [ + "baseline", + 0 + ], + [ + "central", + 0 + ], + [ + "ideographic", + 0 + ], + [ + "mathematical", + 0 + ], + [ + "middle", + 0 + ] +])],["align-items", new Map([ + [ + "anchor-center", + 0 + ] +])],["align-self", new Map([ + [ + "anchor-center", + 0 + ] +])],["anchor-name", new Map([ + [ + "none", + 0 + ] +])],["anchor-scope", new Map([ + [ + "all", + 0 + ], + [ + "none", + 0 + ] +])],["block-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["bottom", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["height", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "stretch", + 0 + ], + [ + "auto", + 10 + ] +])],["inline-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["inset-block-end", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset-block-start", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset-block", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset-inline-end", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset-inline-start", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset-inline", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["inset", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["justify-items", new Map([ + [ + "anchor-center", + 0 + ] +])],["justify-self", new Map([ + [ + "anchor-center", + 0 + ] +])],["left", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["max-block-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["max-height", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "none", + 10 + ], + [ + "stretch", + 0 + ] +])],["max-inline-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["max-width", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "none", + 10 + ], + [ + "stretch", + 0 + ] +])],["min-block-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["min-height", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "auto", + 10 + ], + [ + "stretch", + 0 + ] +])],["min-inline-size", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["min-width", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "auto", + 10 + ], + [ + "stretch", + 0 + ] +])],["place-items", new Map([ + [ + "anchor-center", + 0 + ] +])],["place-self", new Map([ + [ + "anchor-center", + 0 + ] +])],["position-anchor", new Map([ + [ + "auto", + 0 + ] +])],["position-area", new Map([ + [ + "block-end", + 0 + ], + [ + "block-start", + 0 + ], + [ + "bottom", + 0 + ], + [ + "center", + 0 + ], + [ + "end", + 0 + ], + [ + "inline-end", + 0 + ], + [ + "inline-start", + 0 + ], + [ + "left", + 0 + ], + [ + "none", + 0 + ], + [ + "right", + 0 + ], + [ + "self-end", + 0 + ], + [ + "self-start", + 0 + ], + [ + "span-all", + 0 + ], + [ + "span-block-end", + 0 + ], + [ + "span-block-start", + 0 + ], + [ + "span-bottom", + 0 + ], + [ + "span-end", + 0 + ], + [ + "span-inline-end", + 0 + ], + [ + "span-inline-start", + 0 + ], + [ + "span-start", + 0 + ], + [ + "span-top", + 0 + ], + [ + "span-x-end", + 0 + ], + [ + "span-x-start", + 0 + ], + [ + "span-y-end", + 0 + ], + [ + "span-y-start", + 0 + ], + [ + "start", + 0 + ], + [ + "top", + 0 + ], + [ + "x-end", + 0 + ], + [ + "x-self-end", + 0 + ], + [ + "x-self-start", + 0 + ], + [ + "x-start", + 0 + ], + [ + "y-end", + 0 + ], + [ + "y-self-end", + 0 + ], + [ + "y-self-start", + 0 + ], + [ + "y-start", + 0 + ] +])],["position-try-fallbacks", new Map([ + [ + "flip-block", + 0 + ], + [ + "flip-inline", + 0 + ], + [ + "flip-start", + 0 + ], + [ + "none", + 0 + ], + [ + "position-area", + 0 + ] +])],["position-try-order", new Map([ + [ + "most-block-size", + 0 + ], + [ + "most-height", + 0 + ], + [ + "most-inline-size", + 0 + ], + [ + "most-width", + 0 + ], + [ + "normal", + 0 + ] +])],["position-visibility", new Map([ + [ + "always", + 0 + ], + [ + "anchors-visible", + 0 + ], + [ + "no-overflow", + 0 + ] +])],["right", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["top", new Map([ + [ + "anchor", + 0 + ], + [ + "auto", + 10 + ] +])],["width", new Map([ + [ + "anchor-size", + 0 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "stretch", + 0 + ], + [ + "auto", + 10 + ] +])],["animation-direction", new Map([ + [ + "alternate", + 10 + ], + [ + "alternate-reverse", + 10 + ], + [ + "normal", + 10 + ], + [ + "reverse", + 10 + ] +])],["animation-duration", new Map([ + [ + "auto", + 10 + ] +])],["animation-fill-mode", new Map([ + [ + "backwards", + 10 + ], + [ + "both", + 10 + ], + [ + "forwards", + 10 + ], + [ + "none", + 10 + ] +])],["animation-iteration-count", new Map([ + [ + "infinite", + 10 + ] +])],["animation-name", new Map([ + [ + "none", + 10 + ] +])],["animation-play-state", new Map([ + [ + "paused", + 10 + ], + [ + "running", + 10 + ] +])],["animation-timing-function", new Map([ + [ + "jump", + 10 + ] +])],["appearance", new Map([ + [ + "auto", + 10 + ], + [ + "button", + 10 + ], + [ + "checkbox", + 10 + ], + [ + "listbox", + 10 + ], + [ + "menulist", + 10 + ], + [ + "menulist-button", + 10 + ], + [ + "meter", + 10 + ], + [ + "none", + 10 + ], + [ + "progress-bar", + 10 + ], + [ + "radio", + 10 + ], + [ + "searchfield", + 10 + ], + [ + "textarea", + 10 + ], + [ + "textfield", + 10 + ] +])],["aspect-ratio", new Map([ + [ + "auto", + 10 + ] +])],["background-attachment", new Map([ + [ + "fixed", + 10 + ], + [ + "local", + 10 + ], + [ + "scroll", + 10 + ] +])],["background-clip", new Map([ + [ + "border-box", + 10 + ], + [ + "content-box", + 10 + ], + [ + "padding-box", + 10 + ], + [ + "border-area", + 0 + ], + [ + "text", + 0 + ] +])],["background", new Map([ + [ + "background-clip", + 10 + ], + [ + "background-origin", + 10 + ], + [ + "background-size", + 10 + ] +])],["background-image", new Map([ + [ + "none", + 10 + ], + [ + "element", + 0 + ], + [ + "gradients", + 10 + ], + [ + "image-set", + 5 + ] +])],["background-origin", new Map([ + [ + "border-box", + 10 + ], + [ + "content-box", + 10 + ], + [ + "padding-box", + 10 + ] +])],["background-position", new Map([ + [ + "bottom", + 10 + ], + [ + "center", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "top", + 10 + ] +])],["background-repeat", new Map([ + [ + "2-value", + 10 + ], + [ + "no-repeat", + 10 + ], + [ + "repeat", + 10 + ], + [ + "repeat-x", + 10 + ], + [ + "repeat-y", + 10 + ], + [ + "round", + 10 + ], + [ + "space", + 10 + ] +])],["background-size", new Map([ + [ + "auto", + 10 + ], + [ + "contain", + 10 + ], + [ + "cover", + 10 + ] +])],["baseline-shift", new Map([ + [ + "baseline", + 0 + ], + [ + "sub", + 0 + ], + [ + "super", + 0 + ] +])],["baseline-source", new Map([ + [ + "auto", + 0 + ], + [ + "first", + 0 + ], + [ + "last", + 0 + ] +])],["border-image-repeat", new Map([ + [ + "repeat", + 10 + ], + [ + "round", + 10 + ], + [ + "space", + 10 + ], + [ + "stretch", + 10 + ] +])],["border-image-width", new Map([ + [ + "auto", + 10 + ] +])],["border-image", new Map([ + [ + "fill", + 10 + ], + [ + "gradient", + 10 + ] +])],["border-bottom-left-radius", new Map([ + [ + "percentages", + 10 + ] +])],["border-bottom-right-radius", new Map([ + [ + "percentages", + 10 + ] +])],["border-radius", new Map([ + [ + "percentages", + 10 + ] +])],["border-top-left-radius", new Map([ + [ + "percentages", + 10 + ] +])],["border-top-right-radius", new Map([ + [ + "percentages", + 10 + ] +])],["border-style", new Map([ + [ + "dashed", + 10 + ], + [ + "dotted", + 10 + ], + [ + "double", + 10 + ], + [ + "groove", + 10 + ], + [ + "hidden", + 10 + ], + [ + "inset", + 10 + ], + [ + "none", + 10 + ], + [ + "outset", + 10 + ], + [ + "ridge", + 10 + ], + [ + "solid", + 10 + ] +])],["box-decoration-break", new Map([ + [ + "clone", + 0 + ], + [ + "slice", + 0 + ] +])],["box-shadow", new Map([ + [ + "inset", + 10 + ] +])],["box-sizing", new Map([ + [ + "border-box", + 10 + ], + [ + "content-box", + 10 + ] +])],["clip-path", new Map([ + [ + "path", + 10 + ], + [ + "fill-box", + 5 + ], + [ + "stroke-box", + 5 + ], + [ + "view-box", + 5 + ] +])],["color-scheme", new Map([ + [ + "dark", + 10 + ], + [ + "light", + 10 + ], + [ + "normal", + 10 + ] +])],["break-after", new Map([ + [ + "avoid-column", + 0 + ], + [ + "column", + 0 + ], + [ + "always", + 0 + ], + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ], + [ + "avoid-page", + 0 + ], + [ + "left", + 0 + ], + [ + "page", + 0 + ], + [ + "recto", + 0 + ], + [ + "right", + 0 + ], + [ + "verso", + 0 + ] +])],["break-before", new Map([ + [ + "avoid-column", + 0 + ], + [ + "column", + 0 + ], + [ + "always", + 0 + ], + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ], + [ + "avoid-page", + 0 + ], + [ + "left", + 0 + ], + [ + "page", + 0 + ], + [ + "recto", + 0 + ], + [ + "right", + 0 + ], + [ + "verso", + 0 + ] +])],["break-inside", new Map([ + [ + "avoid-column", + 0 + ], + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ], + [ + "avoid-page", + 0 + ] +])],["column-fill", new Map([ + [ + "auto", + 10 + ], + [ + "balance", + 10 + ] +])],["column-span", new Map([ + [ + "all", + 10 + ], + [ + "none", + 10 + ] +])],["contain", new Map([ + [ + "content", + 10 + ], + [ + "none", + 10 + ], + [ + "strict", + 10 + ], + [ + "inline-size", + 5 + ], + [ + "layout", + 10 + ], + [ + "paint", + 10 + ], + [ + "size", + 10 + ], + [ + "style", + 5 + ] +])],["contain-intrinsic-block-size", new Map([ + [ + "none", + 5 + ] +])],["contain-intrinsic-height", new Map([ + [ + "none", + 5 + ] +])],["contain-intrinsic-inline-size", new Map([ + [ + "none", + 5 + ] +])],["contain-intrinsic-size", new Map([ + [ + "none", + 5 + ] +])],["contain-intrinsic-width", new Map([ + [ + "none", + 5 + ] +])],["container-name", new Map([ + [ + "none", + 5 + ] +])],["container-type", new Map([ + [ + "inline-size", + 5 + ], + [ + "normal", + 5 + ], + [ + "size", + 5 + ] +])],["content", new Map([ + [ + "gradient", + 10 + ], + [ + "none", + 10 + ], + [ + "normal", + 10 + ], + [ + "url", + 10 + ], + [ + "image-set", + 5 + ] +])],["content-visibility", new Map([ + [ + "auto", + 5 + ], + [ + "hidden", + 5 + ], + [ + "visible", + 5 + ] +])],["counter-reset", new Map([ + [ + "reversed", + 0 + ], + [ + "list-item", + 10 + ], + [ + "none", + 10 + ] +])],["counter-set", new Map([ + [ + "list-item", + 5 + ], + [ + "none", + 5 + ] +])],["counter-increment", new Map([ + [ + "list-item", + 10 + ], + [ + "none", + 10 + ] +])],["image-rendering", new Map([ + [ + "crisp-edges", + 0 + ], + [ + "auto", + 10 + ], + [ + "pixelated", + 10 + ], + [ + "smooth", + 0 + ] +])],["cursor", new Map([ + [ + "alias", + 0 + ], + [ + "all-scroll", + 0 + ], + [ + "auto", + 0 + ], + [ + "cell", + 0 + ], + [ + "col-resize", + 0 + ], + [ + "context-menu", + 0 + ], + [ + "copy", + 0 + ], + [ + "crosshair", + 0 + ], + [ + "default", + 0 + ], + [ + "e-resize", + 0 + ], + [ + "ew-resize", + 0 + ], + [ + "grab", + 0 + ], + [ + "grabbing", + 0 + ], + [ + "help", + 0 + ], + [ + "move", + 0 + ], + [ + "n-resize", + 0 + ], + [ + "ne-resize", + 0 + ], + [ + "nesw-resize", + 0 + ], + [ + "no-drop", + 0 + ], + [ + "none", + 0 + ], + [ + "not-allowed", + 0 + ], + [ + "ns-resize", + 0 + ], + [ + "nw-resize", + 0 + ], + [ + "nwse-resize", + 0 + ], + [ + "pointer", + 0 + ], + [ + "progress", + 0 + ], + [ + "row-resize", + 0 + ], + [ + "s-resize", + 0 + ], + [ + "se-resize", + 0 + ], + [ + "sw-resize", + 0 + ], + [ + "text", + 0 + ], + [ + "url", + 0 + ], + [ + "vertical-text", + 0 + ], + [ + "w-resize", + 0 + ], + [ + "wait", + 0 + ], + [ + "zoom-in", + 0 + ], + [ + "zoom-out", + 0 + ] +])],["text-overflow", new Map([ + [ + "string", + 0 + ], + [ + "clip", + 10 + ], + [ + "ellipsis", + 10 + ] +])],["custom-property", new Map([ + [ + "var", + 10 + ], + [ + "env", + 10 + ] +])],["display", new Map([ + [ + "block", + 10 + ], + [ + "inline", + 10 + ], + [ + "inline-block", + 10 + ], + [ + "none", + 10 + ], + [ + "contents", + 0 + ], + [ + "flow-root", + 10 + ], + [ + "list-item", + 10 + ], + [ + "ruby", + 0 + ], + [ + "ruby-base", + 0 + ], + [ + "ruby-base-container", + 0 + ], + [ + "ruby-text", + 0 + ], + [ + "ruby-text-container", + 0 + ], + [ + "inline-table", + 10 + ], + [ + "table", + 10 + ], + [ + "table-caption", + 10 + ], + [ + "table-cell", + 10 + ], + [ + "table-column", + 10 + ], + [ + "table-column-group", + 10 + ], + [ + "table-footer-group", + 10 + ], + [ + "table-header-group", + 10 + ], + [ + "table-row", + 10 + ], + [ + "table-row-group", + 10 + ], + [ + "flex", + 10 + ], + [ + "inline-flex", + 10 + ], + [ + "grid", + 10 + ], + [ + "inline-grid", + 10 + ], + [ + "math", + 5 + ] +])],["dominant-baseline", new Map([ + [ + "alphabetic", + 10 + ], + [ + "auto", + 10 + ], + [ + "central", + 10 + ], + [ + "hanging", + 10 + ], + [ + "ideographic", + 10 + ], + [ + "mathematical", + 10 + ], + [ + "middle", + 10 + ] +])],["field-sizing", new Map([ + [ + "content", + 0 + ], + [ + "fixed", + 0 + ] +])],["flex-basis", new Map([ + [ + "auto", + 10 + ], + [ + "content", + 10 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ] +])],["flex-direction", new Map([ + [ + "column", + 10 + ], + [ + "column-reverse", + 10 + ], + [ + "row", + 10 + ], + [ + "row-reverse", + 10 + ] +])],["flex-wrap", new Map([ + [ + "nowrap", + 10 + ], + [ + "wrap", + 10 + ], + [ + "wrap-reverse", + 10 + ] +])],["flex", new Map([ + [ + "none", + 10 + ] +])],["clear", new Map([ + [ + "both", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "inline-end", + 10 + ], + [ + "inline-start", + 10 + ] +])],["float", new Map([ + [ + "left", + 10 + ], + [ + "none", + 10 + ], + [ + "right", + 10 + ], + [ + "inline-end", + 10 + ], + [ + "inline-start", + 10 + ] +])],["font-family", new Map([ + [ + "math", + 0 + ], + [ + "system-ui", + 10 + ] +])],["font-feature-settings", new Map([ + [ + "normal", + 10 + ] +])],["font-optical-sizing", new Map([ + [ + "auto", + 10 + ], + [ + "none", + 10 + ] +])],["font-palette", new Map([ + [ + "dark", + 5 + ], + [ + "light", + 5 + ], + [ + "normal", + 5 + ] +])],["font", new Map([ + [ + "caption", + 10 + ], + [ + "icon", + 10 + ], + [ + "menu", + 10 + ], + [ + "message-box", + 10 + ], + [ + "small-caption", + 10 + ], + [ + "status-bar", + 10 + ] +])],["font-size", new Map([ + [ + "xxx-large", + 10 + ], + [ + "math", + 5 + ] +])],["font-size-adjust", new Map([ + [ + "from-font", + 5 + ], + [ + "none", + 5 + ], + [ + "two-values", + 5 + ] +])],["font-stretch", new Map([ + [ + "percentage", + 10 + ] +])],["font-style", new Map([ + [ + "italic", + 10 + ], + [ + "normal", + 10 + ], + [ + "oblique-angle", + 10 + ] +])],["font-synthesis", new Map([ + [ + "position", + 10 + ], + [ + "small-caps", + 10 + ], + [ + "style", + 10 + ], + [ + "weight", + 10 + ] +])],["font-synthesis-position", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ] +])],["font-synthesis-small-caps", new Map([ + [ + "auto", + 5 + ], + [ + "none", + 5 + ] +])],["font-synthesis-style", new Map([ + [ + "auto", + 5 + ], + [ + "none", + 5 + ] +])],["font-synthesis-weight", new Map([ + [ + "auto", + 5 + ], + [ + "none", + 5 + ] +])],["font-variant", new Map([ + [ + "historical-forms", + 10 + ], + [ + "none", + 10 + ], + [ + "normal", + 10 + ], + [ + "sub", + 10 + ], + [ + "super", + 10 + ] +])],["font-variant-alternates", new Map([ + [ + "annotation", + 5 + ], + [ + "historical-forms", + 5 + ], + [ + "normal", + 5 + ], + [ + "ornaments", + 5 + ], + [ + "styleset", + 5 + ], + [ + "stylistic", + 5 + ], + [ + "swash", + 5 + ] +])],["font-variant-caps", new Map([ + [ + "all-petite-caps", + 10 + ], + [ + "all-small-caps", + 10 + ], + [ + "normal", + 10 + ], + [ + "petite-caps", + 10 + ], + [ + "small-caps", + 10 + ], + [ + "titling-caps", + 10 + ], + [ + "unicase", + 10 + ] +])],["font-variant-east-asian", new Map([ + [ + "full-width", + 10 + ], + [ + "jis04", + 10 + ], + [ + "jis78", + 10 + ], + [ + "jis83", + 10 + ], + [ + "jis90", + 10 + ], + [ + "normal", + 10 + ], + [ + "proportional-width", + 10 + ], + [ + "ruby", + 10 + ], + [ + "simplified", + 10 + ], + [ + "traditional", + 10 + ] +])],["font-variant-emoji", new Map([ + [ + "emoji", + 0 + ], + [ + "normal", + 0 + ], + [ + "text", + 0 + ], + [ + "unicode", + 0 + ] +])],["font-variant-ligatures", new Map([ + [ + "common-ligatures", + 10 + ], + [ + "contextual", + 10 + ], + [ + "discretionary-ligatures", + 10 + ], + [ + "historical-ligatures", + 10 + ], + [ + "no-common-ligatures", + 10 + ], + [ + "no-contextual", + 10 + ], + [ + "no-discretionary-ligatures", + 10 + ], + [ + "no-historical-ligatures", + 10 + ], + [ + "none", + 10 + ], + [ + "normal", + 10 + ] +])],["font-variant-numeric", new Map([ + [ + "diagonal-fractions", + 10 + ], + [ + "lining-nums", + 10 + ], + [ + "normal", + 10 + ], + [ + "oldstyle-nums", + 10 + ], + [ + "ordinal", + 10 + ], + [ + "proportional-nums", + 10 + ], + [ + "slashed-zero", + 10 + ], + [ + "stacked-fractions", + 10 + ], + [ + "tabular-nums", + 10 + ] +])],["font-variant-position", new Map([ + [ + "normal", + 0 + ], + [ + "sub", + 0 + ], + [ + "super", + 0 + ] +])],["font-weight", new Map([ + [ + "bold", + 10 + ], + [ + "bolder", + 10 + ], + [ + "lighter", + 10 + ], + [ + "normal", + 10 + ], + [ + "number", + 10 + ] +])],["forced-color-adjust", new Map([ + [ + "auto", + 5 + ], + [ + "none", + 5 + ], + [ + "preserve-parent-color", + 5 + ] +])],["grid-auto-flow", new Map([ + [ + "column", + 10 + ], + [ + "dense", + 10 + ], + [ + "row", + 10 + ] +])],["grid-template-areas", new Map([ + [ + "none", + 10 + ] +])],["grid-template-columns", new Map([ + [ + "auto", + 10 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "minmax", + 10 + ], + [ + "none", + 10 + ], + [ + "repeat", + 10 + ], + [ + "animation", + 5 + ], + [ + "masonry", + 0 + ], + [ + "subgrid", + 5 + ] +])],["grid-template-rows", new Map([ + [ + "auto", + 10 + ], + [ + "fit-content", + 10 + ], + [ + "max-content", + 10 + ], + [ + "min-content", + 10 + ], + [ + "minmax", + 10 + ], + [ + "none", + 10 + ], + [ + "repeat", + 10 + ], + [ + "animation", + 5 + ], + [ + "masonry", + 0 + ], + [ + "subgrid", + 5 + ] +])],["grid-template", new Map([ + [ + "none", + 10 + ] +])],["hanging-punctuation", new Map([ + [ + "allow-end", + 0 + ], + [ + "first", + 0 + ], + [ + "last", + 0 + ], + [ + "none", + 0 + ] +])],["hyphenate-character", new Map([ + [ + "auto", + 5 + ] +])],["hyphenate-limit-chars", new Map([ + [ + "auto", + 0 + ] +])],["hyphens", new Map([ + [ + "auto", + 5 + ] +])],["image-orientation", new Map([ + [ + "from-image", + 10 + ], + [ + "none", + 10 + ] +])],["rotate", new Map([ + [ + "none", + 5 + ] +])],["scale", new Map([ + [ + "none", + 5 + ] +])],["translate", new Map([ + [ + "none", + 5 + ] +])],["initial-letter", new Map([ + [ + "normal", + 0 + ] +])],["interpolate-size", new Map([ + [ + "allow-keywords", + 0 + ], + [ + "numeric-only", + 0 + ] +])],["direction", new Map([ + [ + "ltr", + 10 + ], + [ + "rtl", + 10 + ] +])],["unicode-bidi", new Map([ + [ + "bidi-override", + 10 + ], + [ + "embed", + 10 + ], + [ + "isolate", + 10 + ], + [ + "isolate-override", + 10 + ], + [ + "normal", + 10 + ], + [ + "plaintext", + 10 + ] +])],["letter-spacing", new Map([ + [ + "normal", + 10 + ] +])],["line-break", new Map([ + [ + "anywhere", + 10 + ], + [ + "auto", + 10 + ], + [ + "loose", + 10 + ], + [ + "normal", + 10 + ], + [ + "strict", + 10 + ] +])],["line-clamp", new Map([ + [ + "none", + 0 + ] +])],["line-height", new Map([ + [ + "normal", + 10 + ] +])],["list-style-image", new Map([ + [ + "none", + 10 + ] +])],["list-style-position", new Map([ + [ + "inside", + 10 + ], + [ + "outside", + 10 + ] +])],["list-style-type", new Map([ + [ + "arabic-indic", + 10 + ], + [ + "armenian", + 10 + ], + [ + "bengali", + 10 + ], + [ + "cambodian", + 10 + ], + [ + "circle", + 10 + ], + [ + "cjk-decimal", + 10 + ], + [ + "cjk-earthly-branch", + 10 + ], + [ + "cjk-heavenly-stem", + 10 + ], + [ + "cjk-ideographic", + 10 + ], + [ + "decimal", + 10 + ], + [ + "decimal-leading-zero", + 10 + ], + [ + "devanagari", + 10 + ], + [ + "disc", + 10 + ], + [ + "disclosure-closed", + 10 + ], + [ + "disclosure-open", + 10 + ], + [ + "ethiopic-numeric", + 10 + ], + [ + "georgian", + 10 + ], + [ + "gujarati", + 10 + ], + [ + "gurmukhi", + 10 + ], + [ + "hebrew", + 10 + ], + [ + "hiragana", + 10 + ], + [ + "hiragana-iroha", + 10 + ], + [ + "japanese-formal", + 10 + ], + [ + "japanese-informal", + 10 + ], + [ + "kannada", + 10 + ], + [ + "katakana", + 10 + ], + [ + "katakana-iroha", + 10 + ], + [ + "khmer", + 10 + ], + [ + "korean-hangul-formal", + 10 + ], + [ + "korean-hanja-formal", + 10 + ], + [ + "korean-hanja-informal", + 10 + ], + [ + "lao", + 10 + ], + [ + "lower-alpha", + 10 + ], + [ + "lower-armenian", + 10 + ], + [ + "lower-greek", + 10 + ], + [ + "lower-latin", + 10 + ], + [ + "lower-roman", + 10 + ], + [ + "malayalam", + 10 + ], + [ + "mongolian", + 10 + ], + [ + "myanmar", + 10 + ], + [ + "none", + 10 + ], + [ + "oriya", + 10 + ], + [ + "persian", + 10 + ], + [ + "simp-chinese-formal", + 10 + ], + [ + "simp-chinese-informal", + 10 + ], + [ + "square", + 10 + ], + [ + "string", + 10 + ], + [ + "symbols", + 10 + ], + [ + "tamil", + 10 + ], + [ + "telugu", + 10 + ], + [ + "thai", + 10 + ], + [ + "tibetan", + 10 + ], + [ + "trad-chinese-formal", + 10 + ], + [ + "trad-chinese-informal", + 10 + ], + [ + "upper-alpha", + 10 + ], + [ + "upper-armenian", + 10 + ], + [ + "upper-latin", + 10 + ], + [ + "upper-roman", + 10 + ] +])],["list-style", new Map([ + [ + "symbols", + 10 + ] +])],["overflow-block", new Map([ + [ + "overlay", + 10 + ] +])],["overflow-inline", new Map([ + [ + "overlay", + 10 + ] +])],["margin-bottom", new Map([ + [ + "auto", + 10 + ] +])],["margin-left", new Map([ + [ + "auto", + 10 + ] +])],["margin-right", new Map([ + [ + "auto", + 10 + ] +])],["margin-top", new Map([ + [ + "auto", + 10 + ] +])],["margin", new Map([ + [ + "auto", + 10 + ] +])],["margin-trim", new Map([ + [ + "block", + 0 + ], + [ + "block-end", + 0 + ], + [ + "block-start", + 0 + ], + [ + "inline", + 0 + ], + [ + "inline-end", + 0 + ], + [ + "inline-start", + 0 + ], + [ + "none", + 0 + ] +])],["mask-type", new Map([ + [ + "alpha", + 10 + ], + [ + "luminance", + 10 + ] +])],["mask-clip", new Map([ + [ + "border", + 5 + ], + [ + "content", + 5 + ], + [ + "padding", + 5 + ], + [ + "text", + 5 + ] +])],["mask-composite", new Map([ + [ + "add", + 5 + ], + [ + "exclude", + 5 + ], + [ + "intersect", + 5 + ], + [ + "subtract", + 5 + ] +])],["mask-mode", new Map([ + [ + "alpha", + 5 + ], + [ + "luminance", + 5 + ], + [ + "match-source", + 5 + ] +])],["mask-origin", new Map([ + [ + "border", + 5 + ], + [ + "content", + 5 + ], + [ + "fill-box", + 5 + ], + [ + "padding", + 5 + ], + [ + "stroke-box", + 5 + ], + [ + "view-box", + 5 + ] +])],["text-transform", new Map([ + [ + "math-auto", + 5 + ], + [ + "capitalize", + 10 + ], + [ + "full-size-kana", + 10 + ], + [ + "full-width", + 10 + ], + [ + "lowercase", + 10 + ], + [ + "none", + 10 + ], + [ + "uppercase", + 10 + ] +])],["mix-blend-mode", new Map([ + [ + "plus-darker", + 10 + ], + [ + "plus-lighter", + 10 + ] +])],["offset-anchor", new Map([ + [ + "auto", + 5 + ] +])],["offset-path", new Map([ + [ + "path", + 5 + ], + [ + "ray", + 5 + ], + [ + "url", + 5 + ] +])],["offset-position", new Map([ + [ + "auto", + 5 + ], + [ + "normal", + 5 + ] +])],["offset-rotate", new Map([ + [ + "auto", + 5 + ], + [ + "reverse", + 5 + ] +])],["column-count", new Map([ + [ + "auto", + 10 + ] +])],["column-width", new Map([ + [ + "auto", + 10 + ] +])],["object-fit", new Map([ + [ + "contain", + 10 + ], + [ + "cover", + 10 + ], + [ + "fill", + 10 + ], + [ + "none", + 10 + ], + [ + "scale-down", + 10 + ] +])],["object-view-box", new Map([ + [ + "none", + 0 + ] +])],["opacity", new Map([ + [ + "percentages", + 10 + ] +])],["outline-style", new Map([ + [ + "auto", + 10 + ], + [ + "dashed", + 10 + ], + [ + "dotted", + 10 + ], + [ + "double", + 10 + ], + [ + "groove", + 10 + ], + [ + "inset", + 10 + ], + [ + "none", + 10 + ], + [ + "outset", + 10 + ], + [ + "ridge", + 10 + ], + [ + "solid", + 10 + ] +])],["overflow-anchor", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ] +])],["overflow-clip-margin", new Map([ + [ + "border-box", + 0 + ], + [ + "content-box", + 0 + ], + [ + "padding-box", + 0 + ] +])],["overflow-x", new Map([ + [ + "auto", + 5 + ], + [ + "clip", + 5 + ], + [ + "hidden", + 5 + ], + [ + "scroll", + 5 + ], + [ + "visible", + 5 + ] +])],["overflow-y", new Map([ + [ + "auto", + 5 + ], + [ + "clip", + 5 + ], + [ + "hidden", + 5 + ], + [ + "scroll", + 5 + ], + [ + "visible", + 5 + ] +])],["overflow", new Map([ + [ + "auto", + 5 + ], + [ + "clip", + 5 + ], + [ + "hidden", + 5 + ], + [ + "scroll", + 5 + ], + [ + "visible", + 5 + ] +])],["overflow-wrap", new Map([ + [ + "anywhere", + 10 + ], + [ + "break-word", + 10 + ], + [ + "normal", + 10 + ] +])],["overlay", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ] +])],["overscroll-behavior-block", new Map([ + [ + "auto", + 5 + ], + [ + "contain", + 5 + ], + [ + "none", + 5 + ] +])],["overscroll-behavior-inline", new Map([ + [ + "auto", + 5 + ], + [ + "contain", + 5 + ], + [ + "none", + 5 + ] +])],["overscroll-behavior-x", new Map([ + [ + "auto", + 5 + ], + [ + "contain", + 5 + ], + [ + "none", + 5 + ] +])],["overscroll-behavior-y", new Map([ + [ + "auto", + 5 + ], + [ + "contain", + 5 + ], + [ + "none", + 5 + ] +])],["overscroll-behavior", new Map([ + [ + "auto", + 5 + ], + [ + "contain", + 5 + ], + [ + "none", + 5 + ] +])],["page-break-after", new Map([ + [ + "always", + 0 + ], + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ], + [ + "left", + 0 + ], + [ + "right", + 0 + ] +])],["page-break-before", new Map([ + [ + "always", + 0 + ], + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ], + [ + "left", + 0 + ], + [ + "right", + 0 + ] +])],["page-break-inside", new Map([ + [ + "auto", + 0 + ], + [ + "avoid", + 0 + ] +])],["print-color-adjust", new Map([ + [ + "economy", + 0 + ], + [ + "exact", + 0 + ] +])],["quotes", new Map([ + [ + "auto", + 10 + ], + [ + "none", + 10 + ] +])],["resize", new Map([ + [ + "block", + 0 + ], + [ + "inline", + 0 + ] +])],["ruby-align", new Map([ + [ + "center", + 0 + ], + [ + "space-around", + 0 + ], + [ + "space-between", + 0 + ], + [ + "start", + 0 + ] +])],["ruby-overhang", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ] +])],["ruby-position", new Map([ + [ + "alternate", + 0 + ], + [ + "inter-character", + 0 + ], + [ + "over", + 0 + ], + [ + "under", + 0 + ] +])],["scroll-behavior", new Map([ + [ + "auto", + 10 + ], + [ + "smooth", + 10 + ] +])],["animation-range-end", new Map([ + [ + "normal", + 0 + ] +])],["animation-range-start", new Map([ + [ + "normal", + 0 + ] +])],["animation-timeline", new Map([ + [ + "scroll", + 0 + ], + [ + "view", + 0 + ] +])],["scroll-timeline-axis", new Map([ + [ + "block", + 0 + ], + [ + "inline", + 0 + ], + [ + "x", + 0 + ], + [ + "y", + 0 + ] +])],["timeline-scope", new Map([ + [ + "all", + 0 + ], + [ + "none", + 0 + ] +])],["view-timeline-axis", new Map([ + [ + "block", + 0 + ], + [ + "inline", + 0 + ], + [ + "x", + 0 + ], + [ + "y", + 0 + ] +])],["view-timeline-inset", new Map([ + [ + "auto", + 0 + ] +])],["scroll-padding-block-end", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding-block-start", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding-block", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding-inline-end", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding-inline-start", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding-inline", new Map([ + [ + "auto", + 10 + ] +])],["scroll-padding", new Map([ + [ + "auto", + 10 + ] +])],["scroll-snap-align", new Map([ + [ + "center", + 10 + ], + [ + "end", + 10 + ], + [ + "none", + 10 + ], + [ + "start", + 10 + ] +])],["scroll-snap-stop", new Map([ + [ + "always", + 10 + ], + [ + "normal", + 10 + ] +])],["scroll-snap-type", new Map([ + [ + "block", + 10 + ], + [ + "both", + 10 + ], + [ + "inline", + 10 + ], + [ + "none", + 10 + ], + [ + "x", + 10 + ], + [ + "y", + 10 + ] +])],["scrollbar-color", new Map([ + [ + "auto", + 0 + ] +])],["scrollbar-gutter", new Map([ + [ + "auto", + 0 + ], + [ + "stable", + 0 + ] +])],["scrollbar-width", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ], + [ + "thin", + 0 + ] +])],["shape-image-threshold", new Map([ + [ + "percentages", + 10 + ] +])],["shape-outside", new Map([ + [ + "circle", + 10 + ], + [ + "gradient", + 10 + ], + [ + "image", + 10 + ], + [ + "inset", + 10 + ], + [ + "none", + 10 + ], + [ + "path", + 10 + ], + [ + "polygon", + 10 + ] +])],["speak-as", new Map([ + [ + "digits", + 0 + ], + [ + "literal-punctuation", + 0 + ], + [ + "no-punctuation", + 0 + ], + [ + "normal", + 0 + ], + [ + "spell-out", + 0 + ] +])],["clip-rule", new Map([ + [ + "evenodd", + 10 + ], + [ + "nonzero", + 10 + ] +])],["color-interpolation", new Map([ + [ + "linearGradient", + 10 + ], + [ + "sRGB", + 10 + ] +])],["fill-rule", new Map([ + [ + "evenodd", + 10 + ], + [ + "nonzero", + 10 + ] +])],["stroke-dasharray", new Map([ + [ + "none", + 10 + ] +])],["stroke-linecap", new Map([ + [ + "butt", + 10 + ], + [ + "round", + 10 + ], + [ + "square", + 10 + ] +])],["stroke-linejoin", new Map([ + [ + "bevel", + 10 + ], + [ + "miter", + 10 + ], + [ + "round", + 10 + ] +])],["text-rendering", new Map([ + [ + "auto", + 10 + ], + [ + "geometricPrecision", + 10 + ] +])],["color-interpolation-filters", new Map([ + [ + "auto", + 10 + ], + [ + "linearRGB", + 10 + ], + [ + "sRGB", + 10 + ] +])],["tab-size", new Map([ + [ + "length", + 10 + ] +])],["border-collapse", new Map([ + [ + "collapse", + 10 + ], + [ + "separate", + 10 + ] +])],["caption-side", new Map([ + [ + "bottom", + 10 + ], + [ + "bottom-outside", + 10 + ], + [ + "top", + 10 + ], + [ + "top-outside", + 10 + ] +])],["text-align", new Map([ + [ + "center", + 10 + ], + [ + "end", + 10 + ], + [ + "justify", + 10 + ], + [ + "left", + 10 + ], + [ + "match-parent", + 10 + ], + [ + "right", + 10 + ], + [ + "start", + 10 + ] +])],["text-align-last", new Map([ + [ + "auto", + 5 + ] +])],["text-box-edge", new Map([ + [ + "auto", + 0 + ] +])],["text-box-trim", new Map([ + [ + "none", + 0 + ], + [ + "trim-both", + 0 + ], + [ + "trim-end", + 0 + ], + [ + "trim-start", + 0 + ] +])],["text-box", new Map([ + [ + "normal", + 0 + ] +])],["text-decoration-line", new Map([ + [ + "grammar-error", + 10 + ], + [ + "line-through", + 10 + ], + [ + "none", + 10 + ], + [ + "overline", + 10 + ], + [ + "spelling-error", + 10 + ], + [ + "underline", + 10 + ] +])],["text-decoration-skip-ink", new Map([ + [ + "all", + 10 + ], + [ + "auto", + 10 + ], + [ + "none", + 10 + ] +])],["text-decoration-skip", new Map([ + [ + "auto", + 10 + ], + [ + "none", + 10 + ] +])],["text-decoration-style", new Map([ + [ + "wavy", + 10 + ] +])],["text-decoration-thickness", new Map([ + [ + "auto", + 10 + ], + [ + "from-font", + 10 + ], + [ + "percentage", + 10 + ] +])],["text-emphasis-position", new Map([ + [ + "auto", + 10 + ], + [ + "left", + 10 + ], + [ + "over", + 10 + ], + [ + "right", + 10 + ], + [ + "under", + 10 + ] +])],["text-emphasis-style", new Map([ + [ + "circle", + 10 + ], + [ + "dot", + 10 + ], + [ + "double-circle", + 10 + ], + [ + "filled", + 10 + ], + [ + "none", + 10 + ], + [ + "sesame", + 10 + ], + [ + "triangle", + 10 + ] +])],["text-indent", new Map([ + [ + "each-line", + 0 + ], + [ + "hanging", + 0 + ] +])],["text-justify", new Map([ + [ + "auto", + 0 + ], + [ + "inter-character", + 0 + ], + [ + "inter-word", + 0 + ], + [ + "none", + 0 + ] +])],["text-orientation", new Map([ + [ + "mixed", + 10 + ], + [ + "sideways", + 10 + ], + [ + "upright", + 10 + ] +])],["text-size-adjust", new Map([ + [ + "auto", + 0 + ], + [ + "none", + 0 + ], + [ + "percentages", + 0 + ] +])],["text-spacing-trim", new Map([ + [ + "normal", + 0 + ], + [ + "space-all", + 0 + ], + [ + "space-first", + 0 + ], + [ + "trim-start", + 0 + ] +])],["text-underline-offset", new Map([ + [ + "auto", + 10 + ], + [ + "percentage", + 10 + ] +])],["text-underline-position", new Map([ + [ + "from-font", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "under", + 10 + ] +])],["text-wrap", new Map([ + [ + "wrap", + 5 + ], + [ + "balance", + 5 + ], + [ + "nowrap", + 5 + ], + [ + "pretty", + 0 + ], + [ + "stable", + 5 + ] +])],["text-wrap-mode", new Map([ + [ + "nowrap", + 5 + ], + [ + "wrap", + 5 + ] +])],["text-wrap-style", new Map([ + [ + "auto", + 0 + ], + [ + "balance", + 0 + ], + [ + "pretty", + 0 + ], + [ + "stable", + 0 + ] +])],["touch-action", new Map([ + [ + "manipulation", + 10 + ], + [ + "none", + 10 + ], + [ + "pan-down", + 10 + ], + [ + "pan-left", + 10 + ], + [ + "pan-right", + 10 + ], + [ + "pan-up", + 10 + ], + [ + "pan-x", + 10 + ], + [ + "pan-y", + 10 + ], + [ + "pinch-zoom", + 10 + ] +])],["transform-box", new Map([ + [ + "border-box", + 5 + ], + [ + "content-box", + 5 + ], + [ + "fill-box", + 5 + ], + [ + "stroke-box", + 5 + ], + [ + "view-box", + 5 + ] +])],["transform-origin", new Map([ + [ + "bottom", + 10 + ], + [ + "center", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "top", + 10 + ] +])],["perspective-origin", new Map([ + [ + "bottom", + 10 + ], + [ + "center", + 10 + ], + [ + "left", + 10 + ], + [ + "right", + 10 + ], + [ + "top", + 10 + ] +])],["perspective", new Map([ + [ + "none", + 10 + ] +])],["transform", new Map([ + [ + "3d", + 10 + ] +])],["transition", new Map([ + [ + "transition-behavior", + 5 + ] +])],["transition-property", new Map([ + [ + "all", + 10 + ], + [ + "none", + 10 + ] +])],["transition-timing-function", new Map([ + [ + "jump", + 10 + ] +])],["user-select", new Map([ + [ + "all", + 0 + ], + [ + "auto", + 0 + ], + [ + "none", + 0 + ], + [ + "text", + 0 + ] +])],["vertical-align", new Map([ + [ + "baseline", + 10 + ], + [ + "bottom", + 10 + ], + [ + "middle", + 10 + ], + [ + "sub", + 10 + ], + [ + "super", + 10 + ], + [ + "text-bottom", + 10 + ], + [ + "text-top", + 10 + ], + [ + "top", + 10 + ] +])],["view-transition-class", new Map([ + [ + "none", + 0 + ] +])],["view-transition-name", new Map([ + [ + "none", + 0 + ] +])],["visibility", new Map([ + [ + "collapse", + 10 + ], + [ + "hidden", + 10 + ], + [ + "visible", + 10 + ] +])],["white-space", new Map([ + [ + "break-spaces", + 10 + ], + [ + "normal", + 10 + ], + [ + "nowrap", + 10 + ], + [ + "pre", + 10 + ], + [ + "pre-line", + 10 + ], + [ + "pre-wrap", + 10 + ] +])],["white-space-collapse", new Map([ + [ + "break-spaces", + 5 + ], + [ + "collapse", + 5 + ], + [ + "preserve", + 5 + ], + [ + "preserve-breaks", + 5 + ], + [ + "preserve-spaces", + 5 + ] +])],["will-change", new Map([ + [ + "auto", + 10 + ], + [ + "contents", + 10 + ], + [ + "scroll-position", + 10 + ] +])],["word-break", new Map([ + [ + "break-all", + 10 + ], + [ + "keep-all", + 10 + ], + [ + "normal", + 10 + ], + [ + "auto-phrase", + 0 + ] +])],["word-spacing", new Map([ + [ + "normal", + 10 + ] +])],["writing-mode", new Map([ + [ + "horizontal-tb", + 10 + ], + [ + "sideways-lr", + 10 + ], + [ + "sideways-rl", + 10 + ], + [ + "vertical-lr", + 10 + ], + [ + "vertical-rl", + 10 + ] +])],["z-index", new Map([ + [ + "auto", + 10 + ] +])]]); diff --git a/src/index.js b/src/index.js index b601722..3d1685b 100644 --- a/src/index.js +++ b/src/index.js @@ -13,6 +13,7 @@ import noEmptyBlocks from "./rules/no-empty-blocks.js"; import noDuplicateImports from "./rules/no-duplicate-imports.js"; import noInvalidProperties from "./rules/no-invalid-properties.js"; import noInvalidAtRules from "./rules/no-invalid-at-rules.js"; +import baseline from "./rules/baseline.js"; //----------------------------------------------------------------------------- // Plugin @@ -31,6 +32,7 @@ const plugin = { "no-duplicate-imports": noDuplicateImports, "no-invalid-at-rules": noInvalidAtRules, "no-invalid-properties": noInvalidProperties, + baseline, }, configs: { recommended: { @@ -40,6 +42,7 @@ const plugin = { "css/no-duplicate-imports": "error", "css/no-invalid-at-rules": "error", "css/no-invalid-properties": "error", + "css/baseline": "error", }), }, }, diff --git a/src/rules/baseline.js b/src/rules/baseline.js new file mode 100644 index 0000000..7d77f62 --- /dev/null +++ b/src/rules/baseline.js @@ -0,0 +1,420 @@ +/** + * @fileoverview Rule to enforce the use of baseline features. + * @author Nicholas C. Zakas + */ + +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import { + BASELINE_HIGH, + BASELINE_LOW, + properties, + propertyValues, + atRules, + types, +} from "../data/baseline-data.js"; + +//----------------------------------------------------------------------------- +// Type Definitions +//----------------------------------------------------------------------------- + +/** @typedef {import("css-tree").AtrulePlain} AtrulePlain */ + +//----------------------------------------------------------------------------- +// Helpers +//----------------------------------------------------------------------------- + +/** + * Represents a property that is supported via @supports. + */ +class SupportedProperty { + /** + * The name of the property. + * @type {string} + */ + name; + + /** + * Supported identifier values. + * @type {Set} + */ + #identifiers = new Set(); + + /** + * Creates a new instance. + * @param {string} name The name of the property. + */ + constructor(name) { + this.name = name; + } + + /** + * Adds an identifier to the list of supported identifiers. + * @param {string} identifier The identifier to add. + * @returns {void} + */ + addIdentifier(identifier) { + this.#identifiers.add(identifier); + } + + /** + * Determines if an identifier is supported. + * @param {string} identifier The identifier to check. + * @returns {boolean} `true` if the identifier is supported, `false` if not. + */ + hasIdentifier(identifier) { + return this.#identifiers.has(identifier); + } + + /** + * Determines if any identifiers are supported. + * @returns {boolean} `true` if any identifiers are supported, `false` if not. + */ + hasIdentifiers() { + return this.#identifiers.size > 0; + } +} + +/** + * Represents an `@supports` rule and everything it enables. + */ +class SupportsRule { + /** + * The properties supported by this rule. + * @type {Map} + */ + #properties = new Map(); + + /** + * Adds a property to the rule. + * @param {string} property The name of the property. + * @returns {void} + */ + addProperty(property) { + this.#properties.set(property, new SupportedProperty(property)); + } + + /** + * Determines if the rule supports a property. + * @param {string} property The name of the property. + * @returns {boolean} `true` if the property is supported, `false` if not. + */ + hasProperty(property) { + return this.#properties.has(property); + } + + /** + * Gets the supported property. + * @param {string} property The name of the property. + * @returns {SupportedProperty} The supported property. + */ + getProperty(property) { + return this.#properties.get(property); + } + + /** + * Determines if the rule supports a property value. + * @param {string} property The name of the property. + * @param {string} identifier The identifier to check. + * @returns {boolean} `true` if the property value is supported, `false` if not. + */ + hasPropertyIdentifier(property, identifier) { + const supportedProperty = this.#properties.get(property); + + if (!supportedProperty) { + return false; + } + + return supportedProperty.hasIdentifier(identifier); + } + + /** + * Determines if the rule supports any property values. + * @param {string} property The name of the property. + * @returns {boolean} `true` if any property values are supported, `false` if not. + */ + hasPropertyIdentifiers(property) { + const supportedProperty = this.#properties.get(property); + + if (!supportedProperty) { + return false; + } + + return supportedProperty.hasIdentifiers(); + } +} + +/** + * Represents a collection of supports rules. + */ +class SupportsRules { + /** + * A collection of supports rules. + * @type {Array} + */ + #rules = []; + + /** + * Adds a rule to the collection. + * @param {SupportsRule} rule The rule to add. + * @returns {void} + */ + push(rule) { + this.#rules.push(rule); + } + + /** + * Removes the last rule from the collection. + * @returns {SupportsRule} The last rule in the collection. + */ + pop() { + return this.#rules.pop(); + } + + /** + * Retrieves the last rule in the collection. + * @returns {SupportsRule} The last rule in the collection. + */ + last() { + return this.#rules.at(-1); + } + + /** + * Determines if any rule supports a property. + * @param {string} property The name of the property. + * @returns {boolean} `true` if any rule supports the property, `false` if not. + */ + hasProperty(property) { + return this.#rules.some(rule => rule.hasProperty(property)); + } + + /** + * Determines if any rule supports a property identifier. + * @param {string} property The name of the property. + * @param {string} identifier The identifier to check. + * @returns {boolean} `true` if any rule supports the property value, `false` if not. + */ + hasPropertyIdentifier(property, identifier) { + return this.#rules.some(rule => + rule.hasPropertyIdentifier(property, identifier), + ); + } + + /** + * Determines if any rule supports any property identifiers. + * @param {string} property The name of the property. + * @returns {boolean} `true` if any rule supports the property values, `false` if not. + */ + hasPropertyIdentifiers(property) { + return this.#rules.some(rule => rule.hasPropertyIdentifiers(property)); + } +} + +//----------------------------------------------------------------------------- +// Rule Definition +//----------------------------------------------------------------------------- + +export default { + meta: { + type: /** @type {const} */ ("problem"), + + docs: { + description: "Enforce the use of baseline features", + recommended: true, + }, + + schema: [ + { + type: "object", + properties: { + available: { + enum: ["widely", "newly"], + }, + }, + additionalProperties: false, + }, + ], + + defaultOptions: [ + { + available: "widely", + }, + ], + + messages: { + notBaselineProperty: + "Property '{{property}}' is not a {{availability}} available baseline feature.", + notBaselinePropertyValue: + "Value '{{value}}' of property '{{property}}' is not a {{availability}} available baseline feature.", + notBaselineAtRule: + "At-rule '@{{atRule}}' is not a {{availability}} available baseline feature.", + notBaselineType: + "Type '{{type}}' is not a {{availability}} available baseline feature.", + }, + }, + + create(context) { + const availability = context.options[0].available; + const baselineLevel = + availability === "widely" ? BASELINE_HIGH : BASELINE_LOW; + const supportsRules = new SupportsRules(); + + return { + "Atrule[name=supports]"() { + supportsRules.push(new SupportsRule()); + }, + + "Atrule[name=supports] SupportsDeclaration > Declaration"(node) { + const supportsRule = supportsRules.last(); + + if (!supportsRule.hasProperty(node.property)) { + supportsRule.addProperty(node.property); + } + + // for now we can only check identifiers + node.value.children.forEach(child => { + if (child.type === "Identifier") { + supportsRule + .getProperty(node.property) + .addIdentifier(child.name); + } + }); + }, + + "Rule > Block > Declaration"(node) { + // ignore unknown properties - no-invalid-properties already catches this + if (!properties.has(node.property)) { + return; + } + + // if the property has been tested in a @supports rule, ignore it + if (supportsRules.hasProperty(node.property)) { + let valueIsValid = false; + + if (supportsRules.hasPropertyIdentifiers(node.property)) { + for (const child of node.value.children) { + if (child.type === "Identifier") { + if ( + supportsRules.hasPropertyIdentifier( + node.property, + child.name, + ) + ) { + valueIsValid = true; + continue; + } + + const propertyValueLevel = propertyValues + .get(node.property) + .get(child.name); + + if (propertyValueLevel < baselineLevel) { + context.report({ + loc: child.loc, + messageId: "notBaselinePropertyValue", + data: { + property: node.property, + value: child.name, + availability, + }, + }); + } + } + } + } + + /* + * When we make it here, that means we've checked all the + * property values we can check. If we can confirm that the + * value is valid, then we can exit early. Otherwise, we + * must continue on to check the baseline status of the + * property itself. + */ + if (valueIsValid) { + return; + } + } + + /* + * If we made it here, that means the property isn't referenced + * in an `@supports` rule, so we need to check it directly. + */ + + const ruleLevel = properties.get(node.property); + + if (ruleLevel < baselineLevel) { + context.report({ + loc: { + start: node.loc.start, + end: { + line: node.loc.start.line, + column: + node.loc.start.column + + node.property.length, + }, + }, + messageId: "notBaselineProperty", + data: { + property: node.property, + availability, + }, + }); + } + }, + + Function(node) { + const type = node.name; + if (types.has(type)) { + const typeLevel = types.get(type); + + if (typeLevel < baselineLevel) { + context.report({ + loc: node.loc, + messageId: "notBaselineType", + data: { + type, + availability, + }, + }); + } + } + }, + + "Atrule[name=supports]:exit"() { + supportsRules.pop(); + }, + + Atrule(node) { + // ignore unknown at-rules - no-invalid-at-rules already catches this + if (!atRules.has(node.name)) { + return; + } + + const ruleLevel = atRules.get(node.name); + + if (ruleLevel < baselineLevel) { + const loc = node.loc; + + context.report({ + loc: { + start: loc.start, + end: { + line: loc.start.line, + + // add 1 to account for the @ symbol + column: loc.start.column + node.name.length + 1, + }, + }, + messageId: "notBaselineAtRule", + data: { + atRule: node.name, + availability, + }, + }); + } + }, + }; + }, +}; diff --git a/tests/rules/baseline.test.js b/tests/rules/baseline.test.js new file mode 100644 index 0000000..9a69c6e --- /dev/null +++ b/tests/rules/baseline.test.js @@ -0,0 +1,250 @@ +/** + * @fileoverview Tests for baseline rule. + * @author Nicholas C. Zakas + */ + +//------------------------------------------------------------------------------ +// Imports +//------------------------------------------------------------------------------ + +import rule from "../../src/rules/baseline.js"; +import css from "../../src/index.js"; +import { RuleTester } from "eslint"; +import dedent from "dedent"; + +//------------------------------------------------------------------------------ +// Tests +//------------------------------------------------------------------------------ + +const ruleTester = new RuleTester({ + plugins: { + css, + }, + language: "css/css", +}); + +ruleTester.run("baseline", rule, { + valid: [ + "a { color: red; }", + "a { color: red; background-color: blue; }", + "a { color: red; transition: none; }", + "body { --custom-property: red; }", + "body { padding: 0; }", + "::before { content: attr(foo); }", + "a { color: red; -moz-transition: bar }", + "@font-face { font-weight: 100 400 }", + "@media (min-width: 800px) { a { color: red; } }", + "@supports (accent-color: auto) { a { accent-color: auto; } }", + "@supports (clip-path: fill-box) { a { clip-path: fill-box; } }", + `@supports (accent-color: auto) and (backdrop-filter: auto) { + a { accent-color: auto; background-filter: auto } + }`, + `@supports (accent-color: auto) { + @supports (backdrop-filter: auto) { + a { accent-color: auto; background-filter: auto } + } + }`, + `@supports (accent-color: auto) { + @supports (accent-color: auto) { + a { accent-color: auto; } + } + a { accent-color: auto; } + }`, + { + code: `@property --foo { + syntax: "*"; + inherits: false; + }`, + options: [{ available: "newly" }], + }, + { + code: "a { backdrop-filter: auto }", + options: [{ available: "newly" }], + }, + ], + invalid: [ + { + code: "a { accent-color: bar; backdrop-filter: auto }", + errors: [ + { + messageId: "notBaselineProperty", + data: { + property: "accent-color", + availability: "widely", + }, + line: 1, + column: 5, + endLine: 1, + endColumn: 17, + }, + { + messageId: "notBaselineProperty", + data: { + property: "backdrop-filter", + availability: "widely", + }, + line: 1, + column: 24, + endLine: 1, + endColumn: 39, + }, + ], + }, + { + code: "a { accent-color: bar; backdrop-filter: auto }", + options: [{ available: "newly" }], + errors: [ + { + messageId: "notBaselineProperty", + data: { + property: "accent-color", + availability: "newly", + }, + line: 1, + column: 5, + endLine: 1, + endColumn: 17, + }, + ], + }, + { + code: `@property --foo { + syntax: "*"; + inherits: false; + } + @media (min-width: 800px) { + a { color: red; } + }`, + options: [{ available: "widely" }], + errors: [ + { + messageId: "notBaselineAtRule", + data: { + atRule: "property", + availability: "widely", + }, + line: 1, + column: 1, + endLine: 1, + endColumn: 10, + }, + ], + }, + { + code: "@container (min-width: 800px) { a { color: red; } }", + errors: [ + { + messageId: "notBaselineAtRule", + data: { + atRule: "container", + availability: "widely", + }, + line: 1, + column: 1, + endLine: 1, + endColumn: 11, + }, + ], + }, + { + code: "@view-transition { from-view: a; to-view: b; }\n@container (min-width: 800px) { a { color: red; } }", + options: [{ available: "newly" }], + errors: [ + { + messageId: "notBaselineAtRule", + data: { + atRule: "view-transition", + availability: "newly", + }, + line: 1, + column: 1, + endLine: 1, + endColumn: 17, + }, + ], + }, + { + code: dedent`@supports (accent-color: auto) { + @supports (backdrop-filter: auto) { + a { accent-color: red; } + } + + a { backdrop-filter: auto; } + }`, + errors: [ + { + messageId: "notBaselineProperty", + data: { + property: "accent-color", + availability: "widely", + }, + line: 3, + column: 7, + endLine: 3, + endColumn: 19, + }, + { + messageId: "notBaselineProperty", + data: { + property: "backdrop-filter", + availability: "widely", + }, + line: 6, + column: 6, + endLine: 6, + endColumn: 21, + }, + ], + }, + { + code: "@supports (clip-path: fill-box) { a { clip-path: stroke-box; } }", + errors: [ + { + messageId: "notBaselinePropertyValue", + data: { + property: "clip-path", + value: "stroke-box", + availability: "widely", + }, + line: 1, + column: 50, + endLine: 1, + endColumn: 60, + }, + ], + }, + { + code: "@supports (accent-color: auto) { a { accent-color: red; } }", + errors: [ + { + messageId: "notBaselineProperty", + data: { + property: "accent-color", + availability: "widely", + }, + line: 1, + column: 38, + endLine: 1, + endColumn: 50, + }, + ], + }, + { + code: "a { width: abs(20% - 100px); }", + errors: [ + { + messageId: "notBaselineType", + data: { + property: "width", + type: "abs", + availability: "widely", + }, + line: 1, + column: 12, + endLine: 1, + endColumn: 28, + }, + ], + }, + ], +}); diff --git a/tools/generate-baseline.js b/tools/generate-baseline.js new file mode 100644 index 0000000..58c8591 --- /dev/null +++ b/tools/generate-baseline.js @@ -0,0 +1,150 @@ +/** + * @fileoverview Extracts CSS features from the web-features package and writes + * them to a file. + * See example output from web-features: https://gist.github.com/nzakas/5bbc9eab6900d1e401208fa7bcf49500 + * @author Nicholas C. Zakas + */ + +//------------------------------------------------------------------------------ +// Imports +//------------------------------------------------------------------------------ + +import { features as webFeatures } from "web-features"; +import fs from "node:fs"; + +//------------------------------------------------------------------------------ +// Helpers +//------------------------------------------------------------------------------ + +const BASELINE_HIGH = 10; +const BASELINE_LOW = 5; +const BASELINE_FALSE = 0; +const baselineIds = new Map([ + ["high", BASELINE_HIGH], + ["low", BASELINE_LOW], + [false, BASELINE_FALSE], +]); + +/** + * Flattens the compat features into an object where the key is the feature + * name and the value is the baseline. + * @param {Object} entry The entry to flatten. + * @returns {Object} The flattened entry. + */ +function flattenCompatFeatures(entry) { + if (!entry.compat_features) { + return {}; + } + + return Object.fromEntries( + entry.compat_features.map(feature => [feature, entry.status.baseline]), + ); +} + +/** + * Extracts CSS features from the raw data. + * @param {Object} features The CSS features to extract. + * @returns {Object} The extracted CSS features. + */ +function extractCSSFeatures(features) { + const cssPropertyPattern = /^css\.properties\.(?[a-zA-Z$\d-]+)$/u; + const cssPropertyValuePattern = + /^css\.properties\.(?[a-zA-Z$\d-]+)\.(?[a-zA-Z$\d-]+)$/u; + const cssAtRulePattern = /^css\.at-rules\.(?[a-zA-Z$\d-]+)$/u; + const cssTypePattern = /^css\.types\.(?[a-zA-Z$\d-]+)$/u; + const cssSelectorPattern = /^css\.selectors\.(?[a-zA-Z$\d-]+)$/u; + + const properties = {}; + const propertyValues = {}; + const atRules = {}; + const types = {}; + const selectors = {}; + + for (const [key, baseline] of Object.entries(features)) { + let match; + + // property names + if ((match = cssPropertyPattern.exec(key)) !== null) { + properties[match.groups.property] = baselineIds.get(baseline); + continue; + } + + // property values + if ((match = cssPropertyValuePattern.exec(key)) !== null) { + if (!propertyValues[match.groups.property]) { + propertyValues[match.groups.property] = {}; + } + propertyValues[match.groups.property][match.groups.value] = + baselineIds.get(baseline); + continue; + } + + // at-rules + if ((match = cssAtRulePattern.exec(key)) !== null) { + atRules[match.groups.atRule] = baselineIds.get(baseline); + continue; + } + + // types + if ((match = cssTypePattern.exec(key)) !== null) { + types[match.groups.type] = baselineIds.get(baseline); + continue; + } + + // selectors + if ((match = cssSelectorPattern.exec(key)) !== null) { + selectors[match.groups.selector] = baselineIds.get(baseline); + continue; + } + } + + return { + properties, + propertyValues, + atRules, + types, + selectors, + }; +} + +//------------------------------------------------------------------------------ +// Main +//------------------------------------------------------------------------------ + +// create one object with all features then filter just on the css ones +const allFeatures = Object.values(webFeatures).reduce( + (acc, entry) => Object.assign(acc, flattenCompatFeatures(entry)), + {}, +); +const cssFeatures = extractCSSFeatures( + Object.fromEntries( + Object.entries(allFeatures).filter(([key]) => key.startsWith("css.")), + ), +); +const featuresPath = "./src/data/baseline-data.js"; + +// export each group separately as a Set, such as highProperties, lowProperties, etc. +const code = `/** + * @fileoverview CSS features extracted from the web-features package. + * @author tools/generate-baseline.js + * + * THIS FILE IS AUTOGENERATED. DO NOT MODIFY DIRECTLY. + */ + +export const BASELINE_HIGH = ${BASELINE_HIGH}; +export const BASELINE_LOW = ${BASELINE_LOW}; +export const BASELINE_FALSE = ${BASELINE_FALSE}; + +export const properties = new Map(${JSON.stringify(Object.entries(cssFeatures.properties), null, "\t")}); +export const atRules = new Map(${JSON.stringify(Object.entries(cssFeatures.atRules), null, "\t")}); +export const types = new Map(${JSON.stringify(Object.entries(cssFeatures.types), null, "\t")}); +export const selectors = new Map(${JSON.stringify(Object.entries(cssFeatures.selectors), null, "\t")}); +export const propertyValues = new Map([${Object.entries( + cssFeatures.propertyValues, +).map( + ([key, value]) => + `["${key}", new Map(${JSON.stringify(Object.entries(value), null, "\t")})]`, +)}]); +`; + +fs.writeFileSync(featuresPath, code);