@jesscss/jess-parser 2.0.0-alpha.11 → 2.0.0-alpha.13

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 CHANGED
@@ -62,10 +62,48 @@ Pass a different `startRule` (any capitalized grammar rule) to parse a fragment.
62
62
  | Entry | Export | Purpose |
63
63
  | --- | --- | --- |
64
64
  | `@jesscss/jess-parser` (`.`) | `parse`, `JessParseError` | Parse Jess directly to canonical AST v2 `Stylesheet`; malformed input throws `JessParseError` with an offset and expected facts. |
65
- | `@jesscss/jess-parser` (`.`) | `parseJessCst`, `jessGrammar` | Convenience exports for the public CST parser and canonical grammar artifact. |
66
65
  | `@jesscss/jess-parser` (`.`) | `JessCstNode`, `JessCstLeaf`, `JessCstError`, `JessCstChild`, `JessCstParseResult`, `JessCstType` (types) | CST type definitions (aliases of the shared `@jesscss/css-parser/cst` types). |
67
- | `@jesscss/jess-parser/cst` | `parseJessCst`, CST types | Same core-free CST parser (explicit subpath). |
68
- | `@jesscss/jess-parser/grammar` | `jessFactory`, `jessGrammar`, `jessAstGrammar`, `jessCstGrammar` | The single host-mode grammar source and its AST/CST compiled artifacts. |
66
+ | `@jesscss/jess-parser/cst` | `parseJessCst`, `parseJessDoc`, CST types | Core-free parse of a Jess string to a CST. Compiled grammars are not re-exported from `.` — reach for a `/grammar` subpath so the main entry never loads a grammar build you did not ask for. |
67
+ | `@jesscss/jess-parser/grammar` | `jessGrammar` | The compiled Jess AST grammar (a rule map). Extend it with `compose()` or drive it directly with parseman's `run`. See the variant table below. |
68
+
69
+ ### Line-aware entries
70
+
71
+ `parse` and the CST parsers come in two bindings, one per compiled table, so an
72
+ entry never loads a table it does not parse with:
73
+
74
+ | Entry | Export | Tree | Positions |
75
+ | --- | --- | --- | --- |
76
+ | `@jesscss/jess-parser` (`.`) | `parse` | AST | no |
77
+ | `@jesscss/jess-parser/positions` | `parse` | AST | yes |
78
+ | `@jesscss/jess-parser/cst` | `parseJessCst`, `parseJessDoc` | CST | no |
79
+ | `@jesscss/jess-parser/cst/positions` | `parseJessCst`, `parseJessDoc` | CST | yes |
80
+
81
+ The `/positions` entries export the same names bound to the line-aware table:
82
+ switching is a change of import specifier, not of call site.
83
+
84
+ ### Choosing a grammar build
85
+
86
+ Each compiled grammar is a standalone multi-megabyte artifact, so the four
87
+ variants ship as four separate files. Importing one never loads the others.
88
+ Pick by the two questions the subpath name answers — which tree, and whether
89
+ source positions are tracked:
90
+
91
+ | Subpath | Export | Tree | Positions |
92
+ | --- | --- | --- | --- |
93
+ | `@jesscss/jess-parser/grammar/ast` | `jessGrammar` | AST | no |
94
+ | `@jesscss/jess-parser/grammar/ast/positions` | `jessPositionsGrammar` | AST | yes |
95
+ | `@jesscss/jess-parser/grammar/cst` | `jessCstGrammar` | CST | no |
96
+ | `@jesscss/jess-parser/grammar/cst/positions` | `jessCstPositionsGrammar` | CST | yes |
97
+
98
+ `@jesscss/jess-parser/grammar` is an alias for `/grammar/ast`, the build the
99
+ shipping `parse()` route uses. It is not a barrel: it exposes the AST variant
100
+ only, so importing it cannot pull the other three in.
101
+
102
+ The positions variants set `startLine`/`startColumn` on every span. There is no
103
+ `trackLines` option: an option would force one module to name both tables, and
104
+ Node executes every module it statically imports, so the choice is which entry
105
+ you import. Error tolerance is not a property of a build — the CST runner
106
+ collects `result.errors` on either CST variant.
69
107
 
70
108
  ## Default CST shape
71
109
 
@@ -83,19 +121,32 @@ Parsing `$brand: #3366ff;` yields:
83
121
  {
84
122
  "_tag": "node", "type": "StyleSheet", "grammarType": "Stylesheet", "span": { "start": 0, "end": 16 },
85
123
  "children": [
86
- { "_tag": "node", "type": "DirectJessVarDeclaration", "grammarType": "DirectJessVarDeclaration", "span": { "start": 0, "end": 16 },
124
+ { "_tag": "node", "type": "VariableDeclaration", "grammarType": "VariableDeclaration", "span": { "start": 0, "end": 16 },
87
125
  "children": [
88
- { "_tag": "leaf", "value": "$brand", "span": { "start": 0, "end": 6 } },
126
+ { "_tag": "leaf", "value": "$", "span": { "start": 0, "end": 1 } },
127
+ { "_tag": "leaf", "value": "brand", "span": { "start": 1, "end": 6 } },
89
128
  { "_tag": "leaf", "value": ":", "span": { "start": 6, "end": 7 } },
90
- { "_tag": "node", "type": "DirectJessColor", "grammarType": "DirectJessColor", "span": { "start": 8, "end": 15 },
91
- "children": [ { "_tag": "leaf", "value": "#3366ff", "span": { "start": 8, "end": 15 } } ] },
129
+ { "_tag": "node", "type": "Value", "grammarType": "Value", "span": { "start": 8, "end": 15 },
130
+ "children": [
131
+ { "_tag": "node", "type": "ValueTerm", "grammarType": "ValueTerm", "span": { "start": 8, "end": 15 },
132
+ "children": [
133
+ { "_tag": "node", "type": "ValueSpaceGroup", "grammarType": "ValueSpaceGroup", "span": { "start": 8, "end": 15 },
134
+ "children": [
135
+ { "_tag": "node", "type": "ValueAtom", "grammarType": "ValueAtom", "span": { "start": 8, "end": 15 },
136
+ "children": [
137
+ { "_tag": "node", "type": "Color", "grammarType": "Color", "span": { "start": 8, "end": 15 },
138
+ "children": [ { "_tag": "leaf", "value": "#3366ff", "span": { "start": 8, "end": 15 } } ] }
139
+ ] }
140
+ ] }
141
+ ] }
142
+ ] },
92
143
  { "_tag": "leaf", "value": ";", "span": { "start": 15, "end": 16 } }
93
144
  ] }
94
145
  ]
95
146
  }
96
147
  ```
97
148
 
98
- Jess-specific grammar rules include `DirectJessVarDeclaration` (`$x: …`), `DirectJessVarReference` / `DirectJessReferenceCall` (`$x`, `$x.prop`, `$x[0]`, callable chains), `DirectJessExpression*` (inside `$(…)`), `DirectJessMixinDef`, `DirectJessMixinCall`, `DirectJessInterpolatedSimple` (`.widget-${side}`), and the `@-compose`/`@-export`/`@-from`/`@-use` import at-rules.
149
+ Jess-specific grammar rules include `VariableDeclaration` (`$x: …`), `VariableReference` / `ReferenceCall` (`$x`, `$x.prop`, `$x[0]`, callable chains), `Expression*` (inside `$(…)`), `MixinDefinition`, `MixinCall`, `InterpolatedSimple` (`.widget-${side}`), and the `@-compose`/`@-export`/`@-from`/`@-use` import at-rules.
99
150
 
100
151
  Pass `{ collapse: true }` to request parseman's transparent-wrapper collapse while preserving source leaves and grammar ownership.
101
152
 
@@ -0,0 +1,193 @@
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 Jess 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 Jess parser. */
12
+ var JessParseError = 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 ?? `Jess parser error.${detail}`);
25
+ this.name = "JessParseError";
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
+ //#endregion
37
+ //#region src/parse-with.ts
38
+ /**
39
+ * The `parse()` body and the `$apply`/`$extend` selector policy checks, shared
40
+ * by the two AST entries.
41
+ *
42
+ * The grammar table arrives as an argument rather than being chosen from a
43
+ * boolean inside this module: Node does not tree-shake, so a module that names
44
+ * both compiled tables executes both at load time. Each entry imports exactly
45
+ * the one table it parses with, and this module imports none.
46
+ */
47
+ function isStylesheet(value) {
48
+ return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "rules" in value && Array.isArray(value.rules);
49
+ }
50
+ const DEFAULT_APPLY_SELECTOR_KINDS = ["class"];
51
+ const DEFAULT_EXTEND_SELECTOR_KINDS = ["class", "placeholder"];
52
+ function selectorPolicyError(message) {
53
+ return new JessParseError(0, [message]);
54
+ }
55
+ function isClassSelector(simple) {
56
+ return simple.interp === null && typeof simple.text === "string" && simple.text.startsWith(".") && simple.text.length > 1;
57
+ }
58
+ /**
59
+ * A lone parent-ref target (`&`). Admitted only on the extend path: `$extend &`
60
+ * parses and no-op-matches at eval, mirroring Less `:extend(&)`. `$apply` stays
61
+ * class-only — a parent-ref carries no utility class to compose.
62
+ *
63
+ * The parser admits `&` because it is a legitimate simple-selector SHAPE; that
64
+ * `$extend &` can only ever no-op (a selector cannot extend itself) is a SEMANTIC
65
+ * fact, not a parse concern. The no-op is surfaced (not rejected) as
66
+ * diagnostics-core lint `lint/no-self-extend`; see DESIGN-DECISIONS ledger X11.
67
+ */
68
+ function isBareParentRef(simple) {
69
+ return simple.type === "SimpleSelector" && simple.interp === null && simple.text === "&";
70
+ }
71
+ function isTermAllowed(term, allowed, isExtend) {
72
+ if (term.type === "CompoundSelector") return allowed.has("compound") || term.value.length === 1 && isSimpleAllowed(term.value[0], allowed, isExtend);
73
+ return isSimpleAllowed(term, allowed, isExtend);
74
+ }
75
+ function isSimpleAllowed(simple, allowed, isExtend) {
76
+ if (isExtend && isBareParentRef(simple)) return true;
77
+ if (simple.type === "PseudoSelector") return allowed.has("simple") || allowed.has("pseudo");
78
+ return allowed.has("class") && isClassSelector(simple) || allowed.has("placeholder") && (0, _jesscss_core_ast.simpleSelectorIsPlaceholder)(simple) || allowed.has("simple") || allowed.has("basic");
79
+ }
80
+ function isBranchAllowed(branch, allowed, isExtend) {
81
+ return branch.type === "ComplexSelector" || branch.type === "RelativeSelector" ? allowed.has("complex") : isTermAllowed(branch, allowed, isExtend);
82
+ }
83
+ function validateSelectorList(label, selector, allowedKinds) {
84
+ const allowed = new Set(allowedKinds);
85
+ if (!selector.selectors.every((item) => isBranchAllowed(item, allowed, true))) throw selectorPolicyError(`${label} selector is not allowed by allowExtendSelectors.`);
86
+ }
87
+ function validateApply(node, allowedKinds) {
88
+ const allowed = new Set(allowedKinds);
89
+ if (!node.selectors.every((selector) => isTermAllowed(selector, allowed, false))) throw selectorPolicyError("$apply target is not allowed by allowApplySelectors.");
90
+ }
91
+ function validateRuleset(node, options) {
92
+ for (const instruction of node.extendInstructions ?? []) validateSelectorList("$extend", instruction.target, options.allowExtendSelectors);
93
+ validateStatements(node.rules, options);
94
+ }
95
+ function validateStatements(rules, options) {
96
+ for (const node of rules) switch (node.type) {
97
+ case "Ruleset":
98
+ validateRuleset(node, options);
99
+ break;
100
+ case "MixinDefinition":
101
+ case "For":
102
+ case "AtRuleBlock":
103
+ validateStatements(node.rules, options);
104
+ break;
105
+ case "If":
106
+ for (const branch of node.branches) validateStatements(branch.rules, options);
107
+ break;
108
+ case "Apply":
109
+ validateApply(node, options.allowApplySelectors);
110
+ break;
111
+ default: break;
112
+ }
113
+ }
114
+ function validateJessOptions(document, options = {}) {
115
+ validateStatements(document.rules, {
116
+ allowApplySelectors: options.allowApplySelectors ?? DEFAULT_APPLY_SELECTOR_KINDS,
117
+ allowExtendSelectors: options.allowExtendSelectors ?? DEFAULT_EXTEND_SELECTOR_KINDS
118
+ });
119
+ }
120
+ /**
121
+ * Line/column at a bare offset. The leftover-input offset is not the start of
122
+ * any span the run returned — `result.span` covers the text that *was*
123
+ * consumed — so the position has to be derived from the offset itself. Only
124
+ * ever reached on a throw path, so building the index here costs a parse
125
+ * nothing.
126
+ */
127
+ function positionAt(input, offset) {
128
+ const { line, col } = (0, parseman.offsetToLineCol)((0, parseman.buildLineIndex)(input), offset);
129
+ return {
130
+ line,
131
+ column: col
132
+ };
133
+ }
134
+ /**
135
+ * Line/column for a failure span. The compiled table without line tracking
136
+ * leaves a span's line fields unset, so fall back to deriving them; an error
137
+ * that reports an offset but no line is barely actionable in an editor.
138
+ */
139
+ function lineOptions(input, span) {
140
+ if (span.startLine === void 0) return positionAt(input, span.start);
141
+ return {
142
+ line: span.startLine,
143
+ column: span.startColumn,
144
+ endLine: span.endLine,
145
+ endColumn: span.endColumn
146
+ };
147
+ }
148
+ function parseWith(grammar, input, options = {}) {
149
+ const entry = grammar.Stylesheet;
150
+ const trivia = grammar.whitespace;
151
+ if (entry === void 0 || trivia === void 0) throw new TypeError("Jess AST grammar is missing its public document entry.");
152
+ const result = (0, parseman.run)(entry, input, {
153
+ trivia,
154
+ rootTrivia: { select: require_trivia_labels.commentTriviaLabels }
155
+ });
156
+ if (!result.ok) throw new JessParseError(result.span.start, result.expected, lineOptions(input, result.span));
157
+ if (result.unconsumedFrom !== null) {
158
+ if (isStylesheet(result.value) && result.value.rules.length > 0) throw new JessParseError(result.unconsumedFrom, [], {
159
+ message: "Unexpected Jess input after a complete stylesheet.",
160
+ reason: "The parser read a complete Jess stylesheet before this point, so the remaining text sits outside every rule, declaration, and at-rule.",
161
+ fix: "Delete the trailing text, or remove the extra \"}\" — over-closing a nested block ends the stylesheet early.",
162
+ ...positionAt(input, result.unconsumedFrom)
163
+ });
164
+ throw new JessParseError(result.unconsumedFrom, [], {
165
+ message: "Unexpected Jess syntax.",
166
+ reason: "The parser could not read this token as the start of a Jess rule, declaration, assignment, or at-rule.",
167
+ fix: "Remove the token, or rewrite it as a selector block, a \"$name: value\" assignment, or an at-rule.",
168
+ ...positionAt(input, result.unconsumedFrom)
169
+ });
170
+ }
171
+ if (!isStylesheet(result.value)) throw new JessParseError(result.span.end, [], {
172
+ message: "Jess parser did not produce a stylesheet.",
173
+ reason: "The Jess parser matched the input but returned a value that is not a stylesheet document.",
174
+ fix: "Report this as a parser bug with the source that triggered it.",
175
+ ...positionAt(input, result.span.end)
176
+ });
177
+ const document = (0, _jesscss_core_ast.withTriviaMap)((0, _jesscss_core_ast.withSourceSpan)(result.value, result.span), (0, _jesscss_core_ast.createTriviaMapFromParseman)(input, result.rootTrivia?.index));
178
+ validateJessOptions(document, options);
179
+ return document;
180
+ }
181
+ //#endregion
182
+ Object.defineProperty(exports, "JessParseError", {
183
+ enumerable: true,
184
+ get: function() {
185
+ return JessParseError;
186
+ }
187
+ });
188
+ Object.defineProperty(exports, "parseWith", {
189
+ enumerable: true,
190
+ get: function() {
191
+ return parseWith;
192
+ }
193
+ });
@@ -0,0 +1,182 @@
1
+ import { t as commentTriviaLabels } from "./trivia-labels.js";
2
+ import { buildLineIndex, offsetToLineCol, run } from "parseman";
3
+ import { createTriviaMapFromParseman, simpleSelectorIsPlaceholder, withSourceSpan, withTriviaMap } from "@jesscss/core/ast";
4
+ //#region src/parse-error.ts
5
+ /**
6
+ * The public Jess 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 Jess parser. */
12
+ var JessParseError = 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 ?? `Jess parser error.${detail}`);
25
+ this.name = "JessParseError";
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
+ //#endregion
37
+ //#region src/parse-with.ts
38
+ /**
39
+ * The `parse()` body and the `$apply`/`$extend` selector policy checks, shared
40
+ * by the two AST entries.
41
+ *
42
+ * The grammar table arrives as an argument rather than being chosen from a
43
+ * boolean inside this module: Node does not tree-shake, so a module that names
44
+ * both compiled tables executes both at load time. Each entry imports exactly
45
+ * the one table it parses with, and this module imports none.
46
+ */
47
+ function isStylesheet(value) {
48
+ return typeof value === "object" && value !== null && "type" in value && value.type === "Stylesheet" && "rules" in value && Array.isArray(value.rules);
49
+ }
50
+ const DEFAULT_APPLY_SELECTOR_KINDS = ["class"];
51
+ const DEFAULT_EXTEND_SELECTOR_KINDS = ["class", "placeholder"];
52
+ function selectorPolicyError(message) {
53
+ return new JessParseError(0, [message]);
54
+ }
55
+ function isClassSelector(simple) {
56
+ return simple.interp === null && typeof simple.text === "string" && simple.text.startsWith(".") && simple.text.length > 1;
57
+ }
58
+ /**
59
+ * A lone parent-ref target (`&`). Admitted only on the extend path: `$extend &`
60
+ * parses and no-op-matches at eval, mirroring Less `:extend(&)`. `$apply` stays
61
+ * class-only — a parent-ref carries no utility class to compose.
62
+ *
63
+ * The parser admits `&` because it is a legitimate simple-selector SHAPE; that
64
+ * `$extend &` can only ever no-op (a selector cannot extend itself) is a SEMANTIC
65
+ * fact, not a parse concern. The no-op is surfaced (not rejected) as
66
+ * diagnostics-core lint `lint/no-self-extend`; see DESIGN-DECISIONS ledger X11.
67
+ */
68
+ function isBareParentRef(simple) {
69
+ return simple.type === "SimpleSelector" && simple.interp === null && simple.text === "&";
70
+ }
71
+ function isTermAllowed(term, allowed, isExtend) {
72
+ if (term.type === "CompoundSelector") return allowed.has("compound") || term.value.length === 1 && isSimpleAllowed(term.value[0], allowed, isExtend);
73
+ return isSimpleAllowed(term, allowed, isExtend);
74
+ }
75
+ function isSimpleAllowed(simple, allowed, isExtend) {
76
+ if (isExtend && isBareParentRef(simple)) return true;
77
+ if (simple.type === "PseudoSelector") return allowed.has("simple") || allowed.has("pseudo");
78
+ return allowed.has("class") && isClassSelector(simple) || allowed.has("placeholder") && simpleSelectorIsPlaceholder(simple) || allowed.has("simple") || allowed.has("basic");
79
+ }
80
+ function isBranchAllowed(branch, allowed, isExtend) {
81
+ return branch.type === "ComplexSelector" || branch.type === "RelativeSelector" ? allowed.has("complex") : isTermAllowed(branch, allowed, isExtend);
82
+ }
83
+ function validateSelectorList(label, selector, allowedKinds) {
84
+ const allowed = new Set(allowedKinds);
85
+ if (!selector.selectors.every((item) => isBranchAllowed(item, allowed, true))) throw selectorPolicyError(`${label} selector is not allowed by allowExtendSelectors.`);
86
+ }
87
+ function validateApply(node, allowedKinds) {
88
+ const allowed = new Set(allowedKinds);
89
+ if (!node.selectors.every((selector) => isTermAllowed(selector, allowed, false))) throw selectorPolicyError("$apply target is not allowed by allowApplySelectors.");
90
+ }
91
+ function validateRuleset(node, options) {
92
+ for (const instruction of node.extendInstructions ?? []) validateSelectorList("$extend", instruction.target, options.allowExtendSelectors);
93
+ validateStatements(node.rules, options);
94
+ }
95
+ function validateStatements(rules, options) {
96
+ for (const node of rules) switch (node.type) {
97
+ case "Ruleset":
98
+ validateRuleset(node, options);
99
+ break;
100
+ case "MixinDefinition":
101
+ case "For":
102
+ case "AtRuleBlock":
103
+ validateStatements(node.rules, options);
104
+ break;
105
+ case "If":
106
+ for (const branch of node.branches) validateStatements(branch.rules, options);
107
+ break;
108
+ case "Apply":
109
+ validateApply(node, options.allowApplySelectors);
110
+ break;
111
+ default: break;
112
+ }
113
+ }
114
+ function validateJessOptions(document, options = {}) {
115
+ validateStatements(document.rules, {
116
+ allowApplySelectors: options.allowApplySelectors ?? DEFAULT_APPLY_SELECTOR_KINDS,
117
+ allowExtendSelectors: options.allowExtendSelectors ?? DEFAULT_EXTEND_SELECTOR_KINDS
118
+ });
119
+ }
120
+ /**
121
+ * Line/column at a bare offset. The leftover-input offset is not the start of
122
+ * any span the run returned — `result.span` covers the text that *was*
123
+ * consumed — so the position has to be derived from the offset itself. Only
124
+ * ever reached on a throw path, so building the index here costs a parse
125
+ * nothing.
126
+ */
127
+ function positionAt(input, offset) {
128
+ const { line, col } = offsetToLineCol(buildLineIndex(input), offset);
129
+ return {
130
+ line,
131
+ column: col
132
+ };
133
+ }
134
+ /**
135
+ * Line/column for a failure span. The compiled table without line tracking
136
+ * leaves a span's line fields unset, so fall back to deriving them; an error
137
+ * that reports an offset but no line is barely actionable in an editor.
138
+ */
139
+ function lineOptions(input, span) {
140
+ if (span.startLine === void 0) return positionAt(input, span.start);
141
+ return {
142
+ line: span.startLine,
143
+ column: span.startColumn,
144
+ endLine: span.endLine,
145
+ endColumn: span.endColumn
146
+ };
147
+ }
148
+ function parseWith(grammar, input, options = {}) {
149
+ const entry = grammar.Stylesheet;
150
+ const trivia = grammar.whitespace;
151
+ if (entry === void 0 || trivia === void 0) throw new TypeError("Jess AST grammar is missing its public document entry.");
152
+ const result = run(entry, input, {
153
+ trivia,
154
+ rootTrivia: { select: commentTriviaLabels }
155
+ });
156
+ if (!result.ok) throw new JessParseError(result.span.start, result.expected, lineOptions(input, result.span));
157
+ if (result.unconsumedFrom !== null) {
158
+ if (isStylesheet(result.value) && result.value.rules.length > 0) throw new JessParseError(result.unconsumedFrom, [], {
159
+ message: "Unexpected Jess input after a complete stylesheet.",
160
+ reason: "The parser read a complete Jess stylesheet before this point, so the remaining text sits outside every rule, declaration, and at-rule.",
161
+ fix: "Delete the trailing text, or remove the extra \"}\" — over-closing a nested block ends the stylesheet early.",
162
+ ...positionAt(input, result.unconsumedFrom)
163
+ });
164
+ throw new JessParseError(result.unconsumedFrom, [], {
165
+ message: "Unexpected Jess syntax.",
166
+ reason: "The parser could not read this token as the start of a Jess rule, declaration, assignment, or at-rule.",
167
+ fix: "Remove the token, or rewrite it as a selector block, a \"$name: value\" assignment, or an at-rule.",
168
+ ...positionAt(input, result.unconsumedFrom)
169
+ });
170
+ }
171
+ if (!isStylesheet(result.value)) throw new JessParseError(result.span.end, [], {
172
+ message: "Jess parser did not produce a stylesheet.",
173
+ reason: "The Jess parser matched the input but returned a value that is not a stylesheet document.",
174
+ fix: "Report this as a parser bug with the source that triggered it.",
175
+ ...positionAt(input, result.span.end)
176
+ });
177
+ const document = withTriviaMap(withSourceSpan(result.value, result.span), createTriviaMapFromParseman(input, result.rootTrivia?.index));
178
+ validateJessOptions(document, options);
179
+ return document;
180
+ }
181
+ //#endregion
182
+ export { JessParseError as n, parseWith as t };
@@ -0,0 +1,18 @@
1
+ //#region src/trivia-labels.ts
2
+ /**
3
+ * Root-trivia label selection for the Jess 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 Jess 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 Jess 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 Jess to a CST whose spans carry line and column facts. */
14
+ function parseJessCst(input, startRule = "Stylesheet", options) {
15
+ return (0, _jesscss_css_parser_cst_host.parseCst)(src_grammar_cst_positions_js.jessCstPositionsGrammar, input, startRule, options, require_trivia_labels.commentTriviaLabels);
16
+ }
17
+ /** Incremental (`.edit()`-able) Jess document with line and column facts. */
18
+ function parseJessDoc(input, startRule = "Stylesheet") {
19
+ return (0, _jesscss_css_parser_cst_host.parseDocCst)(src_grammar_cst_positions_js.jessCstPositionsGrammar, input, startRule);
20
+ }
21
+ //#endregion
22
+ exports.commentTriviaLabels = require_trivia_labels.commentTriviaLabels;
23
+ exports.parseJessCst = parseJessCst;
24
+ exports.parseJessDoc = parseJessDoc;
@@ -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 { jessCstPositionsGrammar } from "../grammar/cst/positions.js";
4
+ //#region src/cst/positions.ts
5
+ /**
6
+ * The line-aware Jess 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 Jess to a CST whose spans carry line and column facts. */
13
+ function parseJessCst(input, startRule = "Stylesheet", options) {
14
+ return parseCst(jessCstPositionsGrammar, input, startRule, options, commentTriviaLabels);
15
+ }
16
+ /** Incremental (`.edit()`-able) Jess document with line and column facts. */
17
+ function parseJessDoc(input, startRule = "Stylesheet") {
18
+ return parseDocCst(jessCstPositionsGrammar, input, startRule);
19
+ }
20
+ //#endregion
21
+ export { commentTriviaLabels, parseJessCst, parseJessDoc };
package/lib/cst.cjs CHANGED
@@ -1,14 +1,21 @@
1
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");
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 Jess to a CST. Spans carry offsets only; for line/column facts import
8
+ * the same functions from `@jesscss/jess-parser/cst/positions`, which binds the
9
+ * line-aware compiled table. This entry never loads that table.
10
+ */
5
11
  function parseJessCst(input, startRule = "Stylesheet", options) {
6
- return (0, _jesscss_css_parser_cst.parseCst)(require_grammar.jessCstGrammar, input, startRule, options);
12
+ return (0, _jesscss_css_parser_cst_host.parseCst)(src_grammar_cst_js.jessCstGrammar, input, startRule, options, require_trivia_labels.commentTriviaLabels);
7
13
  }
8
- /** Incremental (`.edit()`-able) Jess document — mirrors `parseLessDoc`/`parseScssDoc`. */
14
+ /** Incremental (`.edit()`-able) Jess document — see `parseDocCst`. */
9
15
  function parseJessDoc(input, startRule = "Stylesheet") {
10
- return (0, _jesscss_css_parser_cst.parseDocCst)(require_grammar.jessCstGrammar, input, startRule);
16
+ return (0, _jesscss_css_parser_cst_host.parseDocCst)(src_grammar_cst_js.jessCstGrammar, input, startRule);
11
17
  }
12
18
  //#endregion
19
+ exports.commentTriviaLabels = require_trivia_labels.commentTriviaLabels;
13
20
  exports.parseJessCst = parseJessCst;
14
21
  exports.parseJessDoc = parseJessDoc;
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 Jess to a CST. Spans carry offsets only; for line/column facts import
5
+ * the same functions from `@jesscss/jess-parser/cst/positions`, which binds the
6
+ * line-aware compiled table. This entry never loads that table.
7
+ */
2
8
  export declare function parseJessCst(input: string, startRule?: string, options?: CssCstParseOptions): CssCstParseResult;
3
- /** Incremental (`.edit()`-able) Jess document — mirrors `parseLessDoc`/`parseScssDoc`. */
9
+ /** Incremental (`.edit()`-able) Jess document — see `parseDocCst`. */
4
10
  export declare function parseJessDoc(input: string, startRule?: string): ParseDoc<CssCstNode>;
5
- export type { CssCstChild as JessCstChild, CssCstError as JessCstError, CssCstLeaf as JessCstLeaf, CssCstNode as JessCstNode, CssCstParseOptions as JessCstParseOptions, CssCstParseResult as JessCstParseResult, CssCstType as JessCstType } from '@jesscss/css-parser/cst';
11
+ export type { CssCstChild as JessCstChild, CssCstError as JessCstError, CssCstLeaf as JessCstLeaf, CssCstNode as JessCstNode, CssCstParseOptions as JessCstParseOptions, CssCstParseResult as JessCstParseResult, CssCstType as JessCstType } from '@jesscss/css-parser/cst-host';
package/lib/cst.js CHANGED
@@ -1,12 +1,18 @@
1
- import { jessCstGrammar } from "./grammar.js";
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 { jessCstGrammar } from "./grammar/cst.js";
3
4
  //#region src/cst.ts
5
+ /**
6
+ * Parse Jess to a CST. Spans carry offsets only; for line/column facts import
7
+ * the same functions from `@jesscss/jess-parser/cst/positions`, which binds the
8
+ * line-aware compiled table. This entry never loads that table.
9
+ */
4
10
  function parseJessCst(input, startRule = "Stylesheet", options) {
5
- return parseCst(jessCstGrammar, input, startRule, options);
11
+ return parseCst(jessCstGrammar, input, startRule, options, commentTriviaLabels);
6
12
  }
7
- /** Incremental (`.edit()`-able) Jess document — mirrors `parseLessDoc`/`parseScssDoc`. */
13
+ /** Incremental (`.edit()`-able) Jess document — see `parseDocCst`. */
8
14
  function parseJessDoc(input, startRule = "Stylesheet") {
9
15
  return parseDocCst(jessCstGrammar, input, startRule);
10
16
  }
11
17
  //#endregion
12
- export { parseJessCst, parseJessDoc };
18
+ export { commentTriviaLabels, parseJessCst, parseJessDoc };