@jesscss/less-parser 2.0.0-alpha.5 → 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/README.md +133 -5
- package/lib/builders.d.ts +381 -0
- package/lib/builders.d.ts.map +1 -0
- package/lib/cst.cjs +14 -0
- package/lib/cst.d.ts +6 -0
- package/lib/cst.d.ts.map +1 -0
- package/lib/cst.js +12 -0
- package/lib/functional-parser.cjs +2653 -0
- package/lib/functional-parser.d.ts +18 -0
- package/lib/functional-parser.d.ts.map +1 -0
- package/lib/functional-parser.js +2588 -0
- package/lib/grammar.cjs +30621 -0
- package/lib/grammar.d.ts +2 -0
- package/lib/grammar.d.ts.map +1 -0
- package/lib/grammar.js +30620 -0
- package/lib/index.cjs +18 -0
- package/lib/index.d.ts +9 -32
- package/lib/index.d.ts.map +1 -0
- package/lib/index.js +7 -75
- package/lib/jess.cjs +3968 -0
- package/lib/jess.d.ts +7 -0
- package/lib/jess.d.ts.map +1 -0
- package/lib/jess.js +3962 -0
- package/lib/lessParser.d.ts +38 -0
- package/lib/lessParser.d.ts.map +1 -0
- package/lib/lessRecursiveParser.d.ts +99 -0
- package/lib/lessRecursiveParser.d.ts.map +1 -0
- package/lib/lessTokens.d.ts +4 -3
- package/lib/lessTokens.d.ts.map +1 -0
- package/lib/productions/guards.d.ts +113 -0
- package/lib/productions/guards.d.ts.map +1 -0
- package/lib/productions/index.d.ts +5 -0
- package/lib/productions/index.d.ts.map +1 -0
- package/lib/productions/root.d.ts +38 -0
- package/lib/productions/root.d.ts.map +1 -0
- package/lib/productions/selectors.d.ts +41 -0
- package/lib/productions/selectors.d.ts.map +1 -0
- package/lib/productions/values.d.ts +35 -0
- package/lib/productions/values.d.ts.map +1 -0
- package/lib/utils.d.ts +8 -1
- package/lib/utils.d.ts.map +1 -0
- package/package.json +49 -16
- package/{lib/__tests__/debug-log.js → src/__tests__/debug-log.ts} +20 -19
- package/src/__tests__/wall5-parse.test.ts +67 -0
- package/src/builders.ts +3183 -0
- package/src/cst.ts +25 -0
- package/src/functional-parser.ts +162 -0
- package/src/grammar.ts +869 -0
- package/src/index.ts +19 -0
- package/src/jess.ts +6 -0
- package/src/lessParser.ts +120 -0
- package/src/lessRecursiveParser.ts +279 -0
- package/src/lessTokens.ts +350 -0
- package/src/productions/guards.ts +1066 -0
- package/src/productions/index.ts +29 -0
- package/src/productions/root.ts +1613 -0
- package/src/productions/selectors.ts +1309 -0
- package/src/productions/values.ts +1449 -0
- package/src/utils.ts +178 -0
- package/lib/__tests__/debug-log.d.ts +0 -1
- package/lib/__tests__/debug-log.js.map +0 -1
- package/lib/index.js.map +0 -1
- package/lib/lessActionsParser.d.ts +0 -156
- package/lib/lessActionsParser.js +0 -145
- package/lib/lessActionsParser.js.map +0 -1
- package/lib/lessErrorMessageProvider.d.ts +0 -3
- package/lib/lessErrorMessageProvider.js +0 -4
- package/lib/lessErrorMessageProvider.js.map +0 -1
- package/lib/lessTokens.js +0 -249
- package/lib/lessTokens.js.map +0 -1
- package/lib/productions.d.ts +0 -181
- package/lib/productions.js +0 -3521
- package/lib/productions.js.map +0 -1
- package/lib/utils.js +0 -88
- package/lib/utils.js.map +0 -1
package/src/cst.ts
ADDED
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { parseCst, parseDocCst, type CssCstNode, type CssCstParseOptions, type CssCstParseResult, type ParseDoc } from '@jesscss/css-parser/cst';
|
|
2
|
+
import { lessGrammar } from './grammar.js';
|
|
3
|
+
|
|
4
|
+
export function parseLessCst(
|
|
5
|
+
input: string,
|
|
6
|
+
startRule = 'Stylesheet',
|
|
7
|
+
options?: CssCstParseOptions
|
|
8
|
+
): CssCstParseResult {
|
|
9
|
+
return parseCst(lessGrammar as Record<string, unknown>, input, startRule, options);
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** Incremental (`.edit()`-able) Less document — see `parseDocCst`. */
|
|
13
|
+
export function parseLessDoc(input: string, startRule = 'Stylesheet'): ParseDoc<CssCstNode> {
|
|
14
|
+
return parseDocCst(lessGrammar as Record<string, unknown>, input, startRule);
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export type {
|
|
18
|
+
CssCstChild as LessCstChild,
|
|
19
|
+
CssCstError as LessCstError,
|
|
20
|
+
CssCstLeaf as LessCstLeaf,
|
|
21
|
+
CssCstNode as LessCstNode,
|
|
22
|
+
CssCstParseOptions as LessCstParseOptions,
|
|
23
|
+
CssCstParseResult as LessCstParseResult,
|
|
24
|
+
CssCstType as LessCstType
|
|
25
|
+
} from '@jesscss/css-parser/cst';
|
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public functional Less parser: the build host (reuses LessGrammar's Less +
|
|
3
|
+
* inherited CSS `buildNode`) and the `parseLessFn` / `LessParser` entry points.
|
|
4
|
+
* The grammar itself lives in ./grammar.ts; the shared driver is reused from
|
|
5
|
+
* @jesscss/css-parser.
|
|
6
|
+
*/
|
|
7
|
+
import type { FieldMap, Span } from 'parseman';
|
|
8
|
+
import { nil, type MathMode, type Rules, type TreeContext } from '@jesscss/core';
|
|
9
|
+
import {
|
|
10
|
+
runFunctionalParse, toParseError, buildLazyTriviaMap,
|
|
11
|
+
type FunctionalParseHost, type FunctionalParseResult
|
|
12
|
+
} from '@jesscss/css-parser/jess';
|
|
13
|
+
import { LessGrammar } from './builders.js';
|
|
14
|
+
import { lessGrammar } from './grammar.js';
|
|
15
|
+
|
|
16
|
+
// ---------------------------------------------------------------------------
|
|
17
|
+
// Builder host — reuse LessGrammar's builders (Less + inherited CSS buildNode).
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
|
|
20
|
+
class BuilderHost extends LessGrammar implements FunctionalParseHost {
|
|
21
|
+
/**
|
|
22
|
+
* The TreeContext threaded in by the caller (the plugin's per-file context),
|
|
23
|
+
* held for the duration of one parse. Currently a pass-through: it's carried
|
|
24
|
+
* back out in the result so a caller can hand one context in and read it back.
|
|
25
|
+
* Grammar rules (e.g. a future `@compose`/`@use` rule) can read/mutate it —
|
|
26
|
+
* e.g. set `context.opts.strict` — and the mutation is visible to the caller
|
|
27
|
+
* since it's the same object.
|
|
28
|
+
*/
|
|
29
|
+
context?: TreeContext;
|
|
30
|
+
|
|
31
|
+
setSource(src: string) {
|
|
32
|
+
this._source = src;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
resetWarnings() {
|
|
36
|
+
this._warnings = [];
|
|
37
|
+
this._errors = [];
|
|
38
|
+
this._liftedCommentRanges = [];
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
getWarnings() {
|
|
42
|
+
return this._warnings.slice();
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getErrors() {
|
|
46
|
+
return this._errors.slice();
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
/** `ctx.build` host: every structural `node(type, …)` builds through this,
|
|
50
|
+
* reusing LessGrammar's (Less + inherited CSS) `buildNode` verbatim. */
|
|
51
|
+
captureTriviaForNode(type: string) {
|
|
52
|
+
return type === 'CompoundSelector';
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
build(type: string, children: ReadonlyArray<unknown>, fields: FieldMap | undefined, span: { start: number; end: number }, rawChildren: ReadonlyArray<unknown>, triviaLog: readonly number[]): unknown {
|
|
56
|
+
/* eslint-disable @typescript-eslint/no-unsafe-type-assertion */
|
|
57
|
+
return (this as unknown as {
|
|
58
|
+
buildNode(t: string, s: Span, c: ReadonlyArray<unknown>, st: unknown, r: ReadonlyArray<unknown>, f?: FieldMap, tl?: readonly number[]): unknown;
|
|
59
|
+
}).buildNode(type, { start: span.start, end: span.end } as Span, children, undefined, rawChildren, fields, triviaLog);
|
|
60
|
+
/* eslint-enable @typescript-eslint/no-unsafe-type-assertion */
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
const host = new BuilderHost();
|
|
65
|
+
|
|
66
|
+
export type LessFnParseResult = FunctionalParseResult & {
|
|
67
|
+
/** The TreeContext the caller threaded in (if any), passed back out. */
|
|
68
|
+
context?: TreeContext;
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
// `rule` is a grammar rule name — the root `Stylesheet` by default, or any rule
|
|
72
|
+
// (e.g. `Declaration`, `Guard`, `SelectorList`) to parse that fragment directly.
|
|
73
|
+
export function parseLessFn(
|
|
74
|
+
input: string,
|
|
75
|
+
rule = 'Stylesheet',
|
|
76
|
+
mathMode: MathMode = 'parens-division',
|
|
77
|
+
context?: TreeContext
|
|
78
|
+
): LessFnParseResult {
|
|
79
|
+
// mathMode comes from the threaded context when present (the caller's per-file
|
|
80
|
+
// TreeContext carries it, alongside every other option); the `mathMode` param
|
|
81
|
+
// is only the context-less fallback for bare `parseLessFn(src)` callers.
|
|
82
|
+
host.mathMode = context?.options?.mathMode ?? mathMode;
|
|
83
|
+
host.context = context;
|
|
84
|
+
const g = lessGrammar as Record<string, unknown>;
|
|
85
|
+
// Less trivia includes `//` line comments, so trailing `//…` is not leftover.
|
|
86
|
+
const result = runFunctionalParse(input, g[rule], host, { trivia: g.rw });
|
|
87
|
+
// Carry the (possibly rule-mutated) context back out; clear the singleton's
|
|
88
|
+
// reference so it isn't retained across parses.
|
|
89
|
+
const threaded = host.context;
|
|
90
|
+
host.context = undefined;
|
|
91
|
+
return { ...result, context: threaded };
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Index of the first backtick in CODE position (i.e. real inline JS), or -1.
|
|
96
|
+
* Skips `//` line comments, `/* … */` block comments, and quoted strings so a
|
|
97
|
+
* backtick inside a comment/string (common in Less doc comments) is not
|
|
98
|
+
* mistaken for inline JavaScript.
|
|
99
|
+
*/
|
|
100
|
+
function firstInlineJsBacktick(text: string): number {
|
|
101
|
+
for (let i = 0; i < text.length; i++) {
|
|
102
|
+
const c = text[i];
|
|
103
|
+
if (c === '`') {
|
|
104
|
+
return i;
|
|
105
|
+
}
|
|
106
|
+
if (c === '/' && text[i + 1] === '/') {
|
|
107
|
+
const nl = text.indexOf('\n', i + 2);
|
|
108
|
+
if (nl === -1) {
|
|
109
|
+
return -1;
|
|
110
|
+
}
|
|
111
|
+
i = nl;
|
|
112
|
+
} else if (c === '/' && text[i + 1] === '*') {
|
|
113
|
+
const end = text.indexOf('*/', i + 2);
|
|
114
|
+
if (end === -1) {
|
|
115
|
+
return -1;
|
|
116
|
+
}
|
|
117
|
+
i = end + 1;
|
|
118
|
+
} else if (c === '"' || c === '\'') {
|
|
119
|
+
i++;
|
|
120
|
+
while (i < text.length && text[i] !== c) {
|
|
121
|
+
if (text[i] === '\\') {
|
|
122
|
+
i++;
|
|
123
|
+
}
|
|
124
|
+
i++;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
return -1;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Functional Less parser — call .parse(text) to get a Jess AST. */
|
|
132
|
+
export class LessParser {
|
|
133
|
+
private readonly _mathMode: MathMode;
|
|
134
|
+
|
|
135
|
+
constructor(config?: { mathMode?: MathMode } & Record<string, unknown>) {
|
|
136
|
+
this._mathMode = config?.mathMode ?? 'parens-division';
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
// Arrow field so `const parse = parser.parse` (used in tests) keeps `this`.
|
|
140
|
+
// `options.context` threads a caller-owned TreeContext through the parse and
|
|
141
|
+
// is carried back out on the result (same object) — the seam a future
|
|
142
|
+
// `@compose`/`@use` rule uses to set `context.opts.strict`.
|
|
143
|
+
parse = (text: string, rule = 'Stylesheet', options?: { context?: TreeContext }): LessFnParseResult => {
|
|
144
|
+
// Inline JavaScript (backticks) was removed in v5 — report it as a normal
|
|
145
|
+
// parse error at the backtick, NOT by throwing (a parser must not throw).
|
|
146
|
+
// Only a backtick in CODE position is inline JS: skip backticks inside line/
|
|
147
|
+
// block comments and quoted strings (e.g. markdown links in doc comments).
|
|
148
|
+
const backtick = firstInlineJsBacktick(text);
|
|
149
|
+
if (backtick !== -1) {
|
|
150
|
+
return {
|
|
151
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
|
|
152
|
+
tree: nil() as unknown as Rules,
|
|
153
|
+
errors: [toParseError('Inline JavaScript using backticks is not supported. Use @use / @-use to import a script module instead.', backtick, text)],
|
|
154
|
+
warnings: [],
|
|
155
|
+
trivia: buildLazyTriviaMap([], text),
|
|
156
|
+
liftedCommentRanges: [],
|
|
157
|
+
context: options?.context
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
return parseLessFn(text, rule, this._mathMode, options?.context);
|
|
161
|
+
};
|
|
162
|
+
}
|