From 620b6dcb56a677fe4e7b473f65db56d866b4da79 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Fri, 6 Dec 2024 15:06:18 -0500 Subject: [PATCH 1/9] feat: baseline rule fixes #26 --- README.md | 15 +- docs/rules/baseline.md | 39 ++ package.json | 9 +- src/data/README.md | 9 + src/data/baseline-data.js | 724 +++++++++++++++++++++++++++++++++++ src/index.js | 3 + src/rules/baseline.js | 144 +++++++ tests/rules/baseline.test.js | 181 +++++++++ tools/generate-baseline.js | 190 +++++++++ 9 files changed, 1304 insertions(+), 10 deletions(-) create mode 100644 docs/rules/baseline.md create mode 100644 src/data/README.md create mode 100644 src/data/baseline-data.js create mode 100644 src/rules/baseline.js create mode 100644 tests/rules/baseline.test.js create mode 100644 tools/generate-baseline.js diff --git a/README.md b/README.md index f6566be..8a7e8e2 100644 --- a/README.md +++ b/README.md @@ -55,14 +55,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 | **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose. diff --git a/docs/rules/baseline.md b/docs/rules/baseline.md new file mode 100644 index 0000000..42d16d7 --- /dev/null +++ b/docs/rules/baseline.md @@ -0,0 +1,39 @@ +# 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 a CSS property or at-rule that isn't widely available or otherwise isn't enclosed in a `@supports` block. 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; +} + +/* valid - @supports indicates you're choosing a limited availability property */ +@supports (accent-color: auto) { + a { + accent-color: red; + } +} +``` + +## 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..bc68f87 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", @@ -48,9 +51,10 @@ "scripts": { "build:dedupe-types": "node tools/dedupe-types.js dist/cjs/index.cjs dist/esm/index.js", "build:cts": "node -e \"fs.copyFileSync('dist/esm/index.d.ts', 'dist/cjs/index.d.cts')\"", - "build": "rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts", + "build": "npm run build:baseline && 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..473120d --- /dev/null +++ b/src/data/README.md @@ -0,0 +1,9 @@ +# Autogenerated Data + +The files in this directory are auto-generated and should not be modified manually. + +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..711fc67 --- /dev/null +++ b/src/data/baseline-data.js @@ -0,0 +1,724 @@ +/** + * @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([ + ["align-self", 10], + ["justify-self", 10], + ["place-self", 10], + ["position", 10], + ["accent-color", 0], + ["align-content", 10], + ["alignment-baseline", 0], + ["all", 10], + ["content", 10], + ["align-items", 10], + ["anchor-name", 0], + ["anchor-scope", 0], + ["block-size", 10], + ["bottom", 10], + ["height", 10], + ["inline-size", 10], + ["inset-block-end", 10], + ["inset-block-start", 10], + ["inset-block", 10], + ["inset-inline-end", 10], + ["inset-inline-start", 10], + ["inset-inline", 10], + ["inset", 10], + ["justify-items", 10], + ["left", 10], + ["max-block-size", 10], + ["max-height", 10], + ["max-inline-size", 10], + ["max-width", 10], + ["min-block-size", 10], + ["min-height", 10], + ["min-inline-size", 10], + ["min-width", 10], + ["place-items", 10], + ["position-anchor", 0], + ["position-area", 0], + ["position-try", 0], + ["position-try-fallbacks", 0], + ["position-try-order", 0], + ["position-visibility", 0], + ["right", 10], + ["top", 10], + ["width", 10], + ["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], + ["break-after", 0], + ["break-after.multicol_context", 0], + ["break-before", 0], + ["break-before.multicol_context", 0], + ["break-inside", 0], + ["break-inside.multicol_context", 0], + ["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-visibility", 5], + ["counter-reset", 10], + ["counter-set", 5], + ["counter-increment", 10], + ["image-rendering", 10], + ["cursor", 0], + ["text-overflow", 10], + ["custom-property", 10], + ["display", 10], + ["display.none", 10], + ["display.contents", 0], + ["display.list-item", 10], + ["dominant-baseline", 10], + ["field-sizing", 0], + ["filter", 10], + ["align-content.flex_context", 10], + ["align-items.flex_context", 10], + ["align-self.flex_context", 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-content.flex_context", 10], + ["order", 10], + ["place-content", 10], + ["column-gap", 10], + ["gap", 10], + ["row-gap", 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], + ["align-items.grid_context", 10], + ["gap.grid_context", 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], + ["hanging-punctuation", 0], + ["hyphenate-character", 5], + ["hyphenate-limit-chars", 0], + ["hyphens", 5], + ["image-orientation", 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], + ["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], + ["margin-block", 10], + ["margin-block-end", 10], + ["margin-block-start", 10], + ["margin-inline", 10], + ["margin-inline-end", 10], + ["margin-inline-start", 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], + ["text-transform", 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.multicol_context", 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.paged_context", 0], + ["break-before.paged_context", 0], + ["break-inside.paged_context", 0], + ["page-break-after", 0], + ["page-break-before", 0], + ["page-break-inside", 0], + ["page", 0], + ["paint-order", 0], + ["pointer-events", 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], + ["custom-property.env", 10], + ["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], + ["transform-origin", 10], + ["vector-effect", 10], + ["word-spacing", 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-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-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], + ["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], + ["writing-mode", 10], + ["view-transition-class", 0], + ["view-transition-name", 0], + ["visibility", 10], + ["white-space", 10], + ["white-space-collapse", 5], + ["orphans", 0], + ["widows", 0], + ["will-change", 10], + ["word-break", 10], + ["z-index", 10], + ["zoom", 5], +]); +export const atRules = new Map([ + ["position-try", 0], + ["keyframes", 10], + ["import", 10], + ["layer", 10], + ["charset", 10], + ["media", 10], + ["font-face", 10], + ["container", 5], + ["counter-style", 5], + ["view-transition", 0], + ["media.display-mode", 0], + ["font-face.src", 10], + ["font-palette-values", 5], + ["font-feature-values", 5], + ["namespace", 10], + ["page", 0], + ["page.size", 0], + ["media.prefers-color-scheme", 10], + ["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], + ["attr.type-or-unit", 0], + ["blend-mode", 10], + ["line-style", 10], + ["calc", 10], + ["calc-constant", 5], + ["calc-size", 0], + ["length", 10], + ["global_keywords", 10], + ["color", 10], + ["color.color", 5], + ["gradient", 10], + ["gradient.conic-gradient", 10], + ["string", 10], + ["counter", 10], + ["counters", 10], + ["image", 10], + ["easing-function", 10], + ["exp", 5], + ["hypot", 5], + ["log", 5], + ["pow", 5], + ["sqrt", 5], + ["filter-function", 10], + ["url", 10], + ["gradient.linear-gradient", 10], + ["gradient.radial-gradient", 10], + ["gradient.repeating-conic-gradient", 5], + ["gradient.repeating-linear-gradient", 10], + ["gradient.repeating-radial-gradient", 10], + ["flex", 10], + ["color.hsl", 10], + ["color.hwb", 10], + ["color.lab", 5], + ["color.lch", 5], + ["ratio", 10], + ["clamp", 10], + ["max", 10], + ["min", 10], + ["ray", 5], + ["color.named-color", 10], + ["color.oklab", 5], + ["color.oklch", 5], + ["number", 10], + ["overflow", 5], + ["image.paint", 0], + ["basic-shape", 10], + ["basic-shape.path", 0], + ["color.rgb", 10], + ["resolution", 5], + ["color.rgb_hexadecimal_notation", 10], + ["mod", 5], + ["rem", 5], + ["round", 5], + ["easing-function.steps", 10], + ["color.system-color", 10], + ["angle", 10], + ["angle-percentage", 10], + ["position", 10], + ["transform-function", 10], + ["transform-function.perspective", 10], + ["acos", 5], + ["asin", 5], + ["atan", 5], + ["atan2", 5], + ["cos", 5], + ["sin", 5], + ["tan", 5], + ["dimension", 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], + ["attribute", 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], + ["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], +]); 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..e01ea2d --- /dev/null +++ b/src/rules/baseline.js @@ -0,0 +1,144 @@ +/** + * @fileoverview Rule to enforce the use of baseline features. + * @author Nicholas C. Zakas + */ + +//----------------------------------------------------------------------------- +// Imports +//----------------------------------------------------------------------------- + +import { + BASELINE_HIGH, + BASELINE_LOW, + properties, + atRules, +} from "../data/baseline-data.js"; + +//----------------------------------------------------------------------------- +// 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.", + notBaselineAtRule: + "At-rule '@{{atRule}}' is not a {{availability}} available baseline feature.", + }, + }, + + create(context) { + const availability = context.options[0].available; + const baselineLevel = + availability === "widely" ? BASELINE_HIGH : BASELINE_LOW; + const atSupportedProperties = new Set(); + + return { + "Atrule[name=supports] SupportsDeclaration > Declaration"(node) { + atSupportedProperties.add(node.property); + }, + + "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 (atSupportedProperties.has(node.property)) { + return; + } + + 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, + }, + }); + } + }, + + "Atrule[name=supports]:exit"(node) { + // remove all properties tested in this @supports rule + node.prelude.children.forEach(condition => { + condition.children.forEach(child => { + if (child.type === "SupportsDeclaration") { + atSupportedProperties.delete( + child.declaration.property, + ); + } + }); + }); + }, + + 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..96c83e7 --- /dev/null +++ b/tests/rules/baseline.test.js @@ -0,0 +1,181 @@ +/** + * @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; }", + "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: red; } }", + `@supports (accent-color: auto) and (backdrop-filter: auto) { + a { accent-color: red; background-filter: auto } + }`, + `@supports (accent-color: auto) { + @supports (backdrop-filter: auto) { + a { accent-color: red; background-filter: 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: "backdrop-filter", + availability: "widely", + }, + line: 6, + column: 9, + endLine: 6, + endColumn: 24, + }, + ], + }, + ], +}); diff --git a/tools/generate-baseline.js b/tools/generate-baseline.js new file mode 100644 index 0000000..0f27fde --- /dev/null +++ b/tools/generate-baseline.js @@ -0,0 +1,190 @@ +/** + * @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 } 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], +]); + +/** + * Filters out non-CSS features and minimizes the data. + * @param {[string, Object]} entry The entry to filter. + * @returns {boolean} True if the entry is a CSS feature, false otherwise. + */ +function filterCSSFeatures([, value]) { + return value.compat_features?.some(feature => feature.startsWith("css.")); +} + +/** + * Minimizes the data for a CSS feature. + * @param {[string, Object]} entry The entry to minimize. + * @returns {[string, Object]} The minimized entry. + */ +function minimizeData([key, value]) { + return [ + key, + { + baseline: value.status.baseline, + properties: [ + ...new Set( + value.compat_features + .filter(feature => + feature.startsWith("css.properties."), + ) + .map(feature => + feature + .replace("css.properties.", "") + .replace(/\.[\w\d-]+$/u, ""), + ), + ), + ], + atRules: [ + ...new Set( + value.compat_features + .filter(feature => feature.startsWith("css.at-rules.")) + .map(feature => + feature + .replace("css.at-rules.", "") + .replace(/\.[\w\d-]+$/u, ""), + ), + ), + ], + types: [ + ...new Set( + value.compat_features + .filter(feature => feature.startsWith("css.types.")) + .map(feature => + feature + .replace("css.types.", "") + .replace(/\.[\w\d-]+$/u, ""), + ), + ), + ], + selectors: [ + ...new Set( + value.compat_features + .filter(feature => feature.startsWith("css.selectors.")) + .map(feature => + feature + .replace("css.selectors.", "") + .replace(/\.[\w\d-]+$/u, ""), + ), + ), + ], + }, + ]; +} + +/** + * Groups CSS features by baseline. + * @param {Array<[string, Object]>} entries The entries to group. + * @returns {Object} The grouped CSS features. + */ +function groupByBaseline(entries) { + const allFeatures = { + properties: {}, + atRules: {}, + types: {}, + selectors: {}, + }; + + /* + * We end up with duplicates due to the naive way we are calculating + * which values to include. So we need to remove duplicates and update + * each to the highest possible baseline value. + */ + + for (const [, value] of entries) { + value.properties.forEach(property => { + if ( + allFeatures.properties[property] === undefined || + allFeatures.properties[property] < + baselineIds.get(value.baseline) + ) { + allFeatures.properties[property] = baselineIds.get( + value.baseline, + ); + } + }); + + value.atRules.forEach(atRule => { + if ( + allFeatures.atRules[atRule] === undefined || + allFeatures.atRules[atRule] < baselineIds.get(value.baseline) + ) { + allFeatures.atRules[atRule] = baselineIds.get(value.baseline); + } + }); + + value.types.forEach(type => { + if ( + allFeatures.types[type] === undefined || + allFeatures.types[type] < baselineIds.get(value.baseline) + ) { + allFeatures.types[type] = baselineIds.get(value.baseline); + } + }); + + value.selectors.forEach(selector => { + if ( + allFeatures.selectors[selector] === undefined || + allFeatures.selectors[selector] < + baselineIds.get(value.baseline) + ) { + allFeatures.selectors[selector] = baselineIds.get( + value.baseline, + ); + } + }); + } + + return allFeatures; +} + +//------------------------------------------------------------------------------ +// Main +//------------------------------------------------------------------------------ + +const featuresPath = "./src/data/baseline-data.js"; +const cssFeatures = groupByBaseline( + Object.entries(features).filter(filterCSSFeatures).map(minimizeData), +); + +// 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")}); +`; + +fs.writeFileSync(featuresPath, code); From 4b232a967731415d6878a3dd21d98ea166a4ee96 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 12 Dec 2024 12:44:43 -0500 Subject: [PATCH 2/9] Add rule options to docs --- docs/rules/baseline.md | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/docs/rules/baseline.md b/docs/rules/baseline.md index 42d16d7..e991470 100644 --- a/docs/rules/baseline.md +++ b/docs/rules/baseline.md @@ -34,6 +34,12 @@ a { } ``` +### 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. From 11f769165655cb6940115beb60868249e1bd3063 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 12 Dec 2024 12:45:13 -0500 Subject: [PATCH 3/9] Fix README format --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8a7e8e2..b3a3f68 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,15 @@ export default [ -| **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 | + +| **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 | + **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose. From 48019d4416d8781f90b5fe87d2fc4e0f10e88113 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 12 Dec 2024 12:47:17 -0500 Subject: [PATCH 4/9] Omit data file from prettier check --- .prettierignore | 1 + 1 file changed, 1 insertion(+) 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 From 3249949057b2945c5e1c013d7ce2eb510aef63d8 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Thu, 12 Dec 2024 17:03:42 -0500 Subject: [PATCH 5/9] Don't rebuild baseline on every build --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bc68f87..be26e90 100644 --- a/package.json +++ b/package.json @@ -51,7 +51,7 @@ "scripts": { "build:dedupe-types": "node tools/dedupe-types.js dist/cjs/index.cjs dist/esm/index.js", "build:cts": "node -e \"fs.copyFileSync('dist/esm/index.d.ts', 'dist/cjs/index.d.cts')\"", - "build": "npm run build:baseline && rollup -c && npm run build:dedupe-types && tsc -p tsconfig.esm.json && npm run build:cts", + "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", From 380e66b21dd130951a2ec34f16f6d9178182dc68 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Fri, 13 Dec 2024 16:05:40 -0500 Subject: [PATCH 6/9] Update to check some property values --- README.md | 16 +- docs/rules/baseline.md | 17 +- src/data/README.md | 12 +- src/data/baseline-data.js | 7624 ++++++++++++++++++++++++++++++---- src/data/csstree-data.js | 60 + src/rules/baseline.js | 48 +- tests/rules/baseline.test.js | 51 +- tools/generate-baseline.js | 214 +- 8 files changed, 7190 insertions(+), 852 deletions(-) create mode 100644 src/data/csstree-data.js diff --git a/README.md b/README.md index b3a3f68..8a7e8e2 100644 --- a/README.md +++ b/README.md @@ -55,15 +55,13 @@ export default [ - -| **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 | - +| **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 | **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose. diff --git a/docs/rules/baseline.md b/docs/rules/baseline.md index e991470..1b4e05f 100644 --- a/docs/rules/baseline.md +++ b/docs/rules/baseline.md @@ -16,7 +16,13 @@ Generally speaking, it's preferable to stick to widely available features to ens ## Rule Details -This rule warns when it finds a CSS property or at-rule that isn't widely available or otherwise isn't enclosed in a `@supports` block. The data is provided via the [web-features](https://npmjs.com/package/web-features) package. +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). + +The data is provided via the [web-features](https://npmjs.com/package/web-features) package. Here are some examples: @@ -26,12 +32,19 @@ a { accent-color: red; } -/* valid - @supports indicates you're choosing a limited availability property */ +/* 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 diff --git a/src/data/README.md b/src/data/README.md index 473120d..fa8f271 100644 --- a/src/data/README.md +++ b/src/data/README.md @@ -1,9 +1,17 @@ -# Autogenerated Data +# Data -The files in this directory are auto-generated and should not be modified manually. +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 ``` + +## csstree-data.js (manual) + +Contains data that helps to work with CSSTree. diff --git a/src/data/baseline-data.js b/src/data/baseline-data.js index 711fc67..520cc95 100644 --- a/src/data/baseline-data.js +++ b/src/data/baseline-data.js @@ -1,7 +1,7 @@ /** * @fileoverview CSS features extracted from the web-features package. * @author tools/generate-baseline.js - * + * * THIS FILE IS AUTOGENERATED. DO NOT MODIFY DIRECTLY. */ @@ -10,715 +10,6927 @@ export const BASELINE_LOW = 5; export const BASELINE_FALSE = 0; export const properties = new Map([ - ["align-self", 10], - ["justify-self", 10], - ["place-self", 10], - ["position", 10], - ["accent-color", 0], - ["align-content", 10], - ["alignment-baseline", 0], - ["all", 10], - ["content", 10], - ["align-items", 10], - ["anchor-name", 0], - ["anchor-scope", 0], - ["block-size", 10], - ["bottom", 10], - ["height", 10], - ["inline-size", 10], - ["inset-block-end", 10], - ["inset-block-start", 10], - ["inset-block", 10], - ["inset-inline-end", 10], - ["inset-inline-start", 10], - ["inset-inline", 10], - ["inset", 10], - ["justify-items", 10], - ["left", 10], - ["max-block-size", 10], - ["max-height", 10], - ["max-inline-size", 10], - ["max-width", 10], - ["min-block-size", 10], - ["min-height", 10], - ["min-inline-size", 10], - ["min-width", 10], - ["place-items", 10], - ["position-anchor", 0], - ["position-area", 0], - ["position-try", 0], - ["position-try-fallbacks", 0], - ["position-try-order", 0], - ["position-visibility", 0], - ["right", 10], - ["top", 10], - ["width", 10], - ["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], - ["break-after", 0], - ["break-after.multicol_context", 0], - ["break-before", 0], - ["break-before.multicol_context", 0], - ["break-inside", 0], - ["break-inside.multicol_context", 0], - ["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-visibility", 5], - ["counter-reset", 10], - ["counter-set", 5], - ["counter-increment", 10], - ["image-rendering", 10], - ["cursor", 0], - ["text-overflow", 10], - ["custom-property", 10], - ["display", 10], - ["display.none", 10], - ["display.contents", 0], - ["display.list-item", 10], - ["dominant-baseline", 10], - ["field-sizing", 0], - ["filter", 10], - ["align-content.flex_context", 10], - ["align-items.flex_context", 10], - ["align-self.flex_context", 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-content.flex_context", 10], - ["order", 10], - ["place-content", 10], - ["column-gap", 10], - ["gap", 10], - ["row-gap", 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], - ["align-items.grid_context", 10], - ["gap.grid_context", 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], - ["hanging-punctuation", 0], - ["hyphenate-character", 5], - ["hyphenate-limit-chars", 0], - ["hyphens", 5], - ["image-orientation", 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], - ["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], - ["margin-block", 10], - ["margin-block-end", 10], - ["margin-block-start", 10], - ["margin-inline", 10], - ["margin-inline-end", 10], - ["margin-inline-start", 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], - ["text-transform", 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.multicol_context", 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.paged_context", 0], - ["break-before.paged_context", 0], - ["break-inside.paged_context", 0], - ["page-break-after", 0], - ["page-break-before", 0], - ["page-break-inside", 0], - ["page", 0], - ["paint-order", 0], - ["pointer-events", 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], - ["custom-property.env", 10], - ["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], - ["transform-origin", 10], - ["vector-effect", 10], - ["word-spacing", 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-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-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], - ["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], - ["writing-mode", 10], - ["view-transition-class", 0], - ["view-transition-name", 0], - ["visibility", 10], - ["white-space", 10], - ["white-space-collapse", 5], - ["orphans", 0], - ["widows", 0], - ["will-change", 10], - ["word-break", 10], - ["z-index", 10], - ["zoom", 5], + [ + "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], - ["import", 10], - ["layer", 10], - ["charset", 10], - ["media", 10], - ["font-face", 10], - ["container", 5], - ["counter-style", 5], - ["view-transition", 0], - ["media.display-mode", 0], - ["font-face.src", 10], - ["font-palette-values", 5], - ["font-feature-values", 5], - ["namespace", 10], - ["page", 0], - ["page.size", 0], - ["media.prefers-color-scheme", 10], - ["property", 5], - ["scope", 0], - ["starting-style", 0], - ["supports", 10], + [ + "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], - ["attr.type-or-unit", 0], - ["blend-mode", 10], - ["line-style", 10], - ["calc", 10], - ["calc-constant", 5], - ["calc-size", 0], - ["length", 10], - ["global_keywords", 10], - ["color", 10], - ["color.color", 5], - ["gradient", 10], - ["gradient.conic-gradient", 10], - ["string", 10], - ["counter", 10], - ["counters", 10], - ["image", 10], - ["easing-function", 10], - ["exp", 5], - ["hypot", 5], - ["log", 5], - ["pow", 5], - ["sqrt", 5], - ["filter-function", 10], - ["url", 10], - ["gradient.linear-gradient", 10], - ["gradient.radial-gradient", 10], - ["gradient.repeating-conic-gradient", 5], - ["gradient.repeating-linear-gradient", 10], - ["gradient.repeating-radial-gradient", 10], - ["flex", 10], - ["color.hsl", 10], - ["color.hwb", 10], - ["color.lab", 5], - ["color.lch", 5], - ["ratio", 10], - ["clamp", 10], - ["max", 10], - ["min", 10], - ["ray", 5], - ["color.named-color", 10], - ["color.oklab", 5], - ["color.oklch", 5], - ["number", 10], - ["overflow", 5], - ["image.paint", 0], - ["basic-shape", 10], - ["basic-shape.path", 0], - ["color.rgb", 10], - ["resolution", 5], - ["color.rgb_hexadecimal_notation", 10], - ["mod", 5], - ["rem", 5], - ["round", 5], - ["easing-function.steps", 10], - ["color.system-color", 10], - ["angle", 10], - ["angle-percentage", 10], - ["position", 10], - ["transform-function", 10], - ["transform-function.perspective", 10], - ["acos", 5], - ["asin", 5], - ["atan", 5], - ["atan2", 5], - ["cos", 5], - ["sin", 5], - ["tan", 5], - ["dimension", 10], - ["length-percentage", 10], - ["percentage", 10], - ["integer", 10], + [ + "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], - ["attribute", 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], - ["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], + [ + "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/data/csstree-data.js b/src/data/csstree-data.js new file mode 100644 index 0000000..340cee9 --- /dev/null +++ b/src/data/csstree-data.js @@ -0,0 +1,60 @@ +/** + * @fileoverview Data to help work with CSSTree. + * @author Nicholas C. Zakas + */ + +/** + * Map of CSS properties to the nodes representing those types in CSSTree. + */ +export const typeNodes = new Map([ + ["acos", ["Function"]], + ["angle-percentage", ["Dimension", "Percentage"]], + ["angle", ["Dimension"]], + ["asin", ["Function"]], + ["atan", ["Function"]], + ["atan2", ["Function"]], + ["attr", ["Function"]], + ["basic-shape", ["Function"]], + ["blend-mode", ["Function"]], + ["calc-constant", ["Identifier"]], + ["calc", ["Function"]], + ["clamp", ["Function"]], + ["color", ["Hash", "Function", "Identifier"]], + ["cos", "Function"], + ["counter", ["Function"]], + ["counters", ["Function"]], + ["dimension", ["Dimension"]], + ["easing-function", ["Function"]], + ["exp", ["Function"]], + ["filter-function", ["Function"]], + ["flex", "Identifier"], + ["gradient", ["Function"]], + ["hypot", ["Function"]], + ["image", ["Function"]], + ["image", ["Image"]], + ["integer", ["Number"]], + ["length-percentage", ["Length", "Percentage"]], + ["length", ["Dimension"]], + ["line-style", ["Identifier"]], + ["log", ["Function"]], + ["max", ["Function"]], + ["min", ["Function"]], + ["mod", ["Function"]], + ["number", ["Number"]], + ["overflow", ["Overflow"]], + ["percentage", ["Percentage"]], + ["position", ["Position"]], + ["pow", ["Pow"]], + ["ratio", ["Ratio"]], + ["ray", ["Ray"]], + ["rem", ["Rem"]], + ["resolution", ["Resolution"]], + ["round", ["Function"]], + ["sin", ["Function"]], + ["sqrt", ["Function"]], + ["string", ["String"]], + ["tan", ["Function"]], + ["time", ["Dimension"]], + ["transform-function", ["Function"]], + ["url", ["Url"]], +]); diff --git a/src/rules/baseline.js b/src/rules/baseline.js index e01ea2d..05c4d0b 100644 --- a/src/rules/baseline.js +++ b/src/rules/baseline.js @@ -11,6 +11,7 @@ import { BASELINE_HIGH, BASELINE_LOW, properties, + propertyValues, atRules, } from "../data/baseline-data.js"; @@ -48,6 +49,8 @@ export default { 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.", }, @@ -57,11 +60,20 @@ export default { const availability = context.options[0].available; const baselineLevel = availability === "widely" ? BASELINE_HIGH : BASELINE_LOW; - const atSupportedProperties = new Set(); + const atSupportedProperties = new Map(); return { "Atrule[name=supports] SupportsDeclaration > Declaration"(node) { - atSupportedProperties.add(node.property); + if (!atSupportedProperties.has(node.property)) { + atSupportedProperties.set(node.property, new Set()); + } + + // for now we can only check identifiers + if (node.value.children[0].type === "Identifier") { + atSupportedProperties + .get(node.property) + .add(node.value.children[0].name); + } }, "Rule > Block > Declaration"(node) { @@ -72,7 +84,37 @@ export default { // if the property has been tested in a @supports rule, ignore it if (atSupportedProperties.has(node.property)) { - return; + const firstChild = node.value.children[0]; + + // make sure the identifier is allowed + if (firstChild.type === "Identifier") { + if ( + atSupportedProperties + .get(node.property) + .has(firstChild.name) + ) { + return; + } + + const propertyValueLevel = propertyValues + .get(node.property) + .get(firstChild.name); + + if (propertyValueLevel < baselineLevel) { + context.report({ + loc: firstChild.loc, + messageId: "notBaselinePropertyValue", + data: { + property: node.property, + value: firstChild.name, + availability, + }, + }); + } + } else { + // we can't check the value so we'll give the user the benefit of the doubt + return; + } } const ruleLevel = properties.get(node.property); diff --git a/tests/rules/baseline.test.js b/tests/rules/baseline.test.js index 96c83e7..3c7aa24 100644 --- a/tests/rules/baseline.test.js +++ b/tests/rules/baseline.test.js @@ -33,13 +33,14 @@ ruleTester.run("baseline", rule, { "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: 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: red; background-filter: auto } + a { accent-color: auto; background-filter: auto } }`, `@supports (accent-color: auto) { @supports (backdrop-filter: auto) { - a { accent-color: red; background-filter: auto } + a { accent-color: auto; background-filter: auto } } }`, { @@ -164,6 +165,17 @@ ruleTester.run("baseline", rule, { a { backdrop-filter: auto; } }`, errors: [ + { + messageId: "notBaselineProperty", + data: { + property: "accent-color", + availability: "widely", + }, + line: 3, + column: 13, + endLine: 3, + endColumn: 25, + }, { messageId: "notBaselineProperty", data: { @@ -177,5 +189,38 @@ ruleTester.run("baseline", rule, { }, ], }, + { + 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, + }, + ], + }, ], }); diff --git a/tools/generate-baseline.js b/tools/generate-baseline.js index 0f27fde..58c8591 100644 --- a/tools/generate-baseline.js +++ b/tools/generate-baseline.js @@ -9,7 +9,7 @@ // Imports //------------------------------------------------------------------------------ -import { features } from "web-features"; +import { features as webFeatures } from "web-features"; import fs from "node:fs"; //------------------------------------------------------------------------------ @@ -26,148 +26,102 @@ const baselineIds = new Map([ ]); /** - * Filters out non-CSS features and minimizes the data. - * @param {[string, Object]} entry The entry to filter. - * @returns {boolean} True if the entry is a CSS feature, false otherwise. + * 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 filterCSSFeatures([, value]) { - return value.compat_features?.some(feature => feature.startsWith("css.")); -} +function flattenCompatFeatures(entry) { + if (!entry.compat_features) { + return {}; + } -/** - * Minimizes the data for a CSS feature. - * @param {[string, Object]} entry The entry to minimize. - * @returns {[string, Object]} The minimized entry. - */ -function minimizeData([key, value]) { - return [ - key, - { - baseline: value.status.baseline, - properties: [ - ...new Set( - value.compat_features - .filter(feature => - feature.startsWith("css.properties."), - ) - .map(feature => - feature - .replace("css.properties.", "") - .replace(/\.[\w\d-]+$/u, ""), - ), - ), - ], - atRules: [ - ...new Set( - value.compat_features - .filter(feature => feature.startsWith("css.at-rules.")) - .map(feature => - feature - .replace("css.at-rules.", "") - .replace(/\.[\w\d-]+$/u, ""), - ), - ), - ], - types: [ - ...new Set( - value.compat_features - .filter(feature => feature.startsWith("css.types.")) - .map(feature => - feature - .replace("css.types.", "") - .replace(/\.[\w\d-]+$/u, ""), - ), - ), - ], - selectors: [ - ...new Set( - value.compat_features - .filter(feature => feature.startsWith("css.selectors.")) - .map(feature => - feature - .replace("css.selectors.", "") - .replace(/\.[\w\d-]+$/u, ""), - ), - ), - ], - }, - ]; + return Object.fromEntries( + entry.compat_features.map(feature => [feature, entry.status.baseline]), + ); } /** - * Groups CSS features by baseline. - * @param {Array<[string, Object]>} entries The entries to group. - * @returns {Object} The grouped CSS features. + * Extracts CSS features from the raw data. + * @param {Object} features The CSS features to extract. + * @returns {Object} The extracted CSS features. */ -function groupByBaseline(entries) { - const allFeatures = { - properties: {}, - atRules: {}, - types: {}, - selectors: {}, - }; - - /* - * We end up with duplicates due to the naive way we are calculating - * which values to include. So we need to remove duplicates and update - * each to the highest possible baseline value. - */ - - for (const [, value] of entries) { - value.properties.forEach(property => { - if ( - allFeatures.properties[property] === undefined || - allFeatures.properties[property] < - baselineIds.get(value.baseline) - ) { - allFeatures.properties[property] = baselineIds.get( - value.baseline, - ); - } - }); - - value.atRules.forEach(atRule => { - if ( - allFeatures.atRules[atRule] === undefined || - allFeatures.atRules[atRule] < baselineIds.get(value.baseline) - ) { - allFeatures.atRules[atRule] = baselineIds.get(value.baseline); +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] = {}; } - }); - - value.types.forEach(type => { - if ( - allFeatures.types[type] === undefined || - allFeatures.types[type] < baselineIds.get(value.baseline) - ) { - allFeatures.types[type] = baselineIds.get(value.baseline); - } - }); - - value.selectors.forEach(selector => { - if ( - allFeatures.selectors[selector] === undefined || - allFeatures.selectors[selector] < - baselineIds.get(value.baseline) - ) { - allFeatures.selectors[selector] = baselineIds.get( - value.baseline, - ); - } - }); + 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 allFeatures; + return { + properties, + propertyValues, + atRules, + types, + selectors, + }; } //------------------------------------------------------------------------------ // Main //------------------------------------------------------------------------------ -const featuresPath = "./src/data/baseline-data.js"; -const cssFeatures = groupByBaseline( - Object.entries(features).filter(filterCSSFeatures).map(minimizeData), +// 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 = `/** @@ -185,6 +139,12 @@ export const properties = new Map(${JSON.stringify(Object.entries(cssFeatures.pr 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); From 2854f6cdeb1bbbb5c0f512ba565db159c9485fc4 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 16 Dec 2024 14:22:54 -0500 Subject: [PATCH 7/9] Nested @supports rules support --- README.md | 16 +- src/rules/baseline.js | 307 +++++++++++++++++++++++++++++------ tests/rules/baseline.test.js | 56 ++++--- 3 files changed, 300 insertions(+), 79 deletions(-) diff --git a/README.md b/README.md index 8a7e8e2..b3a3f68 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,15 @@ export default [ -| **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 | + +| **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 | + **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose. diff --git a/src/rules/baseline.js b/src/rules/baseline.js index 05c4d0b..03885e8 100644 --- a/src/rules/baseline.js +++ b/src/rules/baseline.js @@ -15,6 +15,202 @@ import { atRules, } 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 //----------------------------------------------------------------------------- @@ -60,20 +256,28 @@ export default { const availability = context.options[0].available; const baselineLevel = availability === "widely" ? BASELINE_HIGH : BASELINE_LOW; - const atSupportedProperties = new Map(); + const supportsRules = new SupportsRules(); return { + "Atrule[name=supports]"() { + supportsRules.push(new SupportsRule()); + }, + "Atrule[name=supports] SupportsDeclaration > Declaration"(node) { - if (!atSupportedProperties.has(node.property)) { - atSupportedProperties.set(node.property, new Set()); + const supportsRule = supportsRules.last(); + + if (!supportsRule.hasProperty(node.property)) { + supportsRule.addProperty(node.property); } // for now we can only check identifiers - if (node.value.children[0].type === "Identifier") { - atSupportedProperties - .get(node.property) - .add(node.value.children[0].name); - } + node.value.children.forEach(child => { + if (child.type === "Identifier") { + supportsRule + .getProperty(node.property) + .addIdentifier(child.name); + } + }); }, "Rule > Block > Declaration"(node) { @@ -83,40 +287,58 @@ export default { } // if the property has been tested in a @supports rule, ignore it - if (atSupportedProperties.has(node.property)) { - const firstChild = node.value.children[0]; - - // make sure the identifier is allowed - if (firstChild.type === "Identifier") { - if ( - atSupportedProperties - .get(node.property) - .has(firstChild.name) - ) { - return; - } + 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); - const propertyValueLevel = propertyValues - .get(node.property) - .get(firstChild.name); - - if (propertyValueLevel < baselineLevel) { - context.report({ - loc: firstChild.loc, - messageId: "notBaselinePropertyValue", - data: { - property: node.property, - value: firstChild.name, - availability, - }, - }); + if (propertyValueLevel < baselineLevel) { + context.report({ + loc: child.loc, + messageId: "notBaselinePropertyValue", + data: { + property: node.property, + value: child.name, + availability, + }, + }); + } + } } - } else { - // we can't check the value so we'll give the user the benefit of the doubt + } + + /* + * 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) { @@ -139,17 +361,8 @@ export default { } }, - "Atrule[name=supports]:exit"(node) { - // remove all properties tested in this @supports rule - node.prelude.children.forEach(condition => { - condition.children.forEach(child => { - if (child.type === "SupportsDeclaration") { - atSupportedProperties.delete( - child.declaration.property, - ); - } - }); - }); + "Atrule[name=supports]:exit"() { + supportsRules.pop(); }, Atrule(node) { diff --git a/tests/rules/baseline.test.js b/tests/rules/baseline.test.js index 3c7aa24..51c4651 100644 --- a/tests/rules/baseline.test.js +++ b/tests/rules/baseline.test.js @@ -36,18 +36,24 @@ ruleTester.run("baseline", rule, { "@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 } - }`, + a { accent-color: auto; background-filter: auto } + }`, `@supports (accent-color: auto) { - @supports (backdrop-filter: auto) { - a { accent-color: auto; background-filter: 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; - }`, + syntax: "*"; + inherits: false; + }`, options: [{ available: "newly" }], }, { @@ -102,12 +108,12 @@ ruleTester.run("baseline", rule, { }, { code: `@property --foo { - syntax: "*"; - inherits: false; - } - @media (min-width: 800px) { - a { color: red; } - }`, + syntax: "*"; + inherits: false; + } + @media (min-width: 800px) { + a { color: red; } + }`, options: [{ available: "widely" }], errors: [ { @@ -158,12 +164,12 @@ ruleTester.run("baseline", rule, { }, { code: dedent`@supports (accent-color: auto) { - @supports (backdrop-filter: auto) { - a { accent-color: red; } - } - - a { backdrop-filter: auto; } - }`, + @supports (backdrop-filter: auto) { + a { accent-color: red; } + } + + a { backdrop-filter: auto; } + }`, errors: [ { messageId: "notBaselineProperty", @@ -172,9 +178,9 @@ ruleTester.run("baseline", rule, { availability: "widely", }, line: 3, - column: 13, + column: 7, endLine: 3, - endColumn: 25, + endColumn: 19, }, { messageId: "notBaselineProperty", @@ -183,9 +189,9 @@ ruleTester.run("baseline", rule, { availability: "widely", }, line: 6, - column: 9, + column: 6, endLine: 6, - endColumn: 24, + endColumn: 21, }, ], }, From 9bfba9c2c50e14b37d7fafc76a7d53b10443afdf Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 16 Dec 2024 14:47:20 -0500 Subject: [PATCH 8/9] Add basic checking for functions --- README.md | 16 +++++----- docs/rules/baseline.md | 6 ++++ src/data/README.md | 4 --- src/data/csstree-data.js | 60 ------------------------------------ src/rules/baseline.js | 21 +++++++++++++ tests/rules/baseline.test.js | 18 +++++++++++ 6 files changed, 52 insertions(+), 73 deletions(-) delete mode 100644 src/data/csstree-data.js diff --git a/README.md b/README.md index b3a3f68..8a7e8e2 100644 --- a/README.md +++ b/README.md @@ -55,15 +55,13 @@ export default [ - -| **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 | - +| **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 | **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose. diff --git a/docs/rules/baseline.md b/docs/rules/baseline.md index 1b4e05f..73dcbea 100644 --- a/docs/rules/baseline.md +++ b/docs/rules/baseline.md @@ -21,6 +21,7 @@ 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. @@ -32,6 +33,11 @@ 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 { diff --git a/src/data/README.md b/src/data/README.md index fa8f271..639ba50 100644 --- a/src/data/README.md +++ b/src/data/README.md @@ -11,7 +11,3 @@ To generate baseline data, run: ```shell npm run build:baseline ``` - -## csstree-data.js (manual) - -Contains data that helps to work with CSSTree. diff --git a/src/data/csstree-data.js b/src/data/csstree-data.js deleted file mode 100644 index 340cee9..0000000 --- a/src/data/csstree-data.js +++ /dev/null @@ -1,60 +0,0 @@ -/** - * @fileoverview Data to help work with CSSTree. - * @author Nicholas C. Zakas - */ - -/** - * Map of CSS properties to the nodes representing those types in CSSTree. - */ -export const typeNodes = new Map([ - ["acos", ["Function"]], - ["angle-percentage", ["Dimension", "Percentage"]], - ["angle", ["Dimension"]], - ["asin", ["Function"]], - ["atan", ["Function"]], - ["atan2", ["Function"]], - ["attr", ["Function"]], - ["basic-shape", ["Function"]], - ["blend-mode", ["Function"]], - ["calc-constant", ["Identifier"]], - ["calc", ["Function"]], - ["clamp", ["Function"]], - ["color", ["Hash", "Function", "Identifier"]], - ["cos", "Function"], - ["counter", ["Function"]], - ["counters", ["Function"]], - ["dimension", ["Dimension"]], - ["easing-function", ["Function"]], - ["exp", ["Function"]], - ["filter-function", ["Function"]], - ["flex", "Identifier"], - ["gradient", ["Function"]], - ["hypot", ["Function"]], - ["image", ["Function"]], - ["image", ["Image"]], - ["integer", ["Number"]], - ["length-percentage", ["Length", "Percentage"]], - ["length", ["Dimension"]], - ["line-style", ["Identifier"]], - ["log", ["Function"]], - ["max", ["Function"]], - ["min", ["Function"]], - ["mod", ["Function"]], - ["number", ["Number"]], - ["overflow", ["Overflow"]], - ["percentage", ["Percentage"]], - ["position", ["Position"]], - ["pow", ["Pow"]], - ["ratio", ["Ratio"]], - ["ray", ["Ray"]], - ["rem", ["Rem"]], - ["resolution", ["Resolution"]], - ["round", ["Function"]], - ["sin", ["Function"]], - ["sqrt", ["Function"]], - ["string", ["String"]], - ["tan", ["Function"]], - ["time", ["Dimension"]], - ["transform-function", ["Function"]], - ["url", ["Url"]], -]); diff --git a/src/rules/baseline.js b/src/rules/baseline.js index 03885e8..7d77f62 100644 --- a/src/rules/baseline.js +++ b/src/rules/baseline.js @@ -13,6 +13,7 @@ import { properties, propertyValues, atRules, + types, } from "../data/baseline-data.js"; //----------------------------------------------------------------------------- @@ -249,6 +250,8 @@ export default { "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.", }, }, @@ -361,6 +364,24 @@ export default { } }, + 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(); }, diff --git a/tests/rules/baseline.test.js b/tests/rules/baseline.test.js index 51c4651..9a69c6e 100644 --- a/tests/rules/baseline.test.js +++ b/tests/rules/baseline.test.js @@ -30,6 +30,7 @@ ruleTester.run("baseline", rule, { "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; } }", @@ -228,5 +229,22 @@ ruleTester.run("baseline", rule, { }, ], }, + { + code: "a { width: abs(20% - 100px); }", + errors: [ + { + messageId: "notBaselineType", + data: { + property: "width", + type: "abs", + availability: "widely", + }, + line: 1, + column: 12, + endLine: 1, + endColumn: 28, + }, + ], + }, ], }); From 125186b3673b0b712cd6094cb6751c808a7b47c2 Mon Sep 17 00:00:00 2001 From: "Nicholas C. Zakas" Date: Mon, 16 Dec 2024 14:48:28 -0500 Subject: [PATCH 9/9] Fix style issues --- README.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 8a7e8e2..b3a3f68 100644 --- a/README.md +++ b/README.md @@ -55,13 +55,15 @@ export default [ -| **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 | + +| **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 | + **Note:** This plugin does not provide formatting rules. We recommend using a source code formatter such as [Prettier](https://prettier.io) for that purpose.