Huge News!Announcing our $40M Series B led by Abstract Ventures.Learn More
Socket
Sign inDemoInstall
Socket

css-tree

Package Overview
Dependencies
Maintainers
2
Versions
57
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

css-tree - npm Package Compare versions

Comparing version 2.3.1 to 3.0.0

cjs/syntax/atrule/container.cjs

440

data/patch.json

@@ -6,2 +6,5 @@ {

},
"container": {
"prelude": "[ <container-name> ]? <container-condition>"
},
"font-face": {

@@ -17,2 +20,46 @@ "descriptors": {

"prelude": "<complex-selector-list>"
},
"scope": {
"prelude": "[ ( <scope-start> ) ]? [ to ( <scope-end> ) ]?"
},
"position-try": {
"comment": "The list of descriptors: https://developer.mozilla.org/en-US/docs/Web/CSS/@position-try",
"descriptors": {
"top": "<'top'>",
"left": "<'left'>",
"bottom": "<'bottom'>",
"right": "<'right'>",
"inset-block-start": "<'inset-block-start'>",
"inset-block-end": "<'inset-block-end'>",
"inset-inline-start": "<'inset-inline-start'>",
"inset-inline-end": "<'inset-inline-end'>",
"inset-block": "<'inset-block'>",
"inset-inline": "<'inset-inline'>",
"inset": "<'inset'>",
"margin-top": "<'margin-top'>",
"margin-left": "<'margin-left'>",
"margin-bottom": "<'margin-bottom'>",
"margin-right": "<'margin-right'>",
"margin-block-start": "<'margin-block-start'>",
"margin-block-end": "<'margin-block-end'>",
"margin-inline-start": "<'margin-inline-start'>",
"margin-inline-end": "<'margin-inline-end'>",
"margin": "<'margin'>",
"margin-block": "<'margin-block'>",
"margin-inline": "<'margin-inline'>",
"width": "<'width'>",
"height": "<'height'>",
"min-width": "<'min-width'>",
"min-height": "<'min-height'>",
"max-width": "<'max-width'>",
"max-height": "<'max-height'>",
"block-size": "<'block-size'>",
"inline-size": "<'inline-size'>",
"min-block-size": "<'min-block-size'>",
"min-inline-size": "<'min-inline-size'>",
"max-block-size": "<'max-block-size'>",
"max-inline-size": "<'max-inline-size'>",
"align-self": "<'align-self'> | anchor-center",
"justify-self": "<'justify-self'> | anchor-center"
}
}

@@ -176,8 +223,5 @@ },

},
"clip-rule": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/masking.html#ClipRuleProperty"
],
"syntax": "nonzero | evenodd"
"container-type": {
"comment": "https://www.w3.org/TR/css-contain-3/#propdef-container-type",
"syntax": "normal || [ size | inline-size ]"
},

@@ -240,9 +284,2 @@ "cue": {

},
"fill-rule": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/painting.html#FillProperty"
],
"syntax": "nonzero | evenodd"
},
"filter": {

@@ -252,2 +289,11 @@ "comment": "extend with IE legacy syntaxes",

},
"font": {
"comment": "align with font-4, fix <'font-family'>#, add non standard fonts",
"references": [
"https://drafts.csswg.org/css-fonts-4/#font-prop",
"https://github.com/w3c/csswg-drafts/pull/10832",
"https://webkit.org/blog/3709/using-the-system-font-in-web-content/"
],
"syntax": "[ [ <'font-style'> || <font-variant-css2> || <'font-weight'> || <font-width-css3> ]? <'font-size'> [ / <'line-height'> ]? <'font-family'># ] | <system-family-name> | <-non-standard-font>"
},
"glyph-orientation-horizontal": {

@@ -281,34 +327,10 @@ "comment": "added SVG property",

},
"marker": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/painting.html#MarkerProperties"
],
"syntax": "none | <url>"
"max-width": {
"comment": "extend by non-standard size keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width",
"syntax": "| stretch | <-non-standard-size>"
},
"marker-end": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/painting.html#MarkerProperties"
],
"syntax": "none | <url>"
"max-height": {
"comment": "extend by non-standard size keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width",
"syntax": "| stretch | <-non-standard-size>"
},
"marker-mid": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/painting.html#MarkerProperties"
],
"syntax": "none | <url>"
},
"marker-start": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/painting.html#MarkerProperties"
],
"syntax": "none | <url>"
},
"max-width": {
"comment": "extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/max-width",
"syntax": "| <-non-standard-width>"
},
"width": {

@@ -319,8 +341,14 @@ "references": [

],
"syntax": "| fill | stretch | intrinsic | -moz-max-content | -webkit-max-content | -moz-fit-content | -webkit-fit-content"
"syntax": "| stretch | <-non-standard-size>"
},
"height": {
"syntax": "| stretch | <-non-standard-size>"
},
"min-width": {
"comment": "extend by non-standard width keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width",
"syntax": "| <-non-standard-width>"
"syntax": "| stretch | <-non-standard-size>"
},
"min-height": {
"syntax": "| stretch | <-non-standard-size>"
},
"overflow": {

@@ -354,9 +382,16 @@ "comment": "extend by vendor keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow",

},
"shape-rendering": {
"comment": "added SVG property",
"scroll-timeline": {
"comment": "fix according to spec",
"references": [
"https://www.w3.org/TR/SVG/painting.html#ShapeRenderingPropert"
"https://www.w3.org/TR/scroll-animations-1/#scroll-timeline-shorthand"
],
"syntax": "auto | optimizeSpeed | crispEdges | geometricPrecision"
"syntax": "[ <'scroll-timeline-name'> || <'scroll-timeline-axis'> ]#"
},
"scroll-timeline-name": {
"comment": "fix according to spec",
"references": [
"https://w3c.github.io/csswg-drafts/scroll-animations/#propdef-scroll-timeline-name"
],
"syntax": "[ none | <dashed-ident> ]#"
},
"src": {

@@ -368,3 +403,3 @@ "comment": "added @font-face's src property https://developer.mozilla.org/en-US/docs/Web/CSS/@font-face/src",

"comment": "https://www.w3.org/TR/css3-speech/#property-index",
"syntax": "auto | none | normal"
"syntax": "auto | never | always"
},

@@ -431,9 +466,2 @@ "speak-as": {

},
"text-anchor": {
"comment": "added SVG property",
"references": [
"https://www.w3.org/TR/SVG/text.html#TextAlignmentProperties"
],
"syntax": "start | middle | end"
},
"unicode-bidi": {

@@ -482,2 +510,21 @@ "comment": "added prefixed keywords https://developer.mozilla.org/en-US/docs/Web/CSS/unicode-bidi",

"syntax": "| <svg-writing-mode>"
},
"white-space-trim": {
"syntax": "none | discard-before || discard-after || discard-inner",
"comment": "missed, https://www.w3.org/TR/css-text-4/#white-space-trim"
},
"position-area": {
"syntax": "none | <position-area>",
"comment": "replaced <'inset-area'>, https://drafts.csswg.org/css-anchor-position-1/#position-area"
},
"position-try-fallbacks": {
"syntax": "none | [ [<dashed-ident> || <try-tactic>] | <'position-area'> ]#",
"comment": "replaced <'position-try-options'>, https://drafts.csswg.org/css-anchor-position-1/#position-try-fallbacks"
},
"word-break": {
"syntax": "normal | break-all | keep-all | break-word | auto-phrase",
"comment": "added in Chrome/Edge 119, not covered by a spec currently (2024-09-02)",
"references": [
"https://developer.mozilla.org/en-US/docs/Web/CSS/word-break"
]
}

@@ -543,7 +590,7 @@ },

"comment": "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/overflow",
"syntax": "-moz-scrollbars-none | -moz-scrollbars-horizontal | -moz-scrollbars-vertical | -moz-hidden-unscrollable"
"syntax": "overlay | -moz-scrollbars-none | -moz-scrollbars-horizontal | -moz-scrollbars-vertical | -moz-hidden-unscrollable"
},
"-non-standard-width": {
"-non-standard-size": {
"comment": "non-standard keywords https://developer.mozilla.org/en-US/docs/Web/CSS/width",
"syntax": "fill-available | min-intrinsic | intrinsic | -moz-available | -moz-fit-content | -moz-min-content | -moz-max-content | -webkit-min-content | -webkit-max-content"
"syntax": "intrinsic | min-intrinsic | -webkit-fill-available | -webkit-fit-content | -webkit-min-content | -webkit-max-content | -moz-available | -moz-fit-content | -moz-min-content | -moz-max-content"
},

@@ -574,6 +621,2 @@ "-webkit-gradient()": {

},
"-webkit-mask-clip-style": {
"comment": "missed; there is no enough information about `-webkit-mask-clip` property, but looks like all those keywords are working",
"syntax": "border | border-box | padding | padding-box | content | content-box | text"
},
"-ms-filter-function-list": {

@@ -595,5 +638,10 @@ "comment": "https://developer.mozilla.org/en-US/docs/Web/CSS/-ms-filter",

},
"-ms-filter": {
"syntax": "<string>"
"absolute-color-base": {
"comment": "https://www.w3.org/TR/css-color-4/#color-syntax",
"syntax": "<hex-color> | <absolute-color-function> | <named-color> | transparent"
},
"absolute-color-function": {
"comment": "https://www.w3.org/TR/css-color-4/#color-syntax",
"syntax": "rgb()> | <rgba()> | <hsl()> | <hsla()> | <hwb()> | <lab()> | <lch()> | <oklab()> | <oklch()> | <color()>"
},
"age": {

@@ -621,2 +669,13 @@ "comment": "https://www.w3.org/TR/css3-speech/#voice-family",

},
"container-name": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "<custom-ident>"
},
"container-condition": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "not <query-in-parens> | <query-in-parens> [ [ and <query-in-parens> ]* | [ or <query-in-parens> ]* ]"
},
"coord-box": {
"syntax": "content-box | padding-box | border-box | fill-box | stroke-box | view-box"
},
"element()": {

@@ -634,8 +693,25 @@ "comment": "https://drafts.csswg.org/css-gcpm/#element-syntax & https://drafts.csswg.org/css-images-4/#element-notation",

},
"general-enclosed": {
"comment": "remove ident-token, optional any-value, brackets (see https://drafts.csswg.org/mediaqueries-5/#typedef-general-enclosed)",
"syntax": "[ <function-token> <any-value>? ) ] | [ ( <any-value>? ) ]"
},
"generic-family": {
"comment": "added -apple-system",
"comment": "new definition on font-4, https://drafts.csswg.org/css-fonts-4/#typedef-generic-family",
"syntax": "<generic-script-specific>| <generic-complete> | <generic-incomplete> | <-non-standard-generic-family>"
},
"generic-script-specific": {
"syntax": "generic(kai) | generic(fangsong) | generic(nastaliq)"
},
"generic-complete": {
"syntax": "serif | sans-serif | system-ui | cursive | fantasy | math | monospace"
},
"generic-incomplete": {
"syntax": "ui-serif | ui-sans-serif | ui-monospace | ui-rounded"
},
"-non-standard-generic-family": {
"syntax": "-apple-system | BlinkMacSystemFont",
"references": [
"https://css-tricks.com/snippets/css/system-font-stack/",
"https://webkit.org/blog/3709/using-the-system-font-in-web-content/"
],
"syntax": "| -apple-system"
]
},

@@ -650,10 +726,48 @@ "gradient": {

},
"mask-image": {
"comment": "missed; https://drafts.fxtf.org/css-masking-1/#the-mask-image",
"syntax": "<mask-reference>#"
"color": {
"comment": "css-color-5, added non standard color names",
"syntax": "<color-base> | currentColor | <system-color> | <device-cmyk()> | <light-dark()> | <-non-standard-color>"
},
"named-color": {
"comment": "added non standard color names",
"syntax": "| <-non-standard-color>"
"color-base": {
"syntax": "<hex-color> | <color-function> | <named-color> | <color-mix()> | transparent"
},
"color-function": {
"syntax": "<rgb()> | <rgba()> | <hsl()> | <hsla()> | <hwb()> | <lab()> | <lch()> | <oklab()> | <oklch()> | <color()>"
},
"system-color": {
"syntax": "AccentColor | AccentColorText | ActiveText | ButtonBorder | ButtonFace | ButtonText | Canvas | CanvasText | Field | FieldText | GrayText | Highlight | HighlightText | LinkText | Mark | MarkText | SelectedItem | SelectedItemText | VisitedText"
},
"device-cmyk()": {
"syntax": "<legacy-device-cmyk-syntax> | <modern-device-cmyk-syntax>"
},
"legacy-device-cmyk-syntax": {
"syntax": "device-cmyk( <number>#{4} )"
},
"modern-device-cmyk-syntax": {
"syntax": "device-cmyk( <cmyk-component>{4} [ / [ <alpha-value> | none ] ]? )"
},
"cmyk-component": {
"syntax": "<number> | <percentage> | none"
},
"color-mix()": {
"syntax": "color-mix( <color-interpolation-method> , [ <color> && <percentage [0,100]>? ]#{2} )"
},
"color-interpolation-method": {
"syntax": "in [ <rectangular-color-space> | <polar-color-space> <hue-interpolation-method>? | <custom-color-space> ]"
},
"color-space": {
"syntax": "<rectangular-color-space> | <polar-color-space> | <custom-color-space>"
},
"rectangular-color-space": {
"syntax": "srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020 | lab | oklab | xyz | xyz-d50 | xyz-d65"
},
"polar-color-space": {
"syntax": "hsl | hwb | lch | oklch"
},
"custom-color-space": {
"syntax": "<dashed-ident>"
},
"hue-interpolation-method": {
"syntax": "[ shorter | longer | increasing | decreasing ] hue"
},
"paint": {

@@ -663,2 +777,6 @@ "comment": "used by SVG https://www.w3.org/TR/SVG/painting.html#SpecifyingPaint",

},
"palette-identifier": {
"comment": "<palette-identifier> is parsed as a <dashed-ident> (https://drafts.csswg.org/css-fonts/#typedef-font-palette-palette-identifier)",
"syntax": "<dashed-ident>"
},
"right": {

@@ -672,13 +790,56 @@ "comment": "missed; not sure we should add it, but no others except `shape` is using it so it's ok for now; https://drafts.fxtf.org/css-masking-1/#funcdef-clip-rect",

},
"scroll-timeline-axis": {
"comment": "missed definition",
"syntax": "block | inline | vertical | horizontal"
"scope-start": {
"syntax": "<forgiving-selector-list>"
},
"scroll-timeline-name": {
"comment": "missed definition",
"references": [
"https://w3c.github.io/csswg-drafts/scroll-animations/#propdef-scroll-timeline-name"
],
"syntax": "none | <custom-ident>"
"scope-end": {
"syntax": "<forgiving-selector-list>"
},
"forgiving-selector-list": {
"syntax": "<complex-real-selector-list>"
},
"forgiving-relative-selector-list": {
"syntax": "<relative-real-selector-list>"
},
"selector-list": {
"syntax": "<complex-selector-list>"
},
"complex-real-selector-list": {
"syntax": "<complex-real-selector>#"
},
"simple-selector-list": {
"syntax": "<simple-selector>#"
},
"relative-real-selector-list": {
"syntax": "<relative-real-selector>#"
},
"complex-selector": {
"syntax": "<complex-selector-unit> [ <combinator>? <complex-selector-unit> ]*"
},
"complex-selector-unit": {
"syntax": "[ <compound-selector>? <pseudo-compound-selector>* ]!"
},
"complex-real-selector": {
"syntax": "<compound-selector> [ <combinator>? <compound-selector> ]*"
},
"relative-real-selector": {
"syntax": "<combinator>? <complex-real-selector>"
},
"compound-selector": {
"syntax": "[ <type-selector>? <subclass-selector>* ]!"
},
"pseudo-compound-selector": {
"syntax": " <pseudo-element-selector> <pseudo-class-selector>*"
},
"simple-selector": {
"syntax": "<type-selector> | <subclass-selector>"
},
"combinator": {
"syntax": "'>' | '+' | '~' | [ '|' '|' ]"
},
"pseudo-element-selector": {
"syntax": "':' <pseudo-class-selector> | <legacy-pseudo-element-selector>"
},
"legacy-pseudo-element-selector": {
"syntax": " ':' [before | after | first-line | first-letter]"
},
"single-animation-composition": {

@@ -740,6 +901,117 @@ "comment": "missed definition",

},
"color()": {
"syntax": "color( <colorspace-params> [ / [ <alpha-value> | none ] ]? )"
},
"colorspace-params": {
"syntax": "[ <predefined-rgb-params> | <xyz-params>]"
},
"predefined-rgb-params": {
"syntax": "<predefined-rgb> [ <number> | <percentage> | none ]{3}"
},
"predefined-rgb": {
"syntax": "srgb | srgb-linear | display-p3 | a98-rgb | prophoto-rgb | rec2020"
},
"xyz-params": {
"syntax": "<xyz-space> [ <number> | <percentage> | none ]{3}"
},
"xyz-space": {
"syntax": "xyz | xyz-d50 | xyz-d65"
},
"oklab()": {
"comment": "https://www.w3.org/TR/css-color-4/#specifying-oklab-oklch",
"syntax": "oklab( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ / [<alpha-value> | none] ]? )"
},
"oklch()": {
"comment": "https://www.w3.org/TR/css-color-4/#specifying-oklab-oklch",
"syntax": "oklch( [ <percentage> | <number> | none] [ <percentage> | <number> | none] [ <hue> | none] [ / [<alpha-value> | none] ]? )"
},
"offset-path": {
"syntax": "<ray()> | <url> | <basic-shape>"
},
"query-in-parens": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "( <container-condition> ) | ( <size-feature> ) | style( <style-query> ) | <general-enclosed>"
},
"size-feature": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#typedef-size-feature",
"syntax": "<mf-plain> | <mf-boolean> | <mf-range>"
},
"style-feature": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#typedef-style-feature",
"syntax": "<declaration>"
},
"style-query": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "<style-condition> | <style-feature>"
},
"style-condition": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "not <style-in-parens> | <style-in-parens> [ [ and <style-in-parens> ]* | [ or <style-in-parens> ]* ]"
},
"style-in-parens": {
"comment": "missed, https://drafts.csswg.org/css-contain-3/#container-rule",
"syntax": "( <style-condition> ) | ( <style-feature> ) | <general-enclosed>"
},
"-non-standard-display": {
"syntax": "-ms-inline-flexbox | -ms-grid | -ms-inline-grid | -webkit-flex | -webkit-inline-flex | -webkit-box | -webkit-inline-box | -moz-inline-stack | -moz-box | -moz-inline-box"
},
"inset-area": {
"syntax": "[ [ left | center | right | span-left | span-right | x-start | x-end | span-x-start | span-x-end | x-self-start | x-self-end | span-x-self-start | span-x-self-end | span-all ] || [ top | center | bottom | span-top | span-bottom | y-start | y-end | span-y-start | span-y-end | y-self-start | y-self-end | span-y-self-start | span-y-self-end | span-all ] | [ block-start | center | block-end | span-block-start | span-block-end | span-all ] || [ inline-start | center | inline-end | span-inline-start | span-inline-end | span-all ] | [ self-block-start | self-block-end | span-self-block-start | span-self-block-end | span-all ] || [ self-inline-start | self-inline-end | span-self-inline-start | span-self-inline-end | span-all ] | [ start | center | end | span-start | span-end | span-all ]{1,2} | [ self-start | center | self-end | span-self-start | span-self-end | span-all ]{1,2} ]",
"comment": "initial name for <position-area> before renamed",
"references": [
"https://www.w3.org/TR/css-anchor-position-1/#inset-area"
]
},
"position-area": {
"syntax": "[ [ left | center | right | span-left | span-right | x-start | x-end | span-x-start | span-x-end | x-self-start | x-self-end | span-x-self-start | span-x-self-end | span-all ] || [ top | center | bottom | span-top | span-bottom | y-start | y-end | span-y-start | span-y-end | y-self-start | y-self-end | span-y-self-start | span-y-self-end | span-all ] | [ block-start | center | block-end | span-block-start | span-block-end | span-all ] || [ inline-start | center | inline-end | span-inline-start | span-inline-end | span-all ] | [ self-block-start | center | self-block-end | span-self-block-start | span-self-block-end | span-all ] || [ self-inline-start | center | self-inline-end | span-self-inline-start | span-self-inline-end | span-all ] | [ start | center | end | span-start | span-end | span-all ]{1,2} | [ self-start | center | self-end | span-self-start | span-self-end | span-all ]{1,2} ]",
"comment": "replaced <inset-area>",
"references": [
"https://drafts.csswg.org/css-anchor-position-1/#typedef-position-area"
]
},
"anchor()": {
"syntax": "anchor( <anchor-element>? && <anchor-side>, <length-percentage>? )",
"comment": "missed",
"references": [
"https://drafts.csswg.org/css-anchor-position-1/#anchor-pos"
]
},
"anchor-side": {
"syntax": "inside | outside | top | left | right | bottom | start | end | self-start | self-end | <percentage> | center"
},
"anchor-size()": {
"syntax": "anchor-size( [ <anchor-element> || <anchor-size> ]? , <length-percentage>? )",
"comment": "missed",
"references": [
"https://drafts.csswg.org/css-anchor-position-1/#funcdef-anchor-size"
]
},
"anchor-size": {
"syntax": "width | height | block | inline | self-block | self-inline"
},
"anchor-element": {
"syntax": "<dashed-ident>",
"comment": "missed, https://drafts.csswg.org/css-anchor-position-1/#typedef-anchor-element"
},
"try-size": {
"syntax": "most-width | most-height | most-block-size | most-inline-size",
"comment": "missed, https://drafts.csswg.org/css-anchor-position-1/#typedef-try-size"
},
"try-tactic": {
"syntax": "flip-block || flip-inline || flip-start",
"comment": "missed, https://drafts.csswg.org/css-anchor-position-1/#typedef-position-try-fallbacks-try-tactic"
},
"font-variant-css2": {
"syntax": "normal | small-caps",
"comment": "new definition on font-4, https://drafts.csswg.org/css-fonts-4/#font-variant-css21-values"
},
"font-width-css3": {
"syntax": "normal | ultra-condensed | extra-condensed | condensed | semi-condensed | semi-expanded | expanded | extra-expanded | ultra-expanded",
"comment": "new definition on font-4, https://drafts.csswg.org/css-fonts-4/#font-width-css3-values"
},
"system-family-name": {
"syntax": "caption | icon | menu | message-box | small-caption | status-bar",
"comment": "new definition on font-4, https://drafts.csswg.org/css-fonts-4/#system-family-name-value"
}
}
}

2

dist/version.js

@@ -1,1 +0,1 @@

export const version = "2.3.1";
export const version = "3.0.0";

@@ -9,2 +9,3 @@ import { createRequire } from 'module';

const hasOwn = Object.hasOwn || ((object, property) => Object.prototype.hasOwnProperty.call(object, property));
const extendSyntax = /^\s*\|\s*/;

@@ -15,4 +16,3 @@

for (const atruleName in dict) {
const atrule = dict[atruleName];
for (const [atruleName, atrule] of Object.entries(dict)) {
let descriptors = null;

@@ -23,4 +23,4 @@

for (const descriptor in atrule.descriptors) {
descriptors[descriptor] = atrule.descriptors[descriptor].syntax;
for (const [name, descriptor] of Object.entries(atrule.descriptors)) {
descriptors[name] = descriptor.syntax;
}

@@ -39,12 +39,14 @@ }

function patchDictionary(dict, patchDict) {
const result = {};
const result = Object.create(null);
// copy all syntaxes for an original dict
for (const key in dict) {
result[key] = dict[key].syntax || dict[key];
for (const [key, value] of Object.entries(dict)) {
if (value) {
result[key] = value.syntax || value;
}
}
// apply a patch
for (const key in patchDict) {
if (key in dict) {
for (const key of Object.keys(patchDict)) {
if (hasOwn(dict, key)) {
if (patchDict[key].syntax) {

@@ -67,2 +69,14 @@ result[key] = extendSyntax.test(patchDict[key].syntax)

function preprocessPatchAtrulesDescritors(declarations) {
const result = {};
for (const [key, value] of Object.entries(declarations || {})) {
result[key] = typeof value === 'string'
? { syntax: value }
: value;
}
return result;
}
function patchAtrules(dict, patchDict) {

@@ -73,2 +87,6 @@ const result = {};

for (const key in dict) {
if (patchDict[key] === null) {
continue;
}
const atrulePatch = patchDict[key] || {};

@@ -80,3 +98,6 @@

: dict[key].prelude || null,
descriptors: patchDictionary(dict[key].descriptors || {}, atrulePatch.descriptors || {})
descriptors: patchDictionary(
dict[key].descriptors || {},
preprocessPatchAtrulesDescritors(atrulePatch.descriptors)
)
};

@@ -86,9 +107,9 @@ }

// apply a patch
for (const key in patchDict) {
if (!hasOwnProperty.call(dict, key)) {
const atrulePatch = patchDict[key] || {};
for (const [key, atrulePatch] of Object.entries(patchDict)) {
if (atrulePatch && !hasOwn(dict, key)) {
result[key] = {
prelude: atrulePatch.prelude || null,
descriptors: atrulePatch.descriptors && patchDictionary({}, atrulePatch.descriptors)
descriptors: atrulePatch.descriptors
? patchDictionary({}, preprocessPatchAtrulesDescritors(atrulePatch.descriptors))
: null
};

@@ -95,0 +116,0 @@ }

@@ -94,9 +94,14 @@ import { Tokenizer } from './tokenizer.js';

tokenizer.eat(LEFTCURLYBRACKET);
tokenizer.skipWs();
min = scanNumber(tokenizer);
tokenizer.skipWs();
if (tokenizer.charCode() === COMMA) {
tokenizer.pos++;
tokenizer.skipWs();
if (tokenizer.charCode() !== RIGHTCURLYBRACKET) {
max = scanNumber(tokenizer);
tokenizer.skipWs();
}

@@ -103,0 +108,0 @@ } else {

@@ -26,2 +26,5 @@ import { SyntaxError } from './SyntaxError.js';

}
skipWs() {
this.pos = this.findWsEnd(this.pos);
}
findWsEnd(pos) {

@@ -28,0 +31,0 @@ for (; pos < this.str.length; pos++) {

@@ -35,4 +35,3 @@ import { tokenize, Delim, WhiteSpace } from '../tokenizer/index.js';

for (let name in config.node) {
const item = config.node[name];
for (let [name, item] of Object.entries(config.node)) {
const fn = item.generate || item;

@@ -39,0 +38,0 @@

@@ -208,15 +208,30 @@ import { cssWideKeywords } from './generic-const.js';

// https://drafts.csswg.org/css-values-4/#dashed-idents
// The <dashed-ident> production is a <custom-ident>, with all the case-sensitivity that implies,
// with the additional restriction that it must start with two dashes (U+002D HYPHEN-MINUS).
function dashedIdent(token) {
if (token === null || token.type !== Ident) {
return 0;
}
// ... must start with two dashes (U+002D HYPHEN-MINUS)
if (charCodeAt(token.value, 0) !== 0x002D || charCodeAt(token.value, 1) !== 0x002D) {
return 0;
}
return 1;
}
// https://drafts.csswg.org/css-variables/#typedef-custom-property-name
// A custom property is any property whose name starts with two dashes (U+002D HYPHEN-MINUS), like --foo.
// The <custom-property-name> production corresponds to this: it’s defined as any valid identifier
// that starts with two dashes, except -- itself, which is reserved for future use by CSS.
// NOTE: Current implementation treat `--` as a valid name since most (all?) major browsers treat it as valid.
// The <custom-property-name> production corresponds to this: it’s defined as any <dashed-ident>
// (a valid identifier that starts with two dashes), except -- itself, which is reserved for future use by CSS.
function customPropertyName(token) {
// ... defined as any valid identifier
if (token === null || token.type !== Ident) {
// ... it’s defined as any <dashed-ident>
if (!dashedIdent(token)) {
return 0;
}
// ... that starts with two dashes (U+002D HYPHEN-MINUS)
if (charCodeAt(token.value, 0) !== 0x002D || charCodeAt(token.value, 1) !== 0x002D) {
// ... except -- itself, which is reserved for future use by CSS
if (token.value === '--') {
return 0;

@@ -555,2 +570,3 @@ }

'custom-ident': customIdent,
'dashed-ident': dashedIdent,
'custom-property-name': customPropertyName,

@@ -557,0 +573,0 @@ 'hex-color': hexColor,

@@ -57,2 +57,13 @@ import { SyntaxReferenceError, SyntaxMatchError } from './error.js';

function syntaxHasTopLevelCommaMultiplier(syntax) {
const singleTerm = syntax.terms[0];
return (
syntax.explicit === false &&
syntax.terms.length === 1 &&
singleTerm.type === 'Multiplier' &&
singleTerm.comma === true
);
}
function buildMatchResult(matched, error, iterations) {

@@ -114,4 +125,4 @@ return {

if (config.types) {
for (const name in config.types) {
this.addType_(name, config.types[name]);
for (const [name, type] of Object.entries(config.types)) {
this.addType_(name, type);
}

@@ -128,4 +139,4 @@ }

if (config.atrules) {
for (const name in config.atrules) {
this.addAtrule_(name, config.atrules[name]);
for (const [name, atrule] of Object.entries(config.atrules)) {
this.addAtrule_(name, atrule);
}

@@ -135,4 +146,4 @@ }

if (config.properties) {
for (const name in config.properties) {
this.addProperty_(name, config.properties[name]);
for (const [name, property] of Object.entries(config.properties)) {
this.addProperty_(name, property);
}

@@ -173,3 +184,4 @@ }

syntax: null,
match: null
match: null,
matchRef: null // used for properties when a syntax referenced as <'property'> in other syntax definitions
};

@@ -205,2 +217,22 @@

});
if (type === 'Property') {
Object.defineProperty(descriptor, 'matchRef', {
get() {
const syntax = descriptor.syntax;
const value = syntaxHasTopLevelCommaMultiplier(syntax)
? buildMatchGraph({
...syntax,
terms: [syntax.terms[0].term]
}, ref)
: null;
Object.defineProperty(descriptor, 'matchRef', {
value
});
return value;
}
});
}
}

@@ -207,0 +239,0 @@

@@ -438,3 +438,3 @@ import { MATCH, MISMATCH, DISALLOW_EMPTY } from './match-graph.js';

openSyntax();
state = dictSyntax.match;
state = dictSyntax.matchRef || dictSyntax.match;
break;

@@ -441,0 +441,0 @@ }

@@ -102,2 +102,23 @@ import { List } from '../utils/List.js';

function genTypesList(fieldTypes, path) {
const docsTypes = [];
for (let i = 0; i < fieldTypes.length; i++) {
const fieldType = fieldTypes[i];
if (fieldType === String || fieldType === Boolean) {
docsTypes.push(fieldType.name.toLowerCase());
} else if (fieldType === null) {
docsTypes.push('null');
} else if (typeof fieldType === 'string') {
docsTypes.push(fieldType);
} else if (Array.isArray(fieldType)) {
docsTypes.push('List<' + (genTypesList(fieldType, path) || 'any') + '>'); // TODO: use type enum
} else {
throw new Error('Wrong value `' + fieldType + '` in `' + path + '` structure definition');
}
}
return docsTypes.join(' | ');
}
function processStructure(name, nodeType) {

@@ -118,3 +139,2 @@ const structure = nodeType.structure;

const docsTypes = [];
const fieldTypes = fields[key] = Array.isArray(structure[key])

@@ -124,18 +144,3 @@ ? structure[key].slice()

for (let i = 0; i < fieldTypes.length; i++) {
const fieldType = fieldTypes[i];
if (fieldType === String || fieldType === Boolean) {
docsTypes.push(fieldType.name);
} else if (fieldType === null) {
docsTypes.push('null');
} else if (typeof fieldType === 'string') {
docsTypes.push('<' + fieldType + '>');
} else if (Array.isArray(fieldType)) {
docsTypes.push('List'); // TODO: use type enum
} else {
throw new Error('Wrong value `' + fieldType + '` in `' + name + '.' + key + '` structure definition');
}
}
docs[key] = docsTypes.join(' | ');
docs[key] = genTypesList(fieldTypes, name + '.' + key);
}

@@ -142,0 +147,0 @@

@@ -41,3 +41,3 @@ import { List } from '../utils/List.js';

for (const name in dict) {
for (const name of Object.keys(dict)) {
const item = dict[name];

@@ -57,2 +57,3 @@ const fn = item.parse || item;

context: Object.create(null),
features: Object.assign(Object.create(null), config.features),
scope: Object.assign(Object.create(null), config.scope),

@@ -64,10 +65,10 @@ atrule: fetchParseValues(config.atrule),

for (const name in config.parseContext) {
switch (typeof config.parseContext[name]) {
for (const [name, context] of Object.entries(config.parseContext)) {
switch (typeof context) {
case 'function':
parseConfig.context[name] = config.parseContext[name];
parseConfig.context[name] = context;
break;
case 'string':
parseConfig.context[name] = createParseContext(config.parseContext[name]);
parseConfig.context[name] = createParseContext(context);
break;

@@ -128,3 +129,3 @@ }

parseWithFallback(consumer, fallback) {
const startToken = this.tokenIndex;
const startIndex = this.tokenIndex;

@@ -138,3 +139,4 @@ try {

const fallbackNode = fallback.call(this, startToken);
this.skip(startIndex - this.tokenIndex);
const fallbackNode = fallback.call(this);

@@ -154,3 +156,3 @@ onParseErrorThrow = true;

type = this.lookupType(offset++);
if (type !== WhiteSpace) {
if (type !== WhiteSpace && type !== Comment) {
return type;

@@ -293,3 +295,5 @@ }

location.line,
location.column
location.column,
locationMap.startLine,
locationMap.startColumn
);

@@ -296,0 +300,0 @@ }

@@ -7,3 +7,3 @@ import { createCustomError } from '../utils/create-custom-error.js';

function sourceFragment({ source, line, column }, extraLines) {
function sourceFragment({ source, line, column, baseLine, baseColumn }, extraLines) {
function processLines(start, end) {

@@ -17,3 +17,5 @@ return lines

const lines = source.split(/\r\n?|\n|\f/);
const prelines = '\n'.repeat(Math.max(baseLine - 1, 0));
const precolumns = ' '.repeat(Math.max(baseColumn - 1, 0));
const lines = (prelines + precolumns + source).split(/\r\n?|\n|\f/);
const startLine = Math.max(1, line - extraLines) - 1;

@@ -46,6 +48,9 @@ const endLine = Math.min(line + extraLines, lines.length + 1);

processLines(line, endLine)
].filter(Boolean).join('\n');
].filter(Boolean)
.join('\n')
.replace(/^(\s+\d+\s+\|\n)+/, '')
.replace(/\n(\s+\d+\s+\|)+$/, '');
}
export function SyntaxError(message, source, offset, line, column) {
export function SyntaxError(message, source, offset, line, column, baseLine = 1, baseColumn = 1) {
const error = Object.assign(createCustomError('SyntaxError', message), {

@@ -57,3 +62,3 @@ source,

sourceFragment(extraLines) {
return sourceFragment({ source, line, column }, isNaN(extraLines) ? 0 : extraLines);
return sourceFragment({ source, line, column, baseLine, baseColumn }, isNaN(extraLines) ? 0 : extraLines);
},

@@ -63,3 +68,3 @@ get formattedMessage() {

`Parse error: ${message}\n` +
sourceFragment({ source, line, column }, 2)
sourceFragment({ source, line, column, baseLine, baseColumn }, 2)
);

@@ -66,0 +71,0 @@ }

@@ -6,5 +6,53 @@ import {

Function as FunctionToken,
LeftParenthesis
LeftParenthesis,
RightParenthesis
} from '../../tokenizer/index.js';
function parseWithFallback(parse, fallback) {
return this.parseWithFallback(
() => {
try {
return parse.call(this);
} finally {
this.skipSC();
if (this.lookupNonWSType(0) !== RightParenthesis) {
this.error();
}
}
},
fallback || (() => this.Raw(null, true))
);
}
const parseFunctions = {
layer() {
this.skipSC();
const children = this.createList();
const node = parseWithFallback.call(this, this.Layer);
if (node.type !== 'Raw' || node.value !== '') {
children.push(node);
}
return children;
},
supports() {
this.skipSC();
const children = this.createList();
const node = parseWithFallback.call(
this,
this.Declaration,
() => parseWithFallback.call(this, () => this.Condition('supports'))
);
if (node.type !== 'Raw' || node.value !== '') {
children.push(node);
}
return children;
}
};
export default {

@@ -15,4 +63,2 @@ parse: {

this.skipSC();
switch (this.tokenType) {

@@ -32,2 +78,21 @@ case StringToken:

this.skipSC();
if (this.tokenType === Ident &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'layer')) {
children.push(this.Identifier());
} else if (
this.tokenType === FunctionToken &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'layer(')
) {
children.push(this.Function(null, parseFunctions));
}
this.skipSC();
if (this.tokenType === FunctionToken &&
this.cmpStr(this.tokenStart, this.tokenEnd, 'supports(')) {
children.push(this.Function(null, parseFunctions));
}
if (this.lookupNonWSType(0) === Ident ||

@@ -34,0 +99,0 @@ this.lookupNonWSType(0) === LeftParenthesis) {

@@ -0,15 +1,23 @@

import container from './container.js';
import fontFace from './font-face.js';
import importAtrule from './import.js';
import layer from './layer.js';
import media from './media.js';
import nest from './nest.js';
import page from './page.js';
import scope from './scope.js';
import startingStyle from './starting-style.js';
import supports from './supports.js';
export default {
container,
'font-face': fontFace,
'import': importAtrule,
import: importAtrule,
layer,
media,
nest,
page,
scope,
'starting-style': startingStyle,
supports
};

@@ -8,6 +8,6 @@ export default {

},
block(isStyleBlock = false) {
return this.Block(isStyleBlock);
block(nested = false) {
return this.Block(nested);
}
}
};

@@ -1,80 +0,12 @@

import {
WhiteSpace,
Comment,
Ident,
Function,
Colon,
LeftParenthesis
} from '../../tokenizer/index.js';
function consumeRaw() {
return this.createSingleNodeList(
this.Raw(this.tokenIndex, null, false)
);
}
function parentheses() {
this.skipSC();
if (this.tokenType === Ident &&
this.lookupNonWSType(1) === Colon) {
return this.createSingleNodeList(
this.Declaration()
);
}
return readSequence.call(this);
}
function readSequence() {
const children = this.createList();
let child;
this.skipSC();
scan:
while (!this.eof) {
switch (this.tokenType) {
case Comment:
case WhiteSpace:
this.next();
continue;
case Function:
child = this.Function(consumeRaw, this.scope.AtrulePrelude);
break;
case Ident:
child = this.Identifier();
break;
case LeftParenthesis:
child = this.Parentheses(parentheses, this.scope.AtrulePrelude);
break;
default:
break scan;
}
children.push(child);
}
return children;
}
export default {
parse: {
prelude() {
const children = readSequence.call(this);
if (this.getFirstListNode(children) === null) {
this.error('Condition is expected');
}
return children;
return this.createSingleNodeList(
this.Condition('supports')
);
},
block(isStyleBlock = false) {
return this.Block(isStyleBlock);
block(nested = false) {
return this.Block(nested);
}
}
};

@@ -85,2 +85,3 @@ function appendOrSet(a, b) {

case 'scope':
case 'features':
result[prop] = { ...dest[prop] };

@@ -103,3 +104,4 @@ for (const [name, props] of Object.entries(value)) {

...dest[prop],
...sliceProps(value, ['parse']) };
...sliceProps(value, ['parse'])
};
break;

@@ -106,0 +108,0 @@

@@ -16,2 +16,5 @@ import * as scope from '../scope/index.js';

mediaQuery: 'MediaQuery',
condition(options) {
return this.Condition(options.kind);
},
rule: 'Rule',

@@ -27,2 +30,14 @@ selectorList: 'SelectorList',

},
features: {
supports: {
selector() {
return this.Selector();
}
},
container: {
style() {
return this.Declaration();
}
}
},
scope,

@@ -29,0 +44,0 @@ atrule,

@@ -43,3 +43,3 @@ import { tokenize } from '../tokenizer/index.js';

syntax.lexer = new Lexer({
generic: true,
generic: config.generic,
units: config.units,

@@ -46,0 +46,0 @@ types: config.types,

@@ -5,4 +5,4 @@ // legacy IE function

return this.createSingleNodeList(
this.Raw(this.tokenIndex, null, false)
this.Raw(null, false)
);
}

@@ -20,3 +20,3 @@ import { Comma, WhiteSpace } from '../../tokenizer/index.js';

? this.Value(null)
: this.Raw(this.tokenIndex, this.consumeUntilExclamationMarkOrSemicolon, false);
: this.Raw(this.consumeUntilExclamationMarkOrSemicolon, false);

@@ -23,0 +23,0 @@ if (value.type === 'Value' && value.children.isEmpty) {

@@ -8,4 +8,4 @@ import {

function consumeRaw(startToken) {
return this.Raw(startToken, this.consumeUntilLeftCurlyBracketOrSemicolon, true);
function consumeRaw() {
return this.Raw(this.consumeUntilLeftCurlyBracketOrSemicolon, true);
}

@@ -69,2 +69,4 @@

case LeftCurlyBracket:
this.eat(LeftCurlyBracket);
if (hasOwnProperty.call(this.atrule, nameLowerCase) &&

@@ -78,2 +80,6 @@ typeof this.atrule[nameLowerCase].block === 'function') {

if (!this.eof) {
this.eat(RightCurlyBracket);
}
break;

@@ -99,3 +105,5 @@ }

if (node.block) {
this.token(LeftCurlyBracket, '{');
this.node(node.block);
this.token(RightCurlyBracket, '}');
} else {

@@ -102,0 +110,0 @@ this.token(Semicolon, ';');

@@ -6,3 +6,2 @@ import {

AtKeyword,
LeftCurlyBracket,
RightCurlyBracket

@@ -13,4 +12,4 @@ } from '../../tokenizer/index.js';

function consumeRaw(startToken) {
return this.Raw(startToken, null, true);
function consumeRaw() {
return this.Raw(null, true);
}

@@ -20,4 +19,4 @@ function consumeRule() {

}
function consumeRawDeclaration(startToken) {
return this.Raw(startToken, this.consumeUntilSemicolonIncluded, true);
function consumeRawDeclaration() {
return this.Raw(this.consumeUntilSemicolonIncluded, true);
}

@@ -53,4 +52,2 @@ function consumeDeclaration() {

this.eat(LeftCurlyBracket);
scan:

@@ -80,6 +77,2 @@ while (!this.eof) {

if (!this.eof) {
this.eat(RightCurlyBracket);
}
return {

@@ -93,3 +86,2 @@ type: 'Block',

export function generate(node) {
this.token(LeftCurlyBracket, '{');
this.children(node, prev => {

@@ -100,3 +92,2 @@ if (prev.type === 'Declaration') {

});
this.token(RightCurlyBracket, '}');
}

@@ -19,8 +19,8 @@ import { isCustomProperty } from '../../utils/names.js';

function consumeValueRaw(startToken) {
return this.Raw(startToken, this.consumeUntilExclamationMarkOrSemicolon, true);
function consumeValueRaw() {
return this.Raw(this.consumeUntilExclamationMarkOrSemicolon, true);
}
function consumeCustomPropertyRaw(startToken) {
return this.Raw(startToken, this.consumeUntilExclamationMarkOrSemicolon, false);
function consumeCustomPropertyRaw() {
return this.Raw(this.consumeUntilExclamationMarkOrSemicolon, false);
}

@@ -27,0 +27,0 @@

@@ -10,4 +10,4 @@ import {

function consumeRaw(startToken) {
return this.Raw(startToken, this.consumeUntilSemicolonIncluded, true);
function consumeRaw() {
return this.Raw(this.consumeUntilSemicolonIncluded, true);
}

@@ -14,0 +14,0 @@

@@ -12,10 +12,16 @@ export { generate as AnPlusB } from './AnPlusB.js';

export { generate as Comment } from './Comment.js';
export { generate as Condition } from './Condition.js';
export { generate as Declaration } from './Declaration.js';
export { generate as DeclarationList } from './DeclarationList.js';
export { generate as Dimension } from './Dimension.js';
export { generate as Feature } from './Feature.js';
export { generate as FeatureFunction } from './FeatureFunction.js';
export { generate as FeatureRange } from './FeatureRange.js';
export { generate as Function } from './Function.js';
export { generate as GeneralEnclosed } from './GeneralEnclosed.js';
export { generate as Hash } from './Hash.js';
export { generate as Identifier } from './Identifier.js';
export { generate as IdSelector } from './IdSelector.js';
export { generate as MediaFeature } from './MediaFeature.js';
export { generate as Layer } from './Layer.js';
export { generate as LayerList } from './LayerList.js';
export { generate as MediaQuery } from './MediaQuery.js';

@@ -34,2 +40,3 @@ export { generate as MediaQueryList } from './MediaQueryList.js';

export { generate as Rule } from './Rule.js';
export { generate as Scope } from './Scope.js';
export { generate as Selector } from './Selector.js';

@@ -39,2 +46,3 @@ export { generate as SelectorList } from './SelectorList.js';

export { generate as StyleSheet } from './StyleSheet.js';
export { generate as SupportsDeclaration } from './SupportsDeclaration.js';
export { generate as TypeSelector } from './TypeSelector.js';

@@ -41,0 +49,0 @@ export { generate as UnicodeRange } from './UnicodeRange.js';

@@ -9,2 +9,3 @@ export { parse as AnPlusB } from './AnPlusB.js';

export { parse as Nth } from './Nth.js';
export { parse as Operator } from './Operator.js';
export { parse as Percentage } from './Percentage.js';

@@ -11,0 +12,0 @@ export { parse as PseudoClassSelector } from './PseudoClassSelector.js';

@@ -12,10 +12,16 @@ export { parse as AnPlusB } from './AnPlusB.js';

export { parse as Comment } from './Comment.js';
export { parse as Condition } from './Condition.js';
export { parse as Declaration } from './Declaration.js';
export { parse as DeclarationList } from './DeclarationList.js';
export { parse as Dimension } from './Dimension.js';
export { parse as Feature } from './Feature.js';
export { parse as FeatureFunction } from './FeatureFunction.js';
export { parse as FeatureRange } from './FeatureRange.js';
export { parse as Function } from './Function.js';
export { parse as GeneralEnclosed } from './GeneralEnclosed.js';
export { parse as Hash } from './Hash.js';
export { parse as Identifier } from './Identifier.js';
export { parse as IdSelector } from './IdSelector.js';
export { parse as MediaFeature } from './MediaFeature.js';
export { parse as Layer } from './Layer.js';
export { parse as LayerList } from './LayerList.js';
export { parse as MediaQuery } from './MediaQuery.js';

@@ -34,2 +40,3 @@ export { parse as MediaQueryList } from './MediaQueryList.js';

export { parse as Rule } from './Rule.js';
export { parse as Scope } from './Scope.js';
export { parse as Selector } from './Selector.js';

@@ -39,2 +46,3 @@ export { parse as SelectorList } from './SelectorList.js';

export { parse as StyleSheet } from './StyleSheet.js';
export { parse as SupportsDeclaration } from './SupportsDeclaration.js';
export { parse as TypeSelector } from './TypeSelector.js';

@@ -41,0 +49,0 @@ export { parse as UnicodeRange } from './UnicodeRange.js';

@@ -12,10 +12,16 @@ export * as AnPlusB from './AnPlusB.js';

export * as Comment from './Comment.js';
export * as Condition from './Condition.js';
export * as Declaration from './Declaration.js';
export * as DeclarationList from './DeclarationList.js';
export * as Dimension from './Dimension.js';
export * as Feature from './Feature.js';
export * as FeatureFunction from './FeatureFunction.js';
export * as FeatureRange from './FeatureRange.js';
export * as Function from './Function.js';
export * as GeneralEnclosed from './GeneralEnclosed.js';
export * as Hash from './Hash.js';
export * as Identifier from './Identifier.js';
export * as IdSelector from './IdSelector.js';
export * as MediaFeature from './MediaFeature.js';
export * as Layer from './Layer.js';
export * as LayerList from './LayerList.js';
export * as MediaQuery from './MediaQuery.js';

@@ -34,2 +40,3 @@ export * as MediaQueryList from './MediaQueryList.js';

export * as Rule from './Rule.js';
export * as Scope from './Scope.js';
export * as Selector from './Selector.js';

@@ -39,2 +46,3 @@ export * as SelectorList from './SelectorList.js';

export * as StyleSheet from './StyleSheet.js';
export * as SupportsDeclaration from './SupportsDeclaration.js';
export * as TypeSelector from './TypeSelector.js';

@@ -41,0 +49,0 @@ export * as UnicodeRange from './UnicodeRange.js';

import {
WhiteSpace,
Comment,
Comma,
EOF,
Ident,
LeftParenthesis
LeftCurlyBracket,
LeftParenthesis,
Function as FunctionToken,
Semicolon
} from '../../tokenizer/index.js';

@@ -10,40 +13,64 @@

export const structure = {
children: [[
'Identifier',
'MediaFeature',
'WhiteSpace'
]]
modifier: [String, null],
mediaType: [String, null],
condition: ['Condition', null]
};
export function parse() {
const children = this.createList();
let child = null;
const start = this.tokenStart;
let modifier = null;
let mediaType = null;
let condition = null;
this.skipSC();
scan:
while (!this.eof) {
switch (this.tokenType) {
case Comment:
case WhiteSpace:
this.next();
continue;
if (this.tokenType === Ident && this.lookupTypeNonSC(1) !== LeftParenthesis) {
// [ not | only ]? <media-type>
const ident = this.consume(Ident);
const identLowerCase = ident.toLowerCase();
case Ident:
child = this.Identifier();
if (identLowerCase === 'not' || identLowerCase === 'only') {
this.skipSC();
modifier = identLowerCase;
mediaType = this.consume(Ident);
} else {
mediaType = ident;
}
switch (this.lookupTypeNonSC(0)) {
case Ident: {
// and <media-condition-without-or>
this.skipSC();
this.eatIdent('and');
condition = this.Condition('media');
break;
}
case LeftParenthesis:
child = this.MediaFeature();
case LeftCurlyBracket:
case Semicolon:
case Comma:
case EOF:
break;
default:
break scan;
this.error('Identifier or parenthesis is expected');
}
} else {
switch (this.tokenType) {
case Ident:
case LeftParenthesis:
case FunctionToken: {
// <media-condition>
condition = this.Condition('media');
break;
}
children.push(child);
}
case LeftCurlyBracket:
case Semicolon:
case EOF:
break;
if (child === null) {
this.error('Identifier or parenthesis is expected');
default:
this.error('Identifier or parenthesis is expected');
}
}

@@ -53,4 +80,6 @@

type: 'MediaQuery',
loc: this.getLocationFromList(children),
children
loc: this.getLocation(start, this.tokenStart),
modifier,
mediaType,
condition
};

@@ -60,4 +89,17 @@ }

export function generate(node) {
this.children(node);
if (node.mediaType) {
if (node.modifier) {
this.token(Ident, node.modifier);
}
this.token(Ident, node.mediaType);
if (node.condition) {
this.token(Ident, 'and');
this.node(node.condition);
}
} else if (node.condition) {
this.node(node.condition);
}
}

@@ -29,3 +29,5 @@ import {

if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
if (this.lookupNonWSType(0) == RightParenthesis) {
children = this.createList();
} else if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
this.skipSC();

@@ -37,3 +39,3 @@ children = this.pseudo[nameLowerCase].call(this);

children.push(
this.Raw(this.tokenIndex, null, false)
this.Raw(null, false)
);

@@ -40,0 +42,0 @@ }

@@ -29,3 +29,5 @@ import {

if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
if (this.lookupNonWSType(0) == RightParenthesis) {
children = this.createList();
} else if (hasOwnProperty.call(this.pseudo, nameLowerCase)) {
this.skipSC();

@@ -37,3 +39,3 @@ children = this.pseudo[nameLowerCase].call(this);

children.push(
this.Raw(this.tokenIndex, null, false)
this.Raw(null, false)
);

@@ -40,0 +42,0 @@ }

@@ -1,29 +0,32 @@

import { isDigit, Delim, Number as NumberToken } from '../../tokenizer/index.js';
import {
Delim,
Number as NumberToken,
Function as FunctionToken
} from '../../tokenizer/index.js';
const SOLIDUS = 0x002F; // U+002F SOLIDUS (/)
const FULLSTOP = 0x002E; // U+002E FULL STOP (.)
// Terms of <ratio> should be a positive numbers (not zero or negative)
// (see https://drafts.csswg.org/mediaqueries-3/#values)
// However, -o-min-device-pixel-ratio takes fractional values as a ratio's term
// and this is using by various sites. Therefore we relax checking on parse
// to test a term is unsigned number without an exponent part.
// Additional checking may be applied on lexer validation.
function consumeNumber() {
// Media Queries Level 3 defines terms of <ratio> as a positive (not zero or negative)
// integers (see https://drafts.csswg.org/mediaqueries-3/#values)
// However, Media Queries Level 4 removes any definition of values
// (see https://drafts.csswg.org/mediaqueries-4/#values) and refers to
// CSS Values and Units for detail. In CSS Values and Units Level 4 a <ratio>
// definition was added (see https://drafts.csswg.org/css-values-4/#ratios) which
// defines ratio as "<number [0,∞]> [ / <number [0,∞]> ]?" and based on it
// any constrains on terms were removed. Parser also doesn't test numbers
// in any way to make possible for linting and fixing them by the tools using CSSTree.
// An additional syntax examination may be applied by a lexer.
function consumeTerm() {
this.skipSC();
const value = this.consume(NumberToken);
switch (this.tokenType) {
case NumberToken:
return this.Number();
for (let i = 0; i < value.length; i++) {
const code = value.charCodeAt(i);
if (!isDigit(code) && code !== FULLSTOP) {
this.error('Unsigned number is expected', this.tokenStart - value.length + i);
}
}
case FunctionToken:
return this.Function(this.readSequence, this.scope.Value);
if (Number(value) === 0) {
this.error('Zero number is not allowed', this.tokenStart - value.length);
default:
this.error('Number of function is expected');
}
return value;
}

@@ -33,15 +36,17 @@

export const structure = {
left: String,
right: String
left: ['Number', 'Function'],
right: ['Number', 'Function', null]
};
// <positive-integer> S* '/' S* <positive-integer>
// <number [0,∞]> [ / <number [0,∞]> ]?
export function parse() {
const start = this.tokenStart;
const left = consumeNumber.call(this);
let right;
const left = consumeTerm.call(this);
let right = null;
this.skipSC();
this.eatDelim(SOLIDUS);
right = consumeNumber.call(this);
if (this.isDelim(SOLIDUS)) {
this.eatDelim(SOLIDUS);
right = consumeTerm.call(this);
}

@@ -57,5 +62,9 @@ return {

export function generate(node) {
this.token(NumberToken, node.left);
this.node(node.left);
this.token(Delim, '/');
this.token(NumberToken, node.right);
if (node.right) {
this.node(node.right);
} else {
this.node(NumberToken, 1);
}
}

@@ -20,7 +20,7 @@ import { WhiteSpace } from '../../tokenizer/index.js';

export function parse(startToken, consumeUntil, excludeWhiteSpace) {
const startOffset = this.getTokenStart(startToken);
export function parse(consumeUntil, excludeWhiteSpace) {
const startOffset = this.getTokenStart(this.tokenIndex);
let endOffset;
this.skipUntilBalanced(startToken, consumeUntil || this.consumeUntilBalanceEnd);
this.skipUntilBalanced(this.tokenIndex, consumeUntil || this.consumeUntilBalanceEnd);

@@ -27,0 +27,0 @@ if (excludeWhiteSpace && this.tokenStart > startOffset) {

@@ -1,5 +0,5 @@

import { LeftCurlyBracket } from '../../tokenizer/index.js';
import { LeftCurlyBracket, RightCurlyBracket } from '../../tokenizer/index.js';
function consumeRaw(startToken) {
return this.Raw(startToken, this.consumeUntilLeftCurlyBracket, true);
function consumeRaw() {
return this.Raw(this.consumeUntilLeftCurlyBracket, true);
}

@@ -38,4 +38,11 @@

this.skipSC();
this.eat(LeftCurlyBracket);
block = this.Block(true);
if (!this.eof) {
this.eat(RightCurlyBracket);
}
return {

@@ -50,4 +57,6 @@ type: 'Rule',

this.node(node.prelude);
this.token(LeftCurlyBracket, '{');
this.node(node.block);
this.token(RightCurlyBracket, '}');
}

@@ -10,4 +10,3 @@ export const name = 'Selector';

'PseudoElementSelector',
'Combinator',
'WhiteSpace'
'Combinator'
]]

@@ -14,0 +13,0 @@ };

@@ -11,4 +11,4 @@ import {

function consumeRaw(startToken) {
return this.Raw(startToken, null, false);
function consumeRaw() {
return this.Raw(null, false);
}

@@ -15,0 +15,0 @@

@@ -0,1 +1,3 @@

import { parseLanguageRangeList } from './lang.js';
const selectorList = {

@@ -25,2 +27,6 @@ parse() {

const langList = {
parse: parseLanguageRangeList
};
const nth = {

@@ -37,3 +43,3 @@ parse() {

'has': selectorList,
'lang': identList,
'lang': langList,
'matches': selectorList,

@@ -40,0 +46,0 @@ 'is': selectorList,

@@ -43,2 +43,7 @@ const EOF = 0;

// A code point with a value equal to or greater than U+0080 <control>.
//
// 2024-09-02: The latest spec narrows the range for non-ASCII characters (see https://github.com/csstree/csstree/issues/188).
// However, all modern browsers support a wider range, and strictly following the latest spec could result
// in some CSS being parsed incorrectly, even though it works in the browser. Therefore, this function adheres
// to the previous, broader definition of non-ASCII characters.
export function isNonAscii(code) {

@@ -45,0 +50,0 @@ return code >= 0x0080;

@@ -26,3 +26,4 @@ export default [

'{-token',
'}-token'
'}-token',
'comment-token'
];

@@ -118,2 +118,15 @@ import { adoptBuffer } from './adopt-buffer.js';

}
lookupTypeNonSC(idx) {
for (let offset = this.tokenIndex; offset < this.tokenCount; offset++) {
const tokenType = this.offsetAndType[offset] >> TYPE_SHIFT;
if (tokenType !== WhiteSpace && tokenType !== Comment) {
if (idx-- === 0) {
return tokenType;
}
}
}
return EOF;
}
lookupOffset(offset) {

@@ -128,2 +141,15 @@ offset += this.tokenIndex;

}
lookupOffsetNonSC(idx) {
for (let offset = this.tokenIndex; offset < this.tokenCount; offset++) {
const tokenType = this.offsetAndType[offset] >> TYPE_SHIFT;
if (tokenType !== WhiteSpace && tokenType !== Comment) {
if (idx-- === 0) {
return offset - this.tokenIndex;
}
}
}
return EOF;
}
lookupValue(offset, referenceStr) {

@@ -130,0 +156,0 @@ offset += this.tokenIndex;

@@ -6,3 +6,3 @@ import { List } from './List.js';

for (const key in node) {
for (const key of Object.keys(node)) {
let value = node[key];

@@ -9,0 +9,0 @@

{
"name": "css-tree",
"version": "2.3.1",
"version": "3.0.0",
"description": "A tool set for CSS: fast detailed parser (CSS → AST), walker (AST traversal), generator (AST → CSS) and lexer (validation and matching) based on specs and browser implementations",

@@ -95,11 +95,10 @@ "author": "Roman Dvornov <rdvornov@gmail.com> (https://github.com/lahmatiy)",

"review:syntax-patch": "node scripts/review-syntax-patch",
"test": "mocha lib/__tests --reporter ${REPORTER:-progress}",
"test:cjs": "mocha cjs/__tests --reporter ${REPORTER:-progress}",
"test:dist": "mocha dist/__tests --reporter ${REPORTER:-progress}",
"test": "mocha lib/__tests --require lib/__tests/helpers/setup.js --reporter progress",
"test:cjs": "mocha cjs/__tests --require lib/__tests/helpers/setup.js --reporter progress",
"test:dist": "mocha dist/__tests --reporter progress",
"coverage": "c8 --exclude lib/__tests --reporter=lcovonly npm test",
"prepublishOnly": "npm run lint-and-test && npm run build-and-test",
"hydrogen": "node --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces --redirect-code-traces-to=code.asm --trace_hydrogen_file=code.cfg --print-opt-code bin/parse --stat -o /dev/null"
"prepublishOnly": "npm run lint-and-test && npm run build-and-test"
},
"dependencies": {
"mdn-data": "2.0.30",
"mdn-data": "2.10.0",
"source-map-js": "^1.0.1"

@@ -106,0 +105,0 @@ },

@@ -1,4 +0,2 @@

<img align="right" width="111" height="111"
alt="CSSTree logo"
src="https://cloud.githubusercontent.com/assets/270491/19243723/6f9136c6-8f21-11e6-82ac-eeeee4c6c452.png"/>
<img align="right" width="111" height="111" alt="CSSTree logo" src="assets/csstree-logo-rounded.svg" />

@@ -5,0 +3,0 @@ # CSSTree

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is too big to display

Sorry, the diff of this file is not supported yet

Sorry, the diff of this file is not supported yet

SocketSocket SOC 2 Logo

Product

  • Package Alerts
  • Integrations
  • Docs
  • Pricing
  • FAQ
  • Roadmap
  • Changelog

Packages

npm

Stay in touch

Get open source security insights delivered straight into your inbox.


  • Terms
  • Privacy
  • Security

Made with ⚡️ by Socket Inc