pax_global_header00006660000000000000000000000064150327234500014513gustar00rootroot0000000000000052 comment=e814dd46909f60eadde80726ebaafe306b43a03a css-1.3.0/000077500000000000000000000000001503272345000123045ustar00rootroot00000000000000css-1.3.0/.gitignore000066400000000000000000000000531503272345000142720ustar00rootroot00000000000000/node_modules/ /src/parser.* .tern-* /dist css-1.3.0/.npmignore000066400000000000000000000000161503272345000143000ustar00rootroot00000000000000/node_modules css-1.3.0/CHANGELOG.md000066400000000000000000000114471503272345000141240ustar00rootroot00000000000000## 1.3.0 (2025-07-07) ### Bug fixes Values wrapped in brackets can now contain more types of tokens. Properly support hex escapes in identifiers. Support variable names as callees in call expressions. ### New features Add support for `@scope` syntax. Add support for `if` notation. ## 1.2.1 (2025-05-15) ### Bug fixes Fix parsing of `*` selectors in descendant positions. ## 1.2.0 (2025-05-12) ### Bug fixes Allow @ keywords to start with a dash, since prefixed ones exist. Bump the dependency on @lezer/lr to a version that supports local token groups. Also bump @lezer/generator dependency ### New features Add support for range queries. `@import` statements now support `layer` syntax. Support relative versions of the `+`, `>`, and `~` selectors, which omit the left-hand selector. Allow @-keywords to start with a dash ## 1.1.11 (2025-03-24) ### Bug fixes Accept trailing commas in argument lists. ## 1.1.10 (2025-01-24) ### Bug fixes Emit a node for class selector dots. ## 1.1.9 (2024-09-10) ### Bug fixes Allow `url()` values to be empty. Don't generate a parse error when declarations don't have a value. ## 1.1.8 (2024-02-19) ### Bug fixes Follow the standard, allowing digits in unit identifiers. ## 1.1.7 (2024-01-08) ### Bug fixes Correctly parse properties with a space before the colon. ## 1.1.6 (2024-01-01) ### Bug fixes Add support for bracketed grid line names. ## 1.1.5 (2023-12-28) ### Bug fixes Tag comments and strings as isolating for the purpose of bidirectional text. ## 1.1.4 (2023-11-09) ### Bug fixes Fix parsing of `&` selectors in descendant selectors. Allow identifiers to contain backslash escapes. ## 1.1.3 (2023-07-03) ### Bug fixes Comments are now parsed to end of file if no closing `*/` is found. Make the package work with new TS resolution styles. ## 1.1.2 (2023-05-15) ### Bug fixes Make keyframe selector parsing more flexible to support timeline ranges. Allow multiple comma-separated keyframe selectors per keyframe. ## 1.1.1 (2022-12-02) ### Bug fixes The `Styles` top rule now also recognizes nested rules. ## 1.1.0 (2022-11-25) ### Bug fixes Don't emit an error node when the input is empty. Export a Styles top-level rule for parsing lists of properties ### New features The new `Styles` top-level rule can be used to parse semicolon-separated lists of properties. ## 1.0.1 (2022-10-10) ### Bug fixes Add support for the `is`, `where`, `host-context`, `nth-last-of-type`, and `nth-of-type` pseudo classes. Apply a consistent highlighting tag (`definitionKeyword`) to all @ keywords. ## 1.0.0 (2022-06-06) ### New features First stable version. ## 0.16.0 (2022-04-20) ### Breaking changes Move to 0.16 serialized parser format. ### New features The parser now includes syntax highlighting information in its node types. ## 0.15.2 (2021-09-24) ### Bug fixes Distinguish between variable names and other names. Fix the name of nodes for the `selector` keyword (which by accident was `callee` before). ## 0.15.1 (2021-08-31) ### Bug fixes Fix parsing of selector arguments to pseudo selectors. ## 0.15.0 (2021-08-11) ### Breaking changes The module's name changed from `lezer-css` to `@lezer/css`. Upgrade to the 0.15.0 lezer interfaces. ## 0.13.1 (2020-12-04) ### Bug fixes Fix versions of lezer packages depended on. ## 0.13.0 (2020-12-04) ## 0.12.0 (2020-10-23) ### Breaking changes Adjust to changed serialized parser format. ## 0.11.1 (2020-09-26) ### Bug fixes Fix lezer depencency versions ## 0.11.0 (2020-09-26) ### Breaking changes Follow change in serialized parser format. ## 0.10.1 (2020-09-02) ### Bug fixes Fix a conflicting pair of tokens that the generator previously didn't catch. ## 0.10.0 (2020-08-07) ### Breaking changes Upgrade to 0.10 parser serialization ## 0.9.0 (2020-06-08) ### Breaking changes Upgrade to 0.9 parser serialization ## 0.8.3 (2020-04-09) ### Bug fixes Regenerate parser with a fix in lezer-generator so that the top node prop is properly assigned. ## 0.8.2 (2020-04-01) ### Bug fixes Make the package load as an ES module on node ## 0.8.1 (2020-02-28) ### New features Provide an ES module file. ## 0.8.0 (2020-02-03) ### New features Follow 0.8.0 release of the library. ## 0.7.0 (2020-01-20) ### Breaking changes Use the lezer 0.7.0 parser format. ## 0.5.2 (2020-01-15) ### Bug fixes Regenerate with lezer-generator 0.5.2 to avoid cyclic forced reductions. ## 0.5.1 (2019-10-22) ### Bug fixes Fix top prop missing from build output. ## 0.5.0 (2019-10-22) ### Breaking changes Move from `lang` to `top` prop on document node. ## 0.4.0 (2019-09-10) ### Breaking changes Adjust to 0.4.0 parse table format. ## 0.3.0 (2019-08-22) ### New features Go back to node names, add props, follow changes in grammar syntax. ## 0.2.0 (2019-08-02) ### New Features First documented release. css-1.3.0/LICENSE000066400000000000000000000021311503272345000133060ustar00rootroot00000000000000MIT License Copyright (C) 2018 by Marijn Haverbeke and others Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. css-1.3.0/README.md000066400000000000000000000002161503272345000135620ustar00rootroot00000000000000# @lezer/css This is a CSS grammar for the [lezer](https://lezer.codemirror.net/) parser system. The code is licensed under an MIT license. css-1.3.0/dist/000077500000000000000000000000001503272345000132475ustar00rootroot00000000000000css-1.3.0/dist/index.d.cts000066400000000000000000000001021503272345000153040ustar00rootroot00000000000000import {LRParser} from "@lezer/lr" export const parser: LRParser css-1.3.0/dist/index.d.ts000066400000000000000000000001021503272345000151410ustar00rootroot00000000000000import {LRParser} from "@lezer/lr" export const parser: LRParser css-1.3.0/package.json000066400000000000000000000017301503272345000145730ustar00rootroot00000000000000{ "name": "@lezer/css", "version": "1.3.0", "description": "lezer-based CSS grammar", "main": "dist/index.cjs", "type": "module", "exports": { "import": "./dist/index.js", "require": "./dist/index.cjs" }, "module": "dist/index.js", "types": "dist/index.d.ts", "author": "Marijn Haverbeke ", "license": "MIT", "devDependencies": { "@lezer/generator": "^1.8.0", "mocha": "^10.2.0", "rollup": "^2.52.2", "@rollup/plugin-node-resolve": "^9.0.0" }, "dependencies": { "@lezer/common": "^1.2.0", "@lezer/lr": "^1.3.0", "@lezer/highlight": "^1.0.0" }, "repository": { "type" : "git", "url" : "https://github.com/lezer-parser/css.git" }, "scripts": { "build": "lezer-generator src/css.grammar -o src/parser && rollup -c", "build-debug": "lezer-generator src/css.grammar --names -o src/parser && rollup -c", "prepare": "npm run build", "test": "mocha test/test-*.js" } } css-1.3.0/rollup.config.js000066400000000000000000000004621503272345000154250ustar00rootroot00000000000000import {nodeResolve} from "@rollup/plugin-node-resolve" export default { input: "./src/parser.js", output: [{ format: "cjs", file: "./dist/index.cjs" }, { format: "es", file: "./dist/index.js" }], external(id) { return !/^[\.\/]/.test(id) }, plugins: [ nodeResolve() ] } css-1.3.0/src/000077500000000000000000000000001503272345000130735ustar00rootroot00000000000000css-1.3.0/src/css.grammar000066400000000000000000000136051503272345000152400ustar00rootroot00000000000000@precedence { attribute @left, structure @left, call, valueCompareOp, valueOp @left, layerName } @skip { whitespace | Comment } @top StyleSheet { item* } @top Styles { blockContent } item { RuleSet | ImportStatement | MediaStatement | CharsetStatement | NamespaceStatement | KeyframesStatement | SupportsStatement | ScopeStatement | AtRule } RuleSet { selector ("," selector)* Block } ImportStatement { atKw<"import"> value Layer { queryCalleeKw<"layer"> (!layerName "(" LayerName ("." LayerName)* ")")? | queryKw<"layer"> }? commaSep ";" } LayerName { identifier } MediaStatement { atKw<"media"> commaSep Block } CharsetStatement { atKw<"charset"> value ";" } NamespaceStatement { atKw<"namespace"> NamespaceName { identifier }? (StringLiteral | CallLiteral) ";" } KeyframesStatement { atKw<"keyframes"> KeyframeName { identifier | StringLiteral } KeyframeList } KeyframeSelector { KeyframeRangeName { identifier } NumberLiteral? | NumberLiteral } KeyframeList { "{" (KeyframeSelector ("," KeyframeSelector)* Block)* "}" } SupportsStatement { atKw<"supports"> query Block } ScopeStatement { atKw<"scope"> ParenthesizedSelector? (@extend[@name=to] ParenthesizedSelector)? Block } AtRule { AtKeyword commaSep (";" | Block) } Block { "{" blockContent "}" } blockContent { ~item item* (Declaration (";" ~item item* Declaration?)*)? } selector { UniversalSelector | TagSelector { ~item TagName { identifier ~item } } | NestingSelector | ClassSelector { selector? !attribute "." ClassName { identifier } } | PseudoClassSelector { selector? !attribute (":" | "::") ( PseudoClassName { identifier } | pseudoClassWithArg ArgList | PseudoClassName { callee } ArgList) } | IdSelector { selector? !attribute "#" IdName { identifier } } | AttributeSelector { selector? !attribute "[" AttributeName { identifier } (MatchOp value)? "]" } | ChildSelector { selector? !structure ChildOp selector } | DescendantSelector { selector !structure descendantOp selector } | SiblingSelector { selector? !structure SiblingOp selector } } pseudoClassWithArg { @specialize[@name=PseudoClassName] } NumberLiteral { numberLiteralInner Unit? } ArgList { "(" commaSep ")" } Declaration { (PropertyName { identifier ~item } | VariableName) ":" (value (","? value)*)? Important? } query { KeywordQuery { queryIdentifier } | FeatureQuery { "(" FeatureName ":" value+ ")" } | BinaryQuery { query !valueOp @specialize[@name=LogicOp] query } | ComparisonQuery { "(" (queryValue | FeatureName) !valueCompareOp CompareOp (queryValue | FeatureName) (!valueCompareOp CompareOp (queryValue | FeatureName))? ")" } | UnaryQuery { @specialize[@name=UnaryQueryOp] query } | ParenthesizedQuery { "(" query ")" } | SelectorQuery { queryCalleeKw<"selector"> ParenthesizedSelector } | CallQuery { QueryCallee ArgList } } ParenthesizedSelector { "(" selector ")" } FeatureName { queryIdentifier } value { VariableName | ValueName { identifier } | ParenthesizedValue { "(" token* ")" } | BracketedValue { "[" token* "]" } | BracedValue { "{" token* "}" } | ColorLiteral | NumberLiteral | StringLiteral | BinaryExpression { value !valueOp BinOp value } | CallExpression | IfExpression | CallLiteral } token { value | AtKeyword | "#" | ";" | "." | ":" } queryValue { queryVariableName | ColorLiteral | NumberLiteral | StringLiteral } IfExpression { @specialize[@name=if] ArgList { "(" (IfBranch ";")* IfBranch ";"? ")" } } IfBranch { query ":" value } CallLiteral { @specialize[@name=CallTag] "(" (ParenthesizedContent | StringLiteral)? ")" } CallExpression { (Callee { callee } | VariableName) !call ArgList } @skip {} { Comment[isolate] { "/*" (commentContent | commentLineBreak)* commentEnd } } @local tokens { commentEnd { "*/" | @eof } commentLineBreak { "\n" } @else commentContent } commaSep { "" | value ("," value?)* } queryKw { @specialize[@name={name}] } queryCalleeKw { @specialize[@name={name}] } atKw { @specialize[@name={name}] } @external tokens descendant from "./tokens" { descendantOp } @external tokens unitToken from "./tokens" { Unit } @external tokens identifiers from "./tokens" { identifier, callee, VariableName } @external tokens queryIdentifiers from "./tokens" { @conflict { identifier, VariableName, callee } queryIdentifier, queryVariableName[@name=VariableName], QueryCallee } @tokens { UniversalSelector { "*" } NestingSelector { "&" } AtKeyword { "@" "-"? @asciiLetter (@asciiLetter | @digit | "-")* } MatchOp { $[~^|*$]? "=" } ChildOp { ">" ">"? } CompareOp { $[<>] "="? | "=" } SiblingOp { "~" | "+" } BinOp { $[+\-*/] } Important { "!important" } whitespace { @whitespace+ } hexDigit { @digit | $[a-fA-F] } ParenthesizedContent { !['")] ![)]+ } @precedence { whitespace, ParenthesizedContent, "/*" } ColorLiteral { "#" hexDigit hexDigit hexDigit (hexDigit (hexDigit hexDigit (hexDigit hexDigit)?)?)? } numberLiteralInner { ("+" | "-")? (@digit+ ("." @digit*)? | "." @digit+) (("e" | "E") ("+" | "-")? @digit+)? } @precedence { numberLiteralInner, BinOp, SiblingOp } @precedence { numberLiteralInner, "." } StringLiteral[isolate] { "\"" (!["\n\\] | "\\" _)* "\"" | "'" (!['\n\\] | "\\" _)* "'" } "#" "." ":" "::" ";" "," "(" ")" "[" "]" "{" "}" } @external propSource cssHighlighting from "./highlight" @detectDelim css-1.3.0/src/highlight.js000066400000000000000000000022071503272345000154010ustar00rootroot00000000000000import {styleTags, tags as t} from "@lezer/highlight" export const cssHighlighting = styleTags({ "AtKeyword import charset namespace keyframes media supports": t.definitionKeyword, "from to selector": t.keyword, NamespaceName: t.namespace, KeyframeName: t.labelName, KeyframeRangeName: t.operatorKeyword, TagName: t.tagName, ClassName: t.className, PseudoClassName: t.constant(t.className), IdName: t.labelName, "FeatureName PropertyName": t.propertyName, AttributeName: t.attributeName, NumberLiteral: t.number, KeywordQuery: t.keyword, UnaryQueryOp: t.operatorKeyword, "CallTag ValueName": t.atom, VariableName: t.variableName, Callee: t.operatorKeyword, Unit: t.unit, "UniversalSelector NestingSelector": t.definitionOperator, "MatchOp CompareOp": t.compareOperator, "ChildOp SiblingOp, LogicOp": t.logicOperator, BinOp: t.arithmeticOperator, Important: t.modifier, Comment: t.blockComment, ColorLiteral: t.color, "ParenthesizedContent StringLiteral": t.string, ":": t.punctuation, "PseudoOp #": t.derefOperator, "; ,": t.separator, "( )": t.paren, "[ ]": t.squareBracket, "{ }": t.brace }) css-1.3.0/src/tokens.js000066400000000000000000000051741503272345000147430ustar00rootroot00000000000000/* Hand-written tokenizers for CSS tokens that can't be expressed by Lezer's built-in tokenizer. */ import {ExternalTokenizer} from "@lezer/lr" import { identifier, callee, VariableName, queryIdentifier, queryVariableName, QueryCallee, descendantOp, Unit } from "./parser.terms.js" const space = [9, 10, 11, 12, 13, 32, 133, 160, 5760, 8192, 8193, 8194, 8195, 8196, 8197, 8198, 8199, 8200, 8201, 8202, 8232, 8233, 8239, 8287, 12288] const colon = 58, parenL = 40, underscore = 95, bracketL = 91, dash = 45, period = 46, hash = 35, percent = 37, ampersand = 38, backslash = 92, newline = 10, asterisk = 42 function isAlpha(ch) { return ch >= 65 && ch <= 90 || ch >= 97 && ch <= 122 || ch >= 161 } function isDigit(ch) { return ch >= 48 && ch <= 57 } function isHex(ch) { return isDigit(ch) || ch >= 97 && ch <= 102 || ch >= 65 && ch <= 70 } const identifierTokens = (id, varName, callee) => (input, stack) => { for (let inside = false, dashes = 0, i = 0;; i++) { let {next} = input if (isAlpha(next) || next == dash || next == underscore || (inside && isDigit(next))) { if (!inside && (next != dash || i > 0)) inside = true if (dashes === i && next == dash) dashes++ input.advance() } else if (next == backslash && input.peek(1) != newline) { input.advance() if (isHex(input.next)) { do { input.advance() } while (isHex(input.next)) if (input.next == 32) input.advance() } else if (input.next > -1) { input.advance() } inside = true } else { if (inside) input.acceptToken( dashes == 2 && stack.canShift(VariableName) ? varName : next == parenL ? callee : id ) break } } } export const identifiers = new ExternalTokenizer( identifierTokens(identifier, VariableName, callee) ) export const queryIdentifiers = new ExternalTokenizer( identifierTokens(queryIdentifier, queryVariableName, QueryCallee) ) export const descendant = new ExternalTokenizer(input => { if (space.includes(input.peek(-1))) { let {next} = input if (isAlpha(next) || next == underscore || next == hash || next == period || next == asterisk || next == bracketL || next == colon && isAlpha(input.peek(1)) || next == dash || next == ampersand) input.acceptToken(descendantOp) } }) export const unitToken = new ExternalTokenizer(input => { if (!space.includes(input.peek(-1))) { let {next} = input if (next == percent) { input.advance(); input.acceptToken(Unit) } if (isAlpha(next)) { do { input.advance() } while (isAlpha(input.next) || isDigit(input.next)) input.acceptToken(Unit) } } }) css-1.3.0/test/000077500000000000000000000000001503272345000132635ustar00rootroot00000000000000css-1.3.0/test/declarations.txt000066400000000000000000000113671503272345000165040ustar00rootroot00000000000000# Function calls a { color: rgba(0, 255, 0, 0.5); } ==> StyleSheet( RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallExpression(Callee,ArgList(NumberLiteral,NumberLiteral,NumberLiteral,NumberLiteral)))))) # Calls where each argument has multiple values div { background: repeating-linear-gradient(red, orange 50px); clip-path: polygon(50% 0%, 60% 40%, 100% 50%, 60% 60%, 50% 100%, 40% 60%, 0% 50%, 40% 40%) } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallExpression(Callee,ArgList(ValueName,ValueName,NumberLiteral(Unit)))), Declaration(PropertyName,CallExpression(Callee,ArgList( NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit), NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit), NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit), NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit))))))) # Color literals a { b: #fafd04; c: #fafd0401; } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,ColorLiteral), Declaration(PropertyName,ColorLiteral)))) # Numbers a { b: 0.5%; c: 5em; margin: 10E3px; margin: -456.8px; margin: -0.0px; } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,NumberLiteral(Unit)), Declaration(PropertyName,NumberLiteral(Unit)), Declaration(PropertyName,NumberLiteral(Unit)), Declaration(PropertyName,NumberLiteral(Unit)), Declaration(PropertyName,NumberLiteral(Unit))))) # Binary arithmetic operators a { width: calc(100% - 80px); aspect-ratio: 1/2; font-size: calc(10px + (56 - 10) * ((100vw - 320px) / (1920 - 320))); } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallExpression(Callee,ArgList(BinaryExpression(NumberLiteral(Unit),BinOp,NumberLiteral(Unit))))), Declaration(PropertyName,BinaryExpression(NumberLiteral,BinOp,NumberLiteral)), Declaration(PropertyName,CallExpression(Callee,ArgList( BinaryExpression(BinaryExpression(NumberLiteral(Unit),BinOp,ParenthesizedValue( BinaryExpression(NumberLiteral,BinOp,NumberLiteral))),BinOp,ParenthesizedValue( BinaryExpression(ParenthesizedValue(BinaryExpression(NumberLiteral(Unit),BinOp,NumberLiteral(Unit))),BinOp, ParenthesizedValue(BinaryExpression(NumberLiteral,BinOp,NumberLiteral))))))))))) # Strings a { b: ''; c: '\'hi\''; } ==> StyleSheet(RuleSet(TagSelector(TagName),Block(Declaration(PropertyName,StringLiteral),Declaration(PropertyName,StringLiteral)))) # URLs a { b: url(http://something-else?foo=bar); c: url(); } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallLiteral(CallTag,ParenthesizedContent)), Declaration(PropertyName,CallLiteral(CallTag))))) # Important declarations a { b: c !important; } ==> StyleSheet(RuleSet(TagSelector(TagName),Block(Declaration(PropertyName,ValueName,Important)))) # Comments right after numbers a { shape-outside: circle(20em/*=*/at 50% 50%); shape-outside: inset(1em, 1em, 1em, 1em); } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallExpression(Callee,ArgList(NumberLiteral(Unit),Comment,ValueName,NumberLiteral(Unit),NumberLiteral(Unit)))), Declaration(PropertyName,CallExpression(Callee,ArgList(NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit),NumberLiteral(Unit))))))) # Unfinished rule a { foo: 2 ==> StyleSheet(RuleSet(TagSelector(TagName),Block(Declaration(PropertyName,NumberLiteral),⚠))) # Variable names foo { --my-variable: white; color: var(--my-variable); } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(VariableName,ValueName), Declaration(PropertyName,CallExpression(Callee,ArgList(VariableName)))))) # Trailing comma div { color: var(--c,) } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,CallExpression(Callee,ArgList(VariableName)))))) # Space before colon div { color : red; .x :active { color : blue; } } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,ValueName), RuleSet(DescendantSelector(ClassSelector(ClassName),PseudoClassSelector(PseudoClassName)),Block( Declaration(PropertyName,ValueName)))))) # Empty value p { --var-name: ; } ==> StyleSheet(RuleSet(TagSelector(TagName),Block(Declaration(VariableName)))) # Bracketed values div { --myvar: [ some: value; ] } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(VariableName,BracketedValue("[", ValueName, ":", ValueName, ";", "]"))))) # Call to variables .foo { box-shadow: --shadow(blue); } ==> StyleSheet(RuleSet(ClassSelector(ClassName),Block( Declaration(PropertyName,CallExpression(VariableName,ArgList(ValueName)))))) css-1.3.0/test/selector.txt000066400000000000000000000065331503272345000156530ustar00rootroot00000000000000# Universal selectors * {} div * {} ==> StyleSheet( RuleSet(UniversalSelector,Block), RuleSet(DescendantSelector(TagSelector(TagName),UniversalSelector),Block)) # Type selectors div, span {} h1, h2, h3, h4 {} ==> StyleSheet( RuleSet(TagSelector(TagName),TagSelector(TagName),Block), RuleSet(TagSelector(TagName),TagSelector(TagName),TagSelector(TagName),TagSelector(TagName),Block)) # Class selectors .class-a {} div.class-b, .class-c.class-d {} ==> StyleSheet( RuleSet(ClassSelector(ClassName),Block), RuleSet(ClassSelector(TagSelector(TagName),ClassName),ClassSelector(ClassSelector(ClassName),ClassName),Block)) # Id selectors #some-id, a#another-id {} ==> StyleSheet(RuleSet(IdSelector(IdName),IdSelector(TagSelector(TagName),IdName),Block)) # Attribute selectors [a] {} [b=c] {} [d~=e] {} a[b] {} ==> StyleSheet( RuleSet(AttributeSelector(AttributeName),Block), RuleSet(AttributeSelector(AttributeName,MatchOp,ValueName),Block), RuleSet(AttributeSelector(AttributeName,MatchOp,ValueName),Block), RuleSet(AttributeSelector(TagSelector(TagName),AttributeName),Block)) # Pseudo-class selectors a:hover {} :nth-child(2) {} ==> StyleSheet( RuleSet(PseudoClassSelector(TagSelector(TagName),":",PseudoClassName),Block), RuleSet(PseudoClassSelector(":",PseudoClassName,ArgList(NumberLiteral)),Block)) # Pseudo-element selectors a::first-line {} ==> StyleSheet(RuleSet(PseudoClassSelector(TagSelector(TagName),"::",PseudoClassName),Block)) # Child selectors a > b {} c > d > e {} ==> StyleSheet( RuleSet(ChildSelector(TagSelector(TagName),ChildOp,TagSelector(TagName)),Block), RuleSet(ChildSelector(ChildSelector(TagSelector(TagName),ChildOp,TagSelector(TagName)),ChildOp,TagSelector(TagName)),Block)) # Descendant selectors a b {} c d e {} ==> StyleSheet( RuleSet(DescendantSelector(TagSelector(TagName),TagSelector(TagName)),Block), RuleSet(DescendantSelector(DescendantSelector(TagSelector(TagName),TagSelector(TagName)),TagSelector(TagName)),Block)) # Nesting selectors a { &.b {} & c {} c & {} & > d {} } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( RuleSet(ClassSelector(NestingSelector,ClassName),Block), RuleSet(DescendantSelector(NestingSelector,TagSelector(TagName)),Block), RuleSet(DescendantSelector(TagSelector(TagName), NestingSelector),Block), RuleSet(ChildSelector(NestingSelector,ChildOp,TagSelector(TagName)),Block)))) # Relative selectors a { p {} > f {} + g {} } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( RuleSet(TagSelector(TagName),Block), RuleSet(ChildSelector(ChildOp,TagSelector(TagName)),Block), RuleSet(SiblingSelector(SiblingOp,TagSelector(TagName)),Block)))) # Sibling selectors a.b ~ c.d {} .e.f + .g.h {} ==> StyleSheet( RuleSet(SiblingSelector(ClassSelector(TagSelector(TagName),ClassName),SiblingOp,ClassSelector(TagSelector(TagName),ClassName)),Block), RuleSet(SiblingSelector(ClassSelector(ClassSelector(ClassName),ClassName),SiblingOp,ClassSelector(ClassSelector(ClassName),ClassName)),Block)) # The :not selector a:not(:hover) {} .b:not(c > .d) {} ==> StyleSheet( RuleSet(PseudoClassSelector(TagSelector(TagName),":",PseudoClassName,ArgList(PseudoClassSelector(":",PseudoClassName))),Block), RuleSet(PseudoClassSelector(ClassSelector(ClassName),":",PseudoClassName,ArgList(ChildSelector(TagSelector(TagName),ChildOp,ClassSelector(ClassName)))),Block)) css-1.3.0/test/statements.txt000066400000000000000000000156571503272345000162310ustar00rootroot00000000000000# Empty stylesheets /* Just a comment */ ==> StyleSheet(Comment) # Import statements @import url("fineprint.css") print; @import url("bluish.css") speech; @import 'custom.css'; @import url("chrome://communicator/skin/"); @import "common.css" screen; @import "reset.css" layer(framework.component); @import "components.css" layer screen; ==> StyleSheet( ImportStatement(import,CallLiteral(CallTag,StringLiteral),KeywordQuery), ImportStatement(import,CallLiteral(CallTag,StringLiteral),KeywordQuery), ImportStatement(import,StringLiteral), ImportStatement(import,CallLiteral(CallTag,StringLiteral)), ImportStatement(import,StringLiteral,KeywordQuery), ImportStatement(import,StringLiteral,Layer(layer,LayerName,LayerName)), ImportStatement(import,StringLiteral,Layer(layer),KeywordQuery)) # Namespace statements /* Default namespace */ @namespace url(XML-namespace-URL); @namespace "XML-namespace-URL"; @namespace url(http://www.w3.org/1999/xhtml); @namespace svg url(http://www.w3.org/2000/svg); /* Prefixed namespace */ @namespace prefix url(XML-namespace-URL); @namespace prefix "XML-namespace-URL"; ==> StyleSheet( Comment, NamespaceStatement(namespace,CallLiteral(CallTag,ParenthesizedContent)), NamespaceStatement(namespace,StringLiteral), NamespaceStatement(namespace,CallLiteral(CallTag,ParenthesizedContent)), NamespaceStatement(namespace,NamespaceName,CallLiteral(CallTag,ParenthesizedContent)), Comment, NamespaceStatement(namespace,NamespaceName,CallLiteral(CallTag,ParenthesizedContent)), NamespaceStatement(namespace,NamespaceName,StringLiteral)) # Keyframes statements @keyframes important1 { from { margin-top: 50px; } 50%, 60% { margin-top: 150px !important; } /* ignored */ to { margin-top: 100px; } } ==> StyleSheet(KeyframesStatement(keyframes,KeyframeName,KeyframeList( KeyframeSelector(KeyframeRangeName),Block(Declaration(PropertyName,NumberLiteral(Unit))), KeyframeSelector(NumberLiteral(Unit)),KeyframeSelector(NumberLiteral(Unit)),Block( Declaration(PropertyName,NumberLiteral(Unit),Important)), Comment, KeyframeSelector(KeyframeRangeName),Block(Declaration(PropertyName,NumberLiteral(Unit)))))) # Keyframes statements with range @keyframes anim-1 { entry 0% { margin-top: 50px; } entry 100% { margin-top: 50px; } exit 0% { margin-top: 50px; } exit 100% { margin-top: 50px; } } ==> StyleSheet(KeyframesStatement(keyframes,KeyframeName,KeyframeList( KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block(Declaration(PropertyName,NumberLiteral(Unit))), KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block(Declaration(PropertyName,NumberLiteral(Unit))), KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block(Declaration(PropertyName,NumberLiteral(Unit))), KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block(Declaration(PropertyName,NumberLiteral(Unit)))))) # Keyframes statements with range and multiple keyframe selectors @keyframes fade-in-out-animation { entry 0%, exit 100% { opacity: 0 } entry 100%, exit 0% { opacity: 1 } } ==> StyleSheet(KeyframesStatement(keyframes,KeyframeName,KeyframeList( KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block( Declaration(PropertyName,NumberLiteral)), KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),KeyframeSelector(KeyframeRangeName,NumberLiteral(Unit)),Block( Declaration(PropertyName,NumberLiteral))))) # Media statements @media screen and (min-width: 30em) and (orientation: landscape) {} @media (min-height: 680px), screen and (orientation: portrait) {} @media not all and (monochrome) {} @media only screen {} @media (10em <= width < 30em) {} ==> StyleSheet( MediaStatement(media,BinaryQuery(BinaryQuery(KeywordQuery,LogicOp,FeatureQuery(FeatureName,NumberLiteral(Unit))),LogicOp, FeatureQuery(FeatureName,ValueName)),Block), MediaStatement(media,FeatureQuery(FeatureName,NumberLiteral(Unit)),BinaryQuery(KeywordQuery,LogicOp,FeatureQuery(FeatureName,ValueName)),Block), MediaStatement(media,UnaryQuery(UnaryQueryOp,BinaryQuery(KeywordQuery,LogicOp,ParenthesizedQuery(KeywordQuery))),Block), MediaStatement(media,UnaryQuery(UnaryQueryOp,KeywordQuery),Block), MediaStatement(media,ComparisonQuery(NumberLiteral(Unit),CompareOp,FeatureName,CompareOp,NumberLiteral(Unit)),Block)) # Supports statements @supports (animation-name: test) { div { animation-name: test; } } @supports (transform-style: preserve) or (-moz-transform-style: preserve) {} @supports not ((text-align-last: justify) or (-moz-text-align-last: justify)) {} @supports not selector(:matches(a, b)) {} ==> StyleSheet( SupportsStatement(supports,FeatureQuery(FeatureName,ValueName),Block(RuleSet(TagSelector(TagName),Block(Declaration(PropertyName,ValueName))))), SupportsStatement(supports,BinaryQuery(FeatureQuery(FeatureName,ValueName),LogicOp,FeatureQuery(FeatureName,ValueName)),Block), SupportsStatement(supports,UnaryQuery(UnaryQueryOp,ParenthesizedQuery( BinaryQuery(FeatureQuery(FeatureName,ValueName),LogicOp,FeatureQuery(FeatureName,ValueName)))),Block), SupportsStatement(supports,UnaryQuery(UnaryQueryOp,SelectorQuery(selector,ParenthesizedSelector(PseudoClassSelector(PseudoClassName,ArgList(TagSelector(TagName),TagSelector(TagName)))))),Block)) # Charset statements @charset "utf-8"; ==> StyleSheet(CharsetStatement(charset,StringLiteral)) # Other at-statements @font-face { font-family: "Open Sans"; src: url("/a") format("woff2"), url("/b/c") format("woff"); } ==> StyleSheet(AtRule(AtKeyword,Block( Declaration(PropertyName,StringLiteral), Declaration(PropertyName,CallLiteral(CallTag,StringLiteral),CallExpression(Callee,ArgList(StringLiteral)), CallLiteral(CallTag,StringLiteral),CallExpression(Callee,ArgList(StringLiteral)))))) # Unterminated Comment p {} /* div {} ==> StyleSheet(RuleSet(TagSelector(TagName),Block),Comment) # Escaped identifiers #foo\ bar { --weird\\var: 5px; width: var(--weird\\var); c\6f lor: b\6c ue; } ==> StyleSheet(RuleSet(IdSelector(IdName),Block( Declaration(VariableName,NumberLiteral(Unit)), Declaration(PropertyName,CallExpression(Callee,ArgList(VariableName))), Declaration(PropertyName, ValueName)))) # Scope @scope { .x {} } @scope (div) {} @scope (.a) to (.b) {} ==> StyleSheet( ScopeStatement(scope,Block(RuleSet(ClassSelector(ClassName),Block))), ScopeStatement(scope,ParenthesizedSelector(TagSelector(TagName)),Block), ScopeStatement(scope,ParenthesizedSelector(ClassSelector(ClassName)),to,ParenthesizedSelector(ClassSelector(ClassName)),Block)) # If Expressions p { background-color: if( style(--color: white): black; supports(foo: bar): red; else: pink ); } ==> StyleSheet(RuleSet(TagSelector(TagName),Block( Declaration(PropertyName,IfExpression(if,ArgList( IfBranch(CallQuery(QueryCallee,ArgList(FeatureName,ValueName)),ValueName), IfBranch(CallQuery(QueryCallee,ArgList(FeatureName,ValueName)),ValueName), IfBranch(KeywordQuery,ValueName))))))) css-1.3.0/test/test-css.js000066400000000000000000000010121503272345000153600ustar00rootroot00000000000000import {parser} from "../dist/index.js" import {fileTests} from "@lezer/generator/dist/test" import * as fs from "fs" import * as path from "path" import {fileURLToPath} from "url" let caseDir = path.dirname(fileURLToPath(import.meta.url)) for (let file of fs.readdirSync(caseDir)) { if (!/\.txt$/.test(file)) continue let name = /^[^\.]*/.exec(file)[0] describe(name, () => { for (let {name, run} of fileTests(fs.readFileSync(path.join(caseDir, file), "utf8"), file)) it(name, () => run(parser)) }) }