@jesscss/scss-parser 2.0.0-alpha.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +173 -0
- package/lib/ast/lower-user-function-calls.d.ts +6 -0
- package/lib/cst.cjs +14 -0
- package/lib/cst.d.ts +5 -0
- package/lib/cst.js +12 -0
- package/lib/grammar.cjs +99135 -0
- package/lib/grammar.d.ts +336 -0
- package/lib/grammar.js +99131 -0
- package/lib/index.cjs +111 -0
- package/lib/index.d.ts +10 -0
- package/lib/index.js +109 -0
- package/package.json +71 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2018 Matthew Dean
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,173 @@
|
|
|
1
|
+
# @jesscss/scss-parser
|
|
2
|
+
|
|
3
|
+
An SCSS grammar for Jess, layered on the CSS base parser — **experimental, and not the focus of the Less alpha.**
|
|
4
|
+
|
|
5
|
+
> **Status: experimental / roadmap.** Part of
|
|
6
|
+
> [Jess](https://github.com/jesscss/jess). The current alpha ships through
|
|
7
|
+
> `.less`; SCSS is **not a goal of this phase**. This parser is early and exists
|
|
8
|
+
> to seed the future **"Sass+"** dialect. Don't rely on it for production;
|
|
9
|
+
> prefer [`@jesscss/css-parser`](https://www.npmjs.com/package/@jesscss/css-parser).
|
|
10
|
+
> [Report bugs](https://github.com/jesscss/jess/issues); docs live at
|
|
11
|
+
> [jesscss.github.io](https://jesscss.github.io/).
|
|
12
|
+
|
|
13
|
+
## What it is
|
|
14
|
+
|
|
15
|
+
The SCSS grammar is the shared CSS grammar plus an SCSS delta:
|
|
16
|
+
`scssGrammar = compose([cssFactory, <SCSS delta>])`, layered on the spec-aligned
|
|
17
|
+
CSS base in `@jesscss/css-parser` and built on
|
|
18
|
+
[parseman](https://www.npmjs.com/package/parseman) — **the fastest
|
|
19
|
+
general-purpose JavaScript parser** in its
|
|
20
|
+
[published benchmarks](https://matthew-dean.github.io/parseman/guide/benchmarks)
|
|
21
|
+
(see `@jesscss/css-parser` for figures and engineering details).
|
|
22
|
+
|
|
23
|
+
The current goal is **parse coverage**: the surface `$`-variable / SCSS syntax
|
|
24
|
+
should parse into a tree, but not every Sass/SCSS feature is necessarily
|
|
25
|
+
*evaluated*. This is the least-mature of the Jess parsers (the `.jess` parser
|
|
26
|
+
trails it), and the seed for the roadmap "Sass+" dialect rather than a shipped
|
|
27
|
+
Sass replacement. The language roadmap is ordered: **Now Less.js → Next Sass+ →
|
|
28
|
+
Final `.jess`.**
|
|
29
|
+
|
|
30
|
+
Two parser representations are available:
|
|
31
|
+
|
|
32
|
+
- **Canonical AST v2** — the default `parse()` entry constructs a `Stylesheet`
|
|
33
|
+
directly through parser-local Parseman reductions.
|
|
34
|
+
- **Explicit CST** — the `./cst` entry has **no dependency on
|
|
35
|
+
`@jesscss/core`** and parses SCSS source text into a concrete syntax tree for
|
|
36
|
+
language-service/document consumers.
|
|
37
|
+
|
|
38
|
+
## Install
|
|
39
|
+
|
|
40
|
+
```sh
|
|
41
|
+
npm install @jesscss/scss-parser
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
`@jesscss/core` is an **optional** peer dependency — needed for the default
|
|
45
|
+
AST v2 `parse()` entry, not for `./cst` or `./grammar`.
|
|
46
|
+
Those explicit entries expose Parseman types and grammar values, so consumers
|
|
47
|
+
of them must also provide the package's `parseman` peer.
|
|
48
|
+
|
|
49
|
+
## Canonical AST parsing
|
|
50
|
+
|
|
51
|
+
```js
|
|
52
|
+
import { parse } from '@jesscss/scss-parser'
|
|
53
|
+
|
|
54
|
+
const stylesheet = parse('$c: red;\n.foo { color: $c; }')
|
|
55
|
+
|
|
56
|
+
stylesheet.type // 'Stylesheet'
|
|
57
|
+
```
|
|
58
|
+
|
|
59
|
+
## Standalone usage (core-free)
|
|
60
|
+
|
|
61
|
+
```js
|
|
62
|
+
import { parseScssCst } from '@jesscss/scss-parser/cst'
|
|
63
|
+
|
|
64
|
+
const result = parseScssCst('$c: red;\n.foo { color: $c; }')
|
|
65
|
+
|
|
66
|
+
result.ok // true
|
|
67
|
+
result.errors // ParseError[] (empty when ok)
|
|
68
|
+
result.unconsumedFrom // index of first unparsed char, or null
|
|
69
|
+
result.tree // the CST root (a StyleSheet node)
|
|
70
|
+
```
|
|
71
|
+
|
|
72
|
+
Signature:
|
|
73
|
+
|
|
74
|
+
```ts
|
|
75
|
+
parseScssCst(input: string, startRule = 'Stylesheet', options?: { collapse?: boolean }): ScssCstParseResult
|
|
76
|
+
```
|
|
77
|
+
|
|
78
|
+
Pass a different `startRule` (any capitalized grammar rule) to parse a fragment.
|
|
79
|
+
|
|
80
|
+
## Public API
|
|
81
|
+
|
|
82
|
+
| Entry | Export | Purpose |
|
|
83
|
+
| --- | --- | --- |
|
|
84
|
+
| `@jesscss/scss-parser/cst` | `parseScssCst` | Core-free parse of an SCSS string to a CST. |
|
|
85
|
+
| `@jesscss/scss-parser/cst` | `ScssCstNode`, `ScssCstLeaf`, `ScssCstError`, `ScssCstChild`, `ScssCstParseResult`, `ScssCstType` (types) | CST type definitions (aliases of the shared `@jesscss/css-parser/cst` types). |
|
|
86
|
+
| `@jesscss/scss-parser/grammar` | `scssGrammar` | The compiled SCSS grammar (a rule map). Extend it with `compose()` or drive it directly with parseman's `run`. |
|
|
87
|
+
| `@jesscss/scss-parser` (`.`) | `parse` | Parse SCSS directly to canonical AST v2 `Stylesheet`. It does not load the CST grammar. |
|
|
88
|
+
|
|
89
|
+
## Default CST shape
|
|
90
|
+
|
|
91
|
+
The CST is parseman's, produced by the shared `cssCstBuildHost`. Three kinds of node:
|
|
92
|
+
|
|
93
|
+
- **node** — `{ _tag: 'node', type, grammarType, span: { start, end }, state, children }` (`grammarType` = raw rule name; `type` = friendly public name).
|
|
94
|
+
- **leaf** — `{ _tag: 'leaf', value, span }` for terminals.
|
|
95
|
+
- **error** — `{ _tag: 'error', type, span, expected, children, state }` where recovery happened.
|
|
96
|
+
|
|
97
|
+
Spans are `[start, end)` offsets; whitespace and comments are trivia and do not appear as children.
|
|
98
|
+
|
|
99
|
+
Parsing `$c: red;\n.foo { color: $c; }` yields (abridged):
|
|
100
|
+
|
|
101
|
+
```jsonc
|
|
102
|
+
{
|
|
103
|
+
"_tag": "node", "type": "StyleSheet", "grammarType": "Stylesheet",
|
|
104
|
+
"children": [
|
|
105
|
+
{ "_tag": "node", "type": "VarDeclaration", "grammarType": "VarDeclaration", "span": { "start": 0, "end": 8 },
|
|
106
|
+
"children": [
|
|
107
|
+
{ "_tag": "leaf", "value": "$c" }, { "_tag": "leaf", "value": ":" },
|
|
108
|
+
{ "_tag": "node", "type": "NamedColor", "grammarType": "NamedColor",
|
|
109
|
+
"children": [ { "_tag": "leaf", "value": "red" } ] },
|
|
110
|
+
{ "_tag": "leaf", "value": ";" }
|
|
111
|
+
] },
|
|
112
|
+
{ "_tag": "node", "type": "QualifiedRule", "grammarType": "Ruleset", "span": { "start": 9, "end": 28 },
|
|
113
|
+
"children": [
|
|
114
|
+
{ "_tag": "node", "type": "InterpolatedSelector", "grammarType": "InterpolatedSelector",
|
|
115
|
+
"children": [ { "_tag": "leaf", "value": "." }, { "_tag": "leaf", "value": "foo" } ] },
|
|
116
|
+
{ "_tag": "leaf", "value": "{" },
|
|
117
|
+
{ "_tag": "node", "type": "Declaration", "grammarType": "Declaration",
|
|
118
|
+
"children": [
|
|
119
|
+
{ "_tag": "leaf", "value": "color" }, { "_tag": "leaf", "value": ":" },
|
|
120
|
+
{ "_tag": "node", "type": "Reference", "grammarType": "Reference",
|
|
121
|
+
"children": [ { "_tag": "leaf", "value": "$c" } ] },
|
|
122
|
+
{ "_tag": "leaf", "value": ";" }
|
|
123
|
+
] },
|
|
124
|
+
{ "_tag": "leaf", "value": "}" }
|
|
125
|
+
] }
|
|
126
|
+
]
|
|
127
|
+
}
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
Note the SCSS-specific nodes: `$c: …` becomes a `VarDeclaration`, `$c` in value position becomes a `Reference`, selectors parse through `InterpolatedSelector` (so `#{…}` interpolation is captured in place), and the color keyword `red` parses as `NamedColor`.
|
|
131
|
+
|
|
132
|
+
Pass `{ collapse: true }` to unwrap single-child wrapper types (`Reference`, `NamedColor`, `InterpolatedSelector`) into their child.
|
|
133
|
+
|
|
134
|
+
## Extending with your own builders
|
|
135
|
+
|
|
136
|
+
The grammar is decoupled from the tree it builds. Every capitalized rule is a parseman `node()`; when you drive a grammar with a `build` host, each `node()` calls your host instead of constructing the default CST. Use parseman's `run` with your own host and the grammar's trivia rule:
|
|
137
|
+
|
|
138
|
+
```js
|
|
139
|
+
import { run } from 'parseman'
|
|
140
|
+
import { scssGrammar } from '@jesscss/scss-parser/grammar'
|
|
141
|
+
|
|
142
|
+
const myHost = (type, children, fields, span) => ({ type, span, children: children.filter(Boolean) })
|
|
143
|
+
|
|
144
|
+
const result = run(scssGrammar.Stylesheet, '$c: red; .foo { color: $c; }', {
|
|
145
|
+
build: myHost,
|
|
146
|
+
trivia: scssGrammar.rw
|
|
147
|
+
})
|
|
148
|
+
|
|
149
|
+
result.value // the root node your host returned
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
The `BuildHost` signature (from parseman):
|
|
153
|
+
|
|
154
|
+
```ts
|
|
155
|
+
type BuildHost = (
|
|
156
|
+
type: string,
|
|
157
|
+
children: readonly unknown[],
|
|
158
|
+
fields: FieldMap | undefined,
|
|
159
|
+
span: { start: number; end: number },
|
|
160
|
+
rawChildren: readonly unknown[],
|
|
161
|
+
triviaLog: readonly number[],
|
|
162
|
+
state: unknown
|
|
163
|
+
) => unknown
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
`parseScssCst(...)` is this pattern with the shared `cssCstBuildHost` (see `@jesscss/css-parser`, `src/cst.ts`) as a reference host.
|
|
167
|
+
|
|
168
|
+
## Part of Jess
|
|
169
|
+
|
|
170
|
+
This package is developed as part of [Jess](https://github.com/jesscss/jess).
|
|
171
|
+
SCSS is the least-mature Jess dialect and is not the focus of the current
|
|
172
|
+
alpha; it seeds the roadmap "Sass+" dialect. For production use, prefer
|
|
173
|
+
`@jesscss/css-parser`. Licensed MIT.
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { Stylesheet } from '@jesscss/core/ast';
|
|
2
|
+
/**
|
|
3
|
+
* Rewrite user-`@function` call sites in a parsed SCSS document to `$f(args)`
|
|
4
|
+
* lambda invokes. Returns the document unchanged when it defines no user function.
|
|
5
|
+
*/
|
|
6
|
+
export declare function lowerUserFunctionCalls(sheet: Stylesheet): Stylesheet;
|
package/lib/cst.cjs
ADDED
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_grammar = require("./grammar.cjs");
|
|
3
|
+
let _jesscss_css_parser_cst = require("@jesscss/css-parser/cst");
|
|
4
|
+
//#region src/cst.ts
|
|
5
|
+
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
6
|
+
return (0, _jesscss_css_parser_cst.parseCst)(require_grammar.scssCstGrammar, input, startRule, options);
|
|
7
|
+
}
|
|
8
|
+
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
9
|
+
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
10
|
+
return (0, _jesscss_css_parser_cst.parseDocCst)(require_grammar.scssCstGrammar, input, startRule);
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
exports.parseScssCst = parseScssCst;
|
|
14
|
+
exports.parseScssDoc = parseScssDoc;
|
package/lib/cst.d.ts
ADDED
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type CssCstNode, type CssCstParseOptions, type CssCstParseResult, type ParseDoc } from '@jesscss/css-parser/cst';
|
|
2
|
+
export declare function parseScssCst(input: string, startRule?: string, options?: CssCstParseOptions): CssCstParseResult;
|
|
3
|
+
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
4
|
+
export declare function parseScssDoc(input: string, startRule?: string): ParseDoc<CssCstNode>;
|
|
5
|
+
export type { CssCstChild as ScssCstChild, CssCstError as ScssCstError, CssCstLeaf as ScssCstLeaf, CssCstNode as ScssCstNode, CssCstParseOptions as ScssCstParseOptions, CssCstParseResult as ScssCstParseResult, CssCstType as ScssCstType } from '@jesscss/css-parser/cst';
|
package/lib/cst.js
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { scssCstGrammar } from "./grammar.js";
|
|
2
|
+
import { parseCst, parseDocCst } from "@jesscss/css-parser/cst";
|
|
3
|
+
//#region src/cst.ts
|
|
4
|
+
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
5
|
+
return parseCst(scssCstGrammar, input, startRule, options);
|
|
6
|
+
}
|
|
7
|
+
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
8
|
+
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
9
|
+
return parseDocCst(scssCstGrammar, input, startRule);
|
|
10
|
+
}
|
|
11
|
+
//#endregion
|
|
12
|
+
export { parseScssCst, parseScssDoc };
|