@jesscss/scss-parser 2.0.0-alpha.10 → 2.0.0-alpha.12
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/README.md +52 -9
- package/lib/chunks/parse-with.cjs +147 -0
- package/lib/chunks/parse-with.js +130 -0
- package/lib/chunks/trivia-labels.cjs +18 -0
- package/lib/chunks/trivia-labels.js +13 -0
- package/lib/cst/positions.cjs +24 -0
- package/lib/cst/positions.js +21 -0
- package/lib/cst.cjs +11 -4
- package/lib/cst.d.ts +8 -2
- package/lib/cst.js +10 -4
- package/lib/grammar/ast/positions.cjs +14296 -0
- package/lib/grammar/ast/positions.js +14295 -0
- package/lib/grammar/ast.cjs +70635 -0
- package/lib/grammar/ast.d.ts +11 -0
- package/lib/grammar/ast.js +70634 -0
- package/lib/grammar/cst/positions.cjs +14296 -0
- package/lib/grammar/cst/positions.js +14295 -0
- package/lib/grammar/cst.cjs +14294 -0
- package/lib/grammar/cst.d.ts +2 -0
- package/lib/grammar/cst.js +14293 -0
- package/lib/grammar.d.ts +6 -336
- package/lib/index.cjs +10 -103
- package/lib/index.d.ts +9 -9
- package/lib/index.js +9 -103
- package/lib/parse-error.d.ts +43 -0
- package/lib/parse-with.d.ts +5 -0
- package/lib/positions.cjs +12 -0
- package/lib/positions.js +9 -0
- package/lib/trivia-labels.d.ts +10 -0
- package/package.json +42 -12
- package/lib/ast/lower-user-function-calls.d.ts +0 -6
- package/lib/grammar.cjs +0 -99135
- package/lib/grammar.js +0 -99131
package/README.md
CHANGED
|
@@ -12,9 +12,12 @@ An SCSS grammar for Jess, layered on the CSS base parser — **experimental, and
|
|
|
12
12
|
|
|
13
13
|
## What it is
|
|
14
14
|
|
|
15
|
-
The SCSS grammar
|
|
16
|
-
|
|
17
|
-
|
|
15
|
+
The SCSS grammar extends the spec-aligned CSS base in `@jesscss/css-parser`:
|
|
16
|
+
unchanged CSS structure remains CSS-owned, and SCSS changes only the smallest
|
|
17
|
+
child, value slot, or reference its syntax requires. Parseman currently compiles
|
|
18
|
+
the CSS and SCSS host factories from shared recognition artifacts rather than
|
|
19
|
+
literally composing a terminal CSS grammar artifact; that macro boundary does
|
|
20
|
+
not relax the ownership rule. It is built on
|
|
18
21
|
[parseman](https://www.npmjs.com/package/parseman) — **the fastest
|
|
19
22
|
general-purpose JavaScript parser** in its
|
|
20
23
|
[published benchmarks](https://matthew-dean.github.io/parseman/guide/benchmarks)
|
|
@@ -83,9 +86,49 @@ Pass a different `startRule` (any capitalized grammar rule) to parse a fragment.
|
|
|
83
86
|
| --- | --- | --- |
|
|
84
87
|
| `@jesscss/scss-parser/cst` | `parseScssCst` | Core-free parse of an SCSS string to a CST. |
|
|
85
88
|
| `@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`. |
|
|
89
|
+
| `@jesscss/scss-parser/grammar` | `scssGrammar` | The compiled SCSS AST grammar (a rule map). Extend it with `compose()` or drive it directly with parseman's `run`. See the variant table below. |
|
|
87
90
|
| `@jesscss/scss-parser` (`.`) | `parse` | Parse SCSS directly to canonical AST v2 `Stylesheet`. It does not load the CST grammar. |
|
|
88
91
|
|
|
92
|
+
### Line-aware entries
|
|
93
|
+
|
|
94
|
+
`parse` and the CST parsers come in two bindings, one per compiled table, so an
|
|
95
|
+
entry never loads a table it does not parse with:
|
|
96
|
+
|
|
97
|
+
| Entry | Export | Tree | Positions |
|
|
98
|
+
| --- | --- | --- | --- |
|
|
99
|
+
| `@jesscss/scss-parser` (`.`) | `parse` | AST | no |
|
|
100
|
+
| `@jesscss/scss-parser/positions` | `parse` | AST | yes |
|
|
101
|
+
| `@jesscss/scss-parser/cst` | `parseScssCst`, `parseScssDoc` | CST | no |
|
|
102
|
+
| `@jesscss/scss-parser/cst/positions` | `parseScssCst`, `parseScssDoc` | CST | yes |
|
|
103
|
+
|
|
104
|
+
The `/positions` entries export the same names bound to the line-aware table:
|
|
105
|
+
switching is a change of import specifier, not of call site.
|
|
106
|
+
|
|
107
|
+
### Choosing a grammar build
|
|
108
|
+
|
|
109
|
+
Each compiled grammar is a standalone multi-megabyte artifact, so the four
|
|
110
|
+
variants ship as four separate files. Importing one never loads the others.
|
|
111
|
+
Pick by the two questions the subpath name answers — which tree, and whether
|
|
112
|
+
source positions are tracked:
|
|
113
|
+
|
|
114
|
+
| Subpath | Export | Tree | Positions |
|
|
115
|
+
| --- | --- | --- | --- |
|
|
116
|
+
| `@jesscss/scss-parser/grammar/ast` | `scssGrammar` | AST | no |
|
|
117
|
+
| `@jesscss/scss-parser/grammar/ast/positions` | `scssPositionsGrammar` | AST | yes |
|
|
118
|
+
| `@jesscss/scss-parser/grammar/cst` | `scssCstGrammar` | CST | no |
|
|
119
|
+
| `@jesscss/scss-parser/grammar/cst/positions` | `scssCstPositionsGrammar` | CST | yes |
|
|
120
|
+
|
|
121
|
+
`@jesscss/scss-parser/grammar` is an alias for `/grammar/ast`, the build the
|
|
122
|
+
shipping `parse()` route uses. It is not a barrel: it exposes the AST variant
|
|
123
|
+
only, so importing it cannot pull the other three in.
|
|
124
|
+
|
|
125
|
+
The positions variants set `startLine`/`startColumn` on every span. There is no
|
|
126
|
+
`trackLines` option: an option would force one module to name both tables, and
|
|
127
|
+
Node executes every module it statically imports, so the choice is which entry
|
|
128
|
+
you import. Error tolerance is not a property of a build — the CST runner
|
|
129
|
+
collects `result.errors` on either CST variant.
|
|
130
|
+
|
|
131
|
+
|
|
89
132
|
## Default CST shape
|
|
90
133
|
|
|
91
134
|
The CST is parseman's, produced by the shared `cssCstBuildHost`. Three kinds of node:
|
|
@@ -105,7 +148,7 @@ Parsing `$c: red;\n.foo { color: $c; }` yields (abridged):
|
|
|
105
148
|
{ "_tag": "node", "type": "VarDeclaration", "grammarType": "VarDeclaration", "span": { "start": 0, "end": 8 },
|
|
106
149
|
"children": [
|
|
107
150
|
{ "_tag": "leaf", "value": "$c" }, { "_tag": "leaf", "value": ":" },
|
|
108
|
-
{ "_tag": "node", "type": "
|
|
151
|
+
{ "_tag": "node", "type": "Keyword", "grammarType": "Keyword",
|
|
109
152
|
"children": [ { "_tag": "leaf", "value": "red" } ] },
|
|
110
153
|
{ "_tag": "leaf", "value": ";" }
|
|
111
154
|
] },
|
|
@@ -127,9 +170,9 @@ Parsing `$c: red;\n.foo { color: $c; }` yields (abridged):
|
|
|
127
170
|
}
|
|
128
171
|
```
|
|
129
172
|
|
|
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
|
|
173
|
+
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 a plain `Keyword` — the same node every dialect uses (NamedColor→Keyword convergence).
|
|
131
174
|
|
|
132
|
-
Pass `{ collapse: true }` to unwrap single-child wrapper types (`Reference`, `
|
|
175
|
+
Pass `{ collapse: true }` to unwrap single-child wrapper types (`Reference`, `InterpolatedSelector`) into their child.
|
|
133
176
|
|
|
134
177
|
## Extending with your own builders
|
|
135
178
|
|
|
@@ -139,7 +182,7 @@ The grammar is decoupled from the tree it builds. Every capitalized rule is a pa
|
|
|
139
182
|
import { run } from 'parseman'
|
|
140
183
|
import { scssGrammar } from '@jesscss/scss-parser/grammar'
|
|
141
184
|
|
|
142
|
-
const myHost = (type, children, fields, span) => ({ type, span,
|
|
185
|
+
const myHost = (type, children, fields, span) => ({ type, span, rules: children.filter(Boolean) })
|
|
143
186
|
|
|
144
187
|
const result = run(scssGrammar.Stylesheet, '$c: red; .foo { color: $c; }', {
|
|
145
188
|
build: myHost,
|
|
@@ -154,7 +197,7 @@ The `BuildHost` signature (from parseman):
|
|
|
154
197
|
```ts
|
|
155
198
|
type BuildHost = (
|
|
156
199
|
type: string,
|
|
157
|
-
|
|
200
|
+
rules: readonly unknown[],
|
|
158
201
|
fields: FieldMap | undefined,
|
|
159
202
|
span: { start: number; end: number },
|
|
160
203
|
rawChildren: readonly unknown[],
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
const require_trivia_labels = require("./trivia-labels.cjs");
|
|
2
|
+
let parseman = require("parseman");
|
|
3
|
+
let _jesscss_core_ast = require("@jesscss/core/ast");
|
|
4
|
+
//#region src/parse-error.ts
|
|
5
|
+
/**
|
|
6
|
+
* The public SCSS parse failure lives in its own module so that both AST
|
|
7
|
+
* entries — `.` and `./positions` — can export it without either one reaching
|
|
8
|
+
* the other's compiled grammar table. A class declared in an entry cannot be
|
|
9
|
+
* re-exported by a sibling entry without dragging that entry's imports along.
|
|
10
|
+
*/
|
|
11
|
+
/** Structured failure from the public direct SCSS parser. */
|
|
12
|
+
var ScssParseError = class extends SyntaxError {
|
|
13
|
+
code = "parse/syntax-error";
|
|
14
|
+
offset;
|
|
15
|
+
expected;
|
|
16
|
+
line;
|
|
17
|
+
column;
|
|
18
|
+
endLine;
|
|
19
|
+
endColumn;
|
|
20
|
+
reason;
|
|
21
|
+
fix;
|
|
22
|
+
constructor(offset, expected, options = {}) {
|
|
23
|
+
const detail = expected.length > 0 ? ` Expected: ${expected.join(", ")}.` : "";
|
|
24
|
+
super(options.message ?? `SCSS parser error.${detail}`);
|
|
25
|
+
this.name = "ScssParseError";
|
|
26
|
+
this.offset = offset;
|
|
27
|
+
this.expected = expected;
|
|
28
|
+
this.line = options.line;
|
|
29
|
+
this.column = options.column;
|
|
30
|
+
this.endLine = options.endLine;
|
|
31
|
+
this.endColumn = options.endColumn;
|
|
32
|
+
this.reason = options.reason;
|
|
33
|
+
this.fix = options.fix;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A media/layer/supports postlude belongs to the plain CSS `@import` form only.
|
|
38
|
+
*
|
|
39
|
+
* Once the parser has decided an `@import` is compile-time — a Sass partial
|
|
40
|
+
* rather than a `.css` file or a URL — a trailing query has nothing left to
|
|
41
|
+
* describe: the partial's rules are spliced into this document, not linked as a
|
|
42
|
+
* separate CSS resource.
|
|
43
|
+
*/
|
|
44
|
+
var ScssImportPostludeError = class extends SyntaxError {
|
|
45
|
+
code = "parse/import-postlude-on-compile-time-import";
|
|
46
|
+
offset;
|
|
47
|
+
endOffset;
|
|
48
|
+
reason = "A media, layer, or supports query is only valid on a plain CSS @import.";
|
|
49
|
+
fix = "Drop the query, or wrap the import in an explicit @media/@supports/@layer block.";
|
|
50
|
+
constructor(offset, endOffset) {
|
|
51
|
+
super("A compile-time @import cannot carry a media query.");
|
|
52
|
+
this.name = "ScssImportPostludeError";
|
|
53
|
+
this.offset = offset;
|
|
54
|
+
this.endOffset = endOffset;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/parse-with.ts
|
|
59
|
+
/**
|
|
60
|
+
* The `parse()` body, shared by the two AST entries.
|
|
61
|
+
*
|
|
62
|
+
* The grammar table arrives as an argument rather than being chosen from a
|
|
63
|
+
* boolean inside this module: Node does not tree-shake, so a module that names
|
|
64
|
+
* both compiled tables executes both at load time. Each entry imports exactly
|
|
65
|
+
* the one table it parses with, and this module imports none.
|
|
66
|
+
*/
|
|
67
|
+
function isStylesheet(value) {
|
|
68
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "rules" in value && Array.isArray(value.rules);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Line/column at a bare offset. The leftover-input offset is not the start of
|
|
72
|
+
* any span the run returned — `result.span` covers the text that *was*
|
|
73
|
+
* consumed — so the position has to be derived from the offset itself. Only
|
|
74
|
+
* ever reached on a throw path, so building the index here costs a parse
|
|
75
|
+
* nothing.
|
|
76
|
+
*/
|
|
77
|
+
function positionAt(input, offset) {
|
|
78
|
+
const { line, col } = (0, parseman.offsetToLineCol)((0, parseman.buildLineIndex)(input), offset);
|
|
79
|
+
return {
|
|
80
|
+
line,
|
|
81
|
+
column: col
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Line/column for a failure span. The compiled table without line tracking
|
|
86
|
+
* leaves a span's line fields unset, so fall back to deriving them; an error
|
|
87
|
+
* that reports an offset but no line is barely actionable in an editor.
|
|
88
|
+
*/
|
|
89
|
+
function lineOptions(input, span) {
|
|
90
|
+
if (span.startLine === void 0) return positionAt(input, span.start);
|
|
91
|
+
return {
|
|
92
|
+
line: span.startLine,
|
|
93
|
+
column: span.startColumn,
|
|
94
|
+
endLine: span.endLine,
|
|
95
|
+
endColumn: span.endColumn
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function parseWith(grammar, input) {
|
|
99
|
+
const entry = grammar.Stylesheet;
|
|
100
|
+
const trivia = grammar.whitespace;
|
|
101
|
+
if (entry === void 0 || trivia === void 0) throw new TypeError("SCSS AST grammar is missing its public document entry.");
|
|
102
|
+
const result = (0, parseman.run)(entry, input, {
|
|
103
|
+
trivia,
|
|
104
|
+
rootTrivia: { select: require_trivia_labels.commentTriviaLabels }
|
|
105
|
+
});
|
|
106
|
+
if (!result.ok) throw new ScssParseError(result.span.start, result.expected, lineOptions(input, result.span));
|
|
107
|
+
if (result.unconsumedFrom !== null) {
|
|
108
|
+
if (isStylesheet(result.value) && result.value.rules.length > 0) throw new ScssParseError(result.unconsumedFrom, [], {
|
|
109
|
+
message: "Unexpected SCSS input after a complete stylesheet.",
|
|
110
|
+
reason: "The parser read a complete SCSS stylesheet before this point, so the remaining text sits outside every rule, declaration, and at-rule.",
|
|
111
|
+
fix: "Delete the trailing text, or remove the extra \"}\" — over-closing a nested block ends the stylesheet early.",
|
|
112
|
+
...positionAt(input, result.unconsumedFrom)
|
|
113
|
+
});
|
|
114
|
+
throw new ScssParseError(result.unconsumedFrom, [], {
|
|
115
|
+
message: "Unexpected SCSS syntax.",
|
|
116
|
+
reason: "The parser could not read this token as the start of an SCSS rule, declaration, or at-rule.",
|
|
117
|
+
fix: "Remove the token, or rewrite it as a selector block, a \"$name: value\" assignment, or an at-rule such as @mixin or @include.",
|
|
118
|
+
...positionAt(input, result.unconsumedFrom)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (!isStylesheet(result.value)) throw new ScssParseError(result.span.end, [], {
|
|
122
|
+
message: "SCSS parser did not produce a stylesheet.",
|
|
123
|
+
reason: "The SCSS parser matched the input but returned a value that is not a stylesheet document.",
|
|
124
|
+
fix: "Report this as a parser bug with the source that triggered it.",
|
|
125
|
+
...positionAt(input, result.span.end)
|
|
126
|
+
});
|
|
127
|
+
return (0, _jesscss_core_ast.withTriviaMap)((0, _jesscss_core_ast.withSourceSpan)(result.value, result.span), (0, _jesscss_core_ast.createTriviaMapFromParseman)(input, result.rootTrivia?.index));
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
Object.defineProperty(exports, "ScssImportPostludeError", {
|
|
131
|
+
enumerable: true,
|
|
132
|
+
get: function() {
|
|
133
|
+
return ScssImportPostludeError;
|
|
134
|
+
}
|
|
135
|
+
});
|
|
136
|
+
Object.defineProperty(exports, "ScssParseError", {
|
|
137
|
+
enumerable: true,
|
|
138
|
+
get: function() {
|
|
139
|
+
return ScssParseError;
|
|
140
|
+
}
|
|
141
|
+
});
|
|
142
|
+
Object.defineProperty(exports, "parseWith", {
|
|
143
|
+
enumerable: true,
|
|
144
|
+
get: function() {
|
|
145
|
+
return parseWith;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
import { t as commentTriviaLabels } from "./trivia-labels.js";
|
|
2
|
+
import { buildLineIndex, offsetToLineCol, run } from "parseman";
|
|
3
|
+
import { createTriviaMapFromParseman, withSourceSpan, withTriviaMap } from "@jesscss/core/ast";
|
|
4
|
+
//#region src/parse-error.ts
|
|
5
|
+
/**
|
|
6
|
+
* The public SCSS parse failure lives in its own module so that both AST
|
|
7
|
+
* entries — `.` and `./positions` — can export it without either one reaching
|
|
8
|
+
* the other's compiled grammar table. A class declared in an entry cannot be
|
|
9
|
+
* re-exported by a sibling entry without dragging that entry's imports along.
|
|
10
|
+
*/
|
|
11
|
+
/** Structured failure from the public direct SCSS parser. */
|
|
12
|
+
var ScssParseError = class extends SyntaxError {
|
|
13
|
+
code = "parse/syntax-error";
|
|
14
|
+
offset;
|
|
15
|
+
expected;
|
|
16
|
+
line;
|
|
17
|
+
column;
|
|
18
|
+
endLine;
|
|
19
|
+
endColumn;
|
|
20
|
+
reason;
|
|
21
|
+
fix;
|
|
22
|
+
constructor(offset, expected, options = {}) {
|
|
23
|
+
const detail = expected.length > 0 ? ` Expected: ${expected.join(", ")}.` : "";
|
|
24
|
+
super(options.message ?? `SCSS parser error.${detail}`);
|
|
25
|
+
this.name = "ScssParseError";
|
|
26
|
+
this.offset = offset;
|
|
27
|
+
this.expected = expected;
|
|
28
|
+
this.line = options.line;
|
|
29
|
+
this.column = options.column;
|
|
30
|
+
this.endLine = options.endLine;
|
|
31
|
+
this.endColumn = options.endColumn;
|
|
32
|
+
this.reason = options.reason;
|
|
33
|
+
this.fix = options.fix;
|
|
34
|
+
}
|
|
35
|
+
};
|
|
36
|
+
/**
|
|
37
|
+
* A media/layer/supports postlude belongs to the plain CSS `@import` form only.
|
|
38
|
+
*
|
|
39
|
+
* Once the parser has decided an `@import` is compile-time — a Sass partial
|
|
40
|
+
* rather than a `.css` file or a URL — a trailing query has nothing left to
|
|
41
|
+
* describe: the partial's rules are spliced into this document, not linked as a
|
|
42
|
+
* separate CSS resource.
|
|
43
|
+
*/
|
|
44
|
+
var ScssImportPostludeError = class extends SyntaxError {
|
|
45
|
+
code = "parse/import-postlude-on-compile-time-import";
|
|
46
|
+
offset;
|
|
47
|
+
endOffset;
|
|
48
|
+
reason = "A media, layer, or supports query is only valid on a plain CSS @import.";
|
|
49
|
+
fix = "Drop the query, or wrap the import in an explicit @media/@supports/@layer block.";
|
|
50
|
+
constructor(offset, endOffset) {
|
|
51
|
+
super("A compile-time @import cannot carry a media query.");
|
|
52
|
+
this.name = "ScssImportPostludeError";
|
|
53
|
+
this.offset = offset;
|
|
54
|
+
this.endOffset = endOffset;
|
|
55
|
+
}
|
|
56
|
+
};
|
|
57
|
+
//#endregion
|
|
58
|
+
//#region src/parse-with.ts
|
|
59
|
+
/**
|
|
60
|
+
* The `parse()` body, shared by the two AST entries.
|
|
61
|
+
*
|
|
62
|
+
* The grammar table arrives as an argument rather than being chosen from a
|
|
63
|
+
* boolean inside this module: Node does not tree-shake, so a module that names
|
|
64
|
+
* both compiled tables executes both at load time. Each entry imports exactly
|
|
65
|
+
* the one table it parses with, and this module imports none.
|
|
66
|
+
*/
|
|
67
|
+
function isStylesheet(value) {
|
|
68
|
+
return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "rules" in value && Array.isArray(value.rules);
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Line/column at a bare offset. The leftover-input offset is not the start of
|
|
72
|
+
* any span the run returned — `result.span` covers the text that *was*
|
|
73
|
+
* consumed — so the position has to be derived from the offset itself. Only
|
|
74
|
+
* ever reached on a throw path, so building the index here costs a parse
|
|
75
|
+
* nothing.
|
|
76
|
+
*/
|
|
77
|
+
function positionAt(input, offset) {
|
|
78
|
+
const { line, col } = offsetToLineCol(buildLineIndex(input), offset);
|
|
79
|
+
return {
|
|
80
|
+
line,
|
|
81
|
+
column: col
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Line/column for a failure span. The compiled table without line tracking
|
|
86
|
+
* leaves a span's line fields unset, so fall back to deriving them; an error
|
|
87
|
+
* that reports an offset but no line is barely actionable in an editor.
|
|
88
|
+
*/
|
|
89
|
+
function lineOptions(input, span) {
|
|
90
|
+
if (span.startLine === void 0) return positionAt(input, span.start);
|
|
91
|
+
return {
|
|
92
|
+
line: span.startLine,
|
|
93
|
+
column: span.startColumn,
|
|
94
|
+
endLine: span.endLine,
|
|
95
|
+
endColumn: span.endColumn
|
|
96
|
+
};
|
|
97
|
+
}
|
|
98
|
+
function parseWith(grammar, input) {
|
|
99
|
+
const entry = grammar.Stylesheet;
|
|
100
|
+
const trivia = grammar.whitespace;
|
|
101
|
+
if (entry === void 0 || trivia === void 0) throw new TypeError("SCSS AST grammar is missing its public document entry.");
|
|
102
|
+
const result = run(entry, input, {
|
|
103
|
+
trivia,
|
|
104
|
+
rootTrivia: { select: commentTriviaLabels }
|
|
105
|
+
});
|
|
106
|
+
if (!result.ok) throw new ScssParseError(result.span.start, result.expected, lineOptions(input, result.span));
|
|
107
|
+
if (result.unconsumedFrom !== null) {
|
|
108
|
+
if (isStylesheet(result.value) && result.value.rules.length > 0) throw new ScssParseError(result.unconsumedFrom, [], {
|
|
109
|
+
message: "Unexpected SCSS input after a complete stylesheet.",
|
|
110
|
+
reason: "The parser read a complete SCSS stylesheet before this point, so the remaining text sits outside every rule, declaration, and at-rule.",
|
|
111
|
+
fix: "Delete the trailing text, or remove the extra \"}\" — over-closing a nested block ends the stylesheet early.",
|
|
112
|
+
...positionAt(input, result.unconsumedFrom)
|
|
113
|
+
});
|
|
114
|
+
throw new ScssParseError(result.unconsumedFrom, [], {
|
|
115
|
+
message: "Unexpected SCSS syntax.",
|
|
116
|
+
reason: "The parser could not read this token as the start of an SCSS rule, declaration, or at-rule.",
|
|
117
|
+
fix: "Remove the token, or rewrite it as a selector block, a \"$name: value\" assignment, or an at-rule such as @mixin or @include.",
|
|
118
|
+
...positionAt(input, result.unconsumedFrom)
|
|
119
|
+
});
|
|
120
|
+
}
|
|
121
|
+
if (!isStylesheet(result.value)) throw new ScssParseError(result.span.end, [], {
|
|
122
|
+
message: "SCSS parser did not produce a stylesheet.",
|
|
123
|
+
reason: "The SCSS parser matched the input but returned a value that is not a stylesheet document.",
|
|
124
|
+
fix: "Report this as a parser bug with the source that triggered it.",
|
|
125
|
+
...positionAt(input, result.span.end)
|
|
126
|
+
});
|
|
127
|
+
return withTriviaMap(withSourceSpan(result.value, result.span), createTriviaMapFromParseman(input, result.rootTrivia?.index));
|
|
128
|
+
}
|
|
129
|
+
//#endregion
|
|
130
|
+
export { ScssImportPostludeError as n, ScssParseError as r, parseWith as t };
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
//#region src/trivia-labels.ts
|
|
2
|
+
/**
|
|
3
|
+
* Root-trivia label selection for the SCSS grammar.
|
|
4
|
+
*
|
|
5
|
+
* This is a plain fact about the grammar's trivia arm labels, so it lives in a
|
|
6
|
+
* leaf module with no imports. Reading it from the CST entry instead would make
|
|
7
|
+
* every consumer of the package entry load the compiled CST grammar tables:
|
|
8
|
+
* Node's ESM loader does not tree-shake, so an unused named import still
|
|
9
|
+
* executes the module it is taken from, and each table is multiple megabytes.
|
|
10
|
+
*/
|
|
11
|
+
const commentTriviaLabels = ["comment"];
|
|
12
|
+
//#endregion
|
|
13
|
+
Object.defineProperty(exports, "commentTriviaLabels", {
|
|
14
|
+
enumerable: true,
|
|
15
|
+
get: function() {
|
|
16
|
+
return commentTriviaLabels;
|
|
17
|
+
}
|
|
18
|
+
});
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/trivia-labels.ts
|
|
2
|
+
/**
|
|
3
|
+
* Root-trivia label selection for the SCSS grammar.
|
|
4
|
+
*
|
|
5
|
+
* This is a plain fact about the grammar's trivia arm labels, so it lives in a
|
|
6
|
+
* leaf module with no imports. Reading it from the CST entry instead would make
|
|
7
|
+
* every consumer of the package entry load the compiled CST grammar tables:
|
|
8
|
+
* Node's ESM loader does not tree-shake, so an unused named import still
|
|
9
|
+
* executes the module it is taken from, and each table is multiple megabytes.
|
|
10
|
+
*/
|
|
11
|
+
const commentTriviaLabels = ["comment"];
|
|
12
|
+
//#endregion
|
|
13
|
+
export { commentTriviaLabels as t };
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
+
const require_trivia_labels = require("../chunks/trivia-labels.cjs");
|
|
3
|
+
let _jesscss_css_parser_cst_host = require("@jesscss/css-parser/cst-host");
|
|
4
|
+
let src_grammar_cst_positions_js = require("../grammar/cst/positions.cjs");
|
|
5
|
+
//#region src/cst/positions.ts
|
|
6
|
+
/**
|
|
7
|
+
* The line-aware SCSS CST entry: the `./cst` functions bound to the compiled
|
|
8
|
+
* table that tracks lines and columns. Tolerant error recovery is a property of
|
|
9
|
+
* the CST runner, not of the table, so `result.errors` is collected here
|
|
10
|
+
* exactly as it is on `./cst` — this entry adds line/column facts and nothing
|
|
11
|
+
* else. It never loads the offsets-only table.
|
|
12
|
+
*/
|
|
13
|
+
/** Parse SCSS to a CST whose spans carry line and column facts. */
|
|
14
|
+
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
15
|
+
return (0, _jesscss_css_parser_cst_host.parseCst)(src_grammar_cst_positions_js.scssCstPositionsGrammar, input, startRule, options, require_trivia_labels.commentTriviaLabels);
|
|
16
|
+
}
|
|
17
|
+
/** Incremental (`.edit()`-able) SCSS document with line and column facts. */
|
|
18
|
+
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
19
|
+
return (0, _jesscss_css_parser_cst_host.parseDocCst)(src_grammar_cst_positions_js.scssCstPositionsGrammar, input, startRule);
|
|
20
|
+
}
|
|
21
|
+
//#endregion
|
|
22
|
+
exports.commentTriviaLabels = require_trivia_labels.commentTriviaLabels;
|
|
23
|
+
exports.parseScssCst = parseScssCst;
|
|
24
|
+
exports.parseScssDoc = parseScssDoc;
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { t as commentTriviaLabels } from "../chunks/trivia-labels.js";
|
|
2
|
+
import { parseCst, parseDocCst } from "@jesscss/css-parser/cst-host";
|
|
3
|
+
import { scssCstPositionsGrammar } from "../grammar/cst/positions.js";
|
|
4
|
+
//#region src/cst/positions.ts
|
|
5
|
+
/**
|
|
6
|
+
* The line-aware SCSS CST entry: the `./cst` functions bound to the compiled
|
|
7
|
+
* table that tracks lines and columns. Tolerant error recovery is a property of
|
|
8
|
+
* the CST runner, not of the table, so `result.errors` is collected here
|
|
9
|
+
* exactly as it is on `./cst` — this entry adds line/column facts and nothing
|
|
10
|
+
* else. It never loads the offsets-only table.
|
|
11
|
+
*/
|
|
12
|
+
/** Parse SCSS to a CST whose spans carry line and column facts. */
|
|
13
|
+
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
14
|
+
return parseCst(scssCstPositionsGrammar, input, startRule, options, commentTriviaLabels);
|
|
15
|
+
}
|
|
16
|
+
/** Incremental (`.edit()`-able) SCSS document with line and column facts. */
|
|
17
|
+
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
18
|
+
return parseDocCst(scssCstPositionsGrammar, input, startRule);
|
|
19
|
+
}
|
|
20
|
+
//#endregion
|
|
21
|
+
export { commentTriviaLabels, parseScssCst, parseScssDoc };
|
package/lib/cst.cjs
CHANGED
|
@@ -1,14 +1,21 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
|
-
const
|
|
3
|
-
let
|
|
2
|
+
const require_trivia_labels = require("./chunks/trivia-labels.cjs");
|
|
3
|
+
let _jesscss_css_parser_cst_host = require("@jesscss/css-parser/cst-host");
|
|
4
|
+
let src_grammar_cst_js = require("./grammar/cst.cjs");
|
|
4
5
|
//#region src/cst.ts
|
|
6
|
+
/**
|
|
7
|
+
* Parse SCSS to a CST. Spans carry offsets only; for line/column facts import
|
|
8
|
+
* the same functions from `@jesscss/scss-parser/cst/positions`, which binds the
|
|
9
|
+
* line-aware compiled table. This entry never loads that table.
|
|
10
|
+
*/
|
|
5
11
|
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
6
|
-
return (0,
|
|
12
|
+
return (0, _jesscss_css_parser_cst_host.parseCst)(src_grammar_cst_js.scssCstGrammar, input, startRule, options, require_trivia_labels.commentTriviaLabels);
|
|
7
13
|
}
|
|
8
14
|
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
9
15
|
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
10
|
-
return (0,
|
|
16
|
+
return (0, _jesscss_css_parser_cst_host.parseDocCst)(src_grammar_cst_js.scssCstGrammar, input, startRule);
|
|
11
17
|
}
|
|
12
18
|
//#endregion
|
|
19
|
+
exports.commentTriviaLabels = require_trivia_labels.commentTriviaLabels;
|
|
13
20
|
exports.parseScssCst = parseScssCst;
|
|
14
21
|
exports.parseScssDoc = parseScssDoc;
|
package/lib/cst.d.ts
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
|
-
import { type CssCstNode, type CssCstParseOptions, type CssCstParseResult, type ParseDoc } from '@jesscss/css-parser/cst';
|
|
1
|
+
import { type CssCstNode, type CssCstParseOptions, type CssCstParseResult, type ParseDoc } from '@jesscss/css-parser/cst-host';
|
|
2
|
+
export { commentTriviaLabels } from './trivia-labels.js';
|
|
3
|
+
/**
|
|
4
|
+
* Parse SCSS to a CST. Spans carry offsets only; for line/column facts import
|
|
5
|
+
* the same functions from `@jesscss/scss-parser/cst/positions`, which binds the
|
|
6
|
+
* line-aware compiled table. This entry never loads that table.
|
|
7
|
+
*/
|
|
2
8
|
export declare function parseScssCst(input: string, startRule?: string, options?: CssCstParseOptions): CssCstParseResult;
|
|
3
9
|
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
4
10
|
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';
|
|
11
|
+
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-host';
|
package/lib/cst.js
CHANGED
|
@@ -1,12 +1,18 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { parseCst, parseDocCst } from "@jesscss/css-parser/cst";
|
|
1
|
+
import { t as commentTriviaLabels } from "./chunks/trivia-labels.js";
|
|
2
|
+
import { parseCst, parseDocCst } from "@jesscss/css-parser/cst-host";
|
|
3
|
+
import { scssCstGrammar } from "./grammar/cst.js";
|
|
3
4
|
//#region src/cst.ts
|
|
5
|
+
/**
|
|
6
|
+
* Parse SCSS to a CST. Spans carry offsets only; for line/column facts import
|
|
7
|
+
* the same functions from `@jesscss/scss-parser/cst/positions`, which binds the
|
|
8
|
+
* line-aware compiled table. This entry never loads that table.
|
|
9
|
+
*/
|
|
4
10
|
function parseScssCst(input, startRule = "Stylesheet", options) {
|
|
5
|
-
return parseCst(scssCstGrammar, input, startRule, options);
|
|
11
|
+
return parseCst(scssCstGrammar, input, startRule, options, commentTriviaLabels);
|
|
6
12
|
}
|
|
7
13
|
/** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
|
|
8
14
|
function parseScssDoc(input, startRule = "Stylesheet") {
|
|
9
15
|
return parseDocCst(scssCstGrammar, input, startRule);
|
|
10
16
|
}
|
|
11
17
|
//#endregion
|
|
12
|
-
export { parseScssCst, parseScssDoc };
|
|
18
|
+
export { commentTriviaLabels, parseScssCst, parseScssDoc };
|