@jesscss/scss-parser 2.0.0-alpha.7

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 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,132 @@
1
+ # @jesscss/scss-parser
2
+
3
+ A [SCSS/Sass](https://sass-lang.com/) parser built on [parseman](https://www.npmjs.com/package/parseman). The grammar is the CSS grammar plus an SCSS delta: `scssGrammar = compose([cssGrammar, <SCSS delta>])`, layered on the shared CSS base in `@jesscss/css-parser`.
4
+
5
+ The goal is **parse coverage**: not every Sass/SCSS feature is necessarily *evaluated*, but the surface syntax should parse. This is the earliest-stage of the four Jess parsers (`2.0.0-alpha.1`).
6
+
7
+ Two ways to use it:
8
+
9
+ - **As part of Jess** — the default `.` entry is wired into `@jesscss/core` and produces the core AST the Jess compiler evaluates. This is the internal, core-coupled path.
10
+ - **As a standalone CST parser** — the `./cst` entry has **no dependency on `@jesscss/core`**. Install just this package and parse SCSS source text into a concrete syntax tree (CST). You can also plug your own builders onto the grammar to produce your own AST instead of the default CST.
11
+
12
+ ## Install
13
+
14
+ ```sh
15
+ npm install @jesscss/scss-parser
16
+ ```
17
+
18
+ `@jesscss/core` is an **optional** peer dependency — needed only for the core-coupled `.` entry, not for `./cst` or `./grammar`.
19
+
20
+ ## Standalone usage (core-free)
21
+
22
+ ```js
23
+ import { parseScssCst } from '@jesscss/scss-parser/cst'
24
+
25
+ const result = parseScssCst('$c: red;\n.foo { color: $c; }')
26
+
27
+ result.ok // true
28
+ result.errors // ParseError[] (empty when ok)
29
+ result.unconsumedFrom // index of first unparsed char, or null
30
+ result.tree // the CST root (a StyleSheet node)
31
+ ```
32
+
33
+ Signature:
34
+
35
+ ```ts
36
+ parseScssCst(input: string, startRule = 'Stylesheet', options?: { collapse?: boolean }): ScssCstParseResult
37
+ ```
38
+
39
+ Pass a different `startRule` (any capitalized grammar rule) to parse a fragment.
40
+
41
+ ## Public API
42
+
43
+ | Entry | Export | Purpose |
44
+ | --- | --- | --- |
45
+ | `@jesscss/scss-parser/cst` | `parseScssCst` | Core-free parse of an SCSS string to a CST. |
46
+ | `@jesscss/scss-parser/cst` | `ScssCstNode`, `ScssCstLeaf`, `ScssCstError`, `ScssCstChild`, `ScssCstParseResult`, `ScssCstType` (types) | CST type definitions (aliases of the shared `@jesscss/css-parser/cst` types). |
47
+ | `@jesscss/scss-parser/grammar` | `scssGrammar` | The compiled SCSS grammar (a rule map). Extend it with `compose()` or drive it directly with parseman's `run`. |
48
+ | `@jesscss/scss-parser` (`.`) | `ScssParser` (also `Parser`), `parseScssFn`, `scssGrammar`, tokens, … | The Jess-internal barrel. **Core-coupled** (the functional parser builds the core AST). Prefer `./cst` if you don't need `@jesscss/core`. |
49
+ | `@jesscss/scss-parser/jess` | `ScssParser`, `ScssGrammar`, `parseScssFn`, … | Internal Jess-facing surface. |
50
+
51
+ ## Default CST shape
52
+
53
+ The CST is parseman's, produced by the shared `cssCstBuildHost`. Three kinds of node:
54
+
55
+ - **node** — `{ _tag: 'node', type, grammarType, span: { start, end }, state, children }` (`grammarType` = raw rule name; `type` = friendly public name).
56
+ - **leaf** — `{ _tag: 'leaf', value, span }` for terminals.
57
+ - **error** — `{ _tag: 'error', type, span, expected, children, state }` where recovery happened.
58
+
59
+ Spans are `[start, end)` offsets; whitespace and comments are trivia and do not appear as children.
60
+
61
+ Parsing `$c: red;\n.foo { color: $c; }` yields (abridged):
62
+
63
+ ```jsonc
64
+ {
65
+ "_tag": "node", "type": "StyleSheet", "grammarType": "Stylesheet",
66
+ "children": [
67
+ { "_tag": "node", "type": "VarDeclaration", "grammarType": "VarDeclaration", "span": { "start": 0, "end": 8 },
68
+ "children": [
69
+ { "_tag": "leaf", "value": "$c" }, { "_tag": "leaf", "value": ":" },
70
+ { "_tag": "node", "type": "NamedColor", "grammarType": "NamedColor",
71
+ "children": [ { "_tag": "leaf", "value": "red" } ] },
72
+ { "_tag": "leaf", "value": ";" }
73
+ ] },
74
+ { "_tag": "node", "type": "QualifiedRule", "grammarType": "Ruleset", "span": { "start": 9, "end": 28 },
75
+ "children": [
76
+ { "_tag": "node", "type": "InterpolatedSelector", "grammarType": "InterpolatedSelector",
77
+ "children": [ { "_tag": "leaf", "value": "." }, { "_tag": "leaf", "value": "foo" } ] },
78
+ { "_tag": "leaf", "value": "{" },
79
+ { "_tag": "node", "type": "Declaration", "grammarType": "Declaration",
80
+ "children": [
81
+ { "_tag": "leaf", "value": "color" }, { "_tag": "leaf", "value": ":" },
82
+ { "_tag": "node", "type": "Reference", "grammarType": "Reference",
83
+ "children": [ { "_tag": "leaf", "value": "$c" } ] },
84
+ { "_tag": "leaf", "value": ";" }
85
+ ] },
86
+ { "_tag": "leaf", "value": "}" }
87
+ ] }
88
+ ]
89
+ }
90
+ ```
91
+
92
+ 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`.
93
+
94
+ Pass `{ collapse: true }` to unwrap single-child wrapper types (`Reference`, `NamedColor`, `InterpolatedSelector`) into their child.
95
+
96
+ ## Extending with your own builders
97
+
98
+ 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:
99
+
100
+ ```js
101
+ import { run } from 'parseman'
102
+ import { scssGrammar } from '@jesscss/scss-parser/grammar'
103
+
104
+ const myHost = (type, children, fields, span) => ({ type, span, children: children.filter(Boolean) })
105
+
106
+ const result = run(scssGrammar.Stylesheet, '$c: red; .foo { color: $c; }', {
107
+ build: myHost,
108
+ trivia: scssGrammar.rw
109
+ })
110
+
111
+ result.value // the root node your host returned
112
+ ```
113
+
114
+ The `BuildHost` signature (from parseman):
115
+
116
+ ```ts
117
+ type BuildHost = (
118
+ type: string,
119
+ children: readonly unknown[],
120
+ fields: FieldMap | undefined,
121
+ span: { start: number; end: number },
122
+ rawChildren: readonly unknown[],
123
+ triviaLog: readonly number[],
124
+ state: unknown
125
+ ) => unknown
126
+ ```
127
+
128
+ `parseScssCst(...)` is this pattern with the shared `cssCstBuildHost` (see `@jesscss/css-parser`, `src/cst.ts`) as a reference host.
129
+
130
+ ## Part of Jess
131
+
132
+ This package is developed as part of [Jess](https://github.com/jesscss/jess). The core-coupled `.` entry integrates with `@jesscss/core`; the `./cst` and `./grammar` entries are usable on their own. SCSS is the least-mature of the Jess dialects — prefer `@jesscss/css-parser` / `@jesscss/less-parser` for production use.
@@ -0,0 +1,154 @@
1
+ /**
2
+ * ScssGrammar — Parséman-based SCSS parser, extending LessGrammar.
3
+ *
4
+ * Adds SCSS-specific grammar on top of Less (which in turn extends CSS):
5
+ * - Variable declarations: $var: value [!default|!global]; → VarDeclaration
6
+ * - Variable references: $var → Reference
7
+ * - Line comments: // ... (added to rw trivia)
8
+ *
9
+ * Inherits from LessGrammar:
10
+ * - Nested rulesets, & ampersand, relative selectors
11
+ * - anyDeclaration entry point
12
+ * - atRuleBody, declarationList, Stylesheet overrides
13
+ * - Less merge operators on Declaration (harmless for SCSS)
14
+ *
15
+ * Chevrotain note: in the Chevrotain architecture, ScssRecursiveParser
16
+ * extends CssRecursiveParser independently of LessRecursiveParser.
17
+ * Here we take the Parséman inheritance chain
18
+ * CssParser → LessGrammar → ScssGrammar to maximise code reuse.
19
+ */
20
+ import type { FieldMap, Span } from 'parseman';
21
+ import type { CSTLeaf, CSTError } from 'parseman';
22
+ import { LessGrammar } from '@jesscss/less-parser/jess';
23
+ import { type Node, type LocationInfo, type TreeContext, Rules, Quoted } from '@jesscss/core';
24
+ type JessNode = Node<any, any>;
25
+ type Child = JessNode | CSTLeaf | CSTError;
26
+ export declare class ScssGrammar extends LessGrammar {
27
+ rw: import("parseman").Combinator<string>;
28
+ protected _trivia: import("parseman").Combinator<string>;
29
+ protected _parseContext?: TreeContext;
30
+ setContext(context?: TreeContext): void;
31
+ scssVar: import("parseman").Combinator<string>;
32
+ VarDeclaration: (g: any) => import("parseman").Combinator<[unknown, string, unknown, string | null, string | null]>;
33
+ Reference: (g: any) => any;
34
+ protected buildNode(type: string, span: Span, children: ReadonlyArray<JessNode | CSTLeaf | CSTError>, _state: unknown, _rawChildren: ReadonlyArray<{
35
+ _tag: string;
36
+ }>, fields?: FieldMap, triviaLog?: readonly number[]): JessNode;
37
+ private _buildScssVarDeclaration;
38
+ /**
39
+ * `ns.$member: value [!default|!global];` — a namespaced variable ASSIGNMENT.
40
+ * Built as a `VarDeclaration` whose name carries the namespace (`ns.member`);
41
+ * `!default` → conditional-assign, `!global` → `setDefined`. Mirrors the
42
+ * member-read shape (`Reference{ target, key }`) on the write side while
43
+ * staying within the `string | Interpolated` declaration-name contract.
44
+ */
45
+ private _buildScssNsVarDeclaration;
46
+ private _buildScssReference;
47
+ /**
48
+ * `left [op right]` → Condition, or a bare operand when there is no operator.
49
+ * `!=` desugars to `=` + negate (matches the Chevrotain scssComparison).
50
+ */
51
+ private _buildScssComparison;
52
+ /**
53
+ * Every condition term is wrapped in a Paren, matching the Chevrotain
54
+ * `scssConditionInParens` production (both the `( … )` group and the bare
55
+ * comparison / value branch wrap their result in a single Paren).
56
+ */
57
+ private _buildScssCondInParens;
58
+ /** Optional leading `not` negates the term. */
59
+ private _buildScssCondTerm;
60
+ /** Fold a left-associative `and` / `or` chain of terms into Conditions. */
61
+ private _buildScssCondJoin;
62
+ /** A `{ … }` control-block body → Rules. */
63
+ private _buildScssRules;
64
+ /**
65
+ * `@if cond { … } (@else if cond { … })* (@else { … })?` → nested `If` chain.
66
+ * Children arrive as alternating condition / Rules nodes, with an optional
67
+ * trailing bare Rules (the final `@else`). Fold from the last branch inward.
68
+ */
69
+ private _buildScssIf;
70
+ /** A `$name` loop-binding with no value (`paramVar` — prints as `$name`). */
71
+ private _scssParamVar;
72
+ /**
73
+ * `@each $a[, $b …] in <expr> { … }` → `For` with a node iterable.
74
+ * Normalizes to Jess `$for ($a of …)` / `$for ([$a, $b] of …)`.
75
+ */
76
+ private _buildScssEach;
77
+ /**
78
+ * `@for $i from <start> (to|through) <end> { … }` → `For` with a range iterable.
79
+ * `through` is inclusive end; `to` is exclusive (`includeEnd: false`).
80
+ */
81
+ private _buildScssFor;
82
+ /** `@while <cond> { … }` → `While`. */
83
+ private _buildScssWhile;
84
+ /** Build a module-qualified or plain mixin `Reference`. */
85
+ private _buildScssMixinName;
86
+ /** `$x: val` keyword arg, `val...` spread, or plain value. */
87
+ private _buildScssCallArg;
88
+ private _buildScssCallArgsInner;
89
+ /** Mixin param: `...$rest`, `$rest...`, `$a: default`, or bare `$a`. */
90
+ private _buildScssMixinParam;
91
+ private _buildScssMixinParams;
92
+ /** `@mixin name($params) { … }` → `Mixin` (inner vars default to private). */
93
+ private _buildScssMixin;
94
+ /** `using ($c, $n)` param list for `@include … using (…)`. */
95
+ private _buildScssIncludeUsing;
96
+ /**
97
+ * `@include name(args) [using (…)] [ { … } ];` → `Call(Reference(type=mixin))`.
98
+ * An optional content block becomes an anonymous visible `Mixin` on the call.
99
+ */
100
+ private _buildScssInclude;
101
+ /** `@content[(args)];` → `Call(Reference('content', type=mixin))`. */
102
+ private _buildScssContent;
103
+ /** `@function name($params) { … }` → `Func` with `returnName: 'result'`. */
104
+ private _buildScssFunction;
105
+ /** `@return <value>;` → `$result: <value>;` */
106
+ private _buildScssReturn;
107
+ private _buildScssInterpBare;
108
+ /** `foo-#{$bar}` name segments → Interpolated(role=name) or plain Any. */
109
+ private _buildScssInterpolatedName;
110
+ private _buildScssInterpValue;
111
+ private _buildScssInterpolatedSelector;
112
+ private _scssInterpDeclName;
113
+ private _buildScssDeclaration;
114
+ private _buildScssCustomDeclaration;
115
+ protected _buildQuoted(children: ReadonlyArray<Child>, loc: LocationInfo): Node<any, any> | Quoted;
116
+ /** `("k": v, …)` pair inside a map literal. */
117
+ private _buildScssMapPair;
118
+ private _buildScssMapLiteral;
119
+ /** `ns.$var`, `ns.fn(…)`, `ns.\#foo(…)`, or a plain ident. */
120
+ private _buildScssIdentValue;
121
+ protected _buildStylesheet(children: ReadonlyArray<Child>, loc: LocationInfo): Rules<never, import("@jesscss/core").RulesOptions & Record<string, any> & {
122
+ semi?: boolean;
123
+ }>;
124
+ private _flattenScssImportLists;
125
+ private _buildScssNestedProps;
126
+ private _buildScssDiagnostic;
127
+ private _buildScssAtRootFilter;
128
+ private _buildScssAtRootSelector;
129
+ private _buildScssAtRootPlain;
130
+ private _buildScssWithConfigEntry;
131
+ private _buildScssWithConfig;
132
+ private _buildScssUseAs;
133
+ private _buildScssUse;
134
+ private _buildScssForward;
135
+ private _buildScssPlaceholderSelector;
136
+ private _buildScssPermissiveAtRule;
137
+ private _buildScssLayerBlock;
138
+ protected _buildQueryAtRuleBlock(children: ReadonlyArray<Child>, loc: LocationInfo): JessNode;
139
+ protected _buildScssParen(rawChildren: ReadonlyArray<{
140
+ _tag: string;
141
+ }>, loc: LocationInfo): JessNode;
142
+ private _buildScssExtendTarget;
143
+ private _scssExtendTargetFrom;
144
+ private _buildScssExtend;
145
+ private _buildScssImportItem;
146
+ private _buildScssImportAtRule;
147
+ protected _buildCall(rawChildren: ReadonlyArray<{
148
+ _tag: string;
149
+ }>, loc: LocationInfo): JessNode;
150
+ protected _buildSquareParen(rawChildren: ReadonlyArray<{
151
+ _tag: string;
152
+ }>, loc: LocationInfo): JessNode;
153
+ }
154
+ export {};
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.scssGrammar, 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.scssGrammar, 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 { scssGrammar } 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(scssGrammar, input, startRule, options);
6
+ }
7
+ /** Incremental (`.edit()`-able) SCSS document — see `parseDocCst`. */
8
+ function parseScssDoc(input, startRule = "Stylesheet") {
9
+ return parseDocCst(scssGrammar, input, startRule);
10
+ }
11
+ //#endregion
12
+ export { parseScssCst, parseScssDoc };