@jesscss/scss-parser 2.0.0-alpha.7 → 2.0.0-alpha.8
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 +20 -3
- package/lib/functional-parser.cjs +176 -14
- package/lib/functional-parser.js +176 -14
- package/lib/grammar.cjs +44760 -39981
- package/lib/grammar.js +44760 -39981
- package/package.json +6 -6
- package/src/grammar.ts +41 -11
package/package.json
CHANGED
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
"access": "public"
|
|
5
5
|
},
|
|
6
6
|
"description": "",
|
|
7
|
-
"version": "2.0.0-alpha.
|
|
7
|
+
"version": "2.0.0-alpha.8",
|
|
8
8
|
"main": "lib/index.cjs",
|
|
9
9
|
"types": "lib/index.d.ts",
|
|
10
10
|
"exports": {
|
|
@@ -40,11 +40,11 @@
|
|
|
40
40
|
],
|
|
41
41
|
"dependencies": {
|
|
42
42
|
"chevrotain": "^12.0.0",
|
|
43
|
-
"@jesscss/css-parser": "2.0.0-alpha.
|
|
44
|
-
"@jesscss/less-parser": "2.0.0-alpha.
|
|
43
|
+
"@jesscss/css-parser": "2.0.0-alpha.8",
|
|
44
|
+
"@jesscss/less-parser": "2.0.0-alpha.8"
|
|
45
45
|
},
|
|
46
46
|
"peerDependencies": {
|
|
47
|
-
"@jesscss/core": "2.0.0-alpha.
|
|
47
|
+
"@jesscss/core": "2.0.0-alpha.8"
|
|
48
48
|
},
|
|
49
49
|
"peerDependenciesMeta": {
|
|
50
50
|
"@jesscss/core": {
|
|
@@ -52,9 +52,9 @@
|
|
|
52
52
|
}
|
|
53
53
|
},
|
|
54
54
|
"devDependencies": {
|
|
55
|
-
"parseman": "
|
|
55
|
+
"parseman": "link:/Users/matthew/git/oss/parser-thing",
|
|
56
56
|
"sass-spec": "github:sass/sass-spec",
|
|
57
|
-
"@jesscss/core": "2.0.0-alpha.
|
|
57
|
+
"@jesscss/core": "2.0.0-alpha.8"
|
|
58
58
|
},
|
|
59
59
|
"author": "Matthew Dean <matthew-dean@users.noreply.github.com>",
|
|
60
60
|
"license": "MIT",
|
package/src/grammar.ts
CHANGED
|
@@ -119,7 +119,7 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
119
119
|
const ScssValueParen = node('Paren',
|
|
120
120
|
sequence(literal('('), g.permissiveParenBody));
|
|
121
121
|
|
|
122
|
-
// Sass allows trailing commas in comma-separated lists (Less v5
|
|
122
|
+
// Sass allows trailing commas in comma-separated lists (as does Less v5, matching Less 4.x).
|
|
123
123
|
const valueList = sequence(
|
|
124
124
|
g.valueSequence,
|
|
125
125
|
many(sequence(literal(','), g.valueSequence)),
|
|
@@ -245,9 +245,16 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
245
245
|
const ifKw = regex(/@if(?![-\w])/i);
|
|
246
246
|
const elseKw = regex(/@else(?![-\w])/i);
|
|
247
247
|
const ifWord = regex(/if(?![-\w])/i);
|
|
248
|
+
// A REQUIRED condition. `@if { … }` (no condition) is a real error. `not('{')`
|
|
249
|
+
// asserts we are not sitting directly on the block opener; `expect` reports the
|
|
250
|
+
// missing condition and RECOVERS IN PLACE (zero-width) so the `{ … }` block still
|
|
251
|
+
// parses (as an `@if` with a recovered error) rather than the whole rule failing
|
|
252
|
+
// and `@if` falling through to the opaque unknown-at-rule handler. Structural,
|
|
253
|
+
// context-free — no `withCtx`/`guard`, so the grammar stays macro-compiled.
|
|
254
|
+
const reqIfCond = expect(sequence(not(literal('{')), g.ScssCondOr), 'condition');
|
|
248
255
|
const ScssIf = node(
|
|
249
256
|
sequence(
|
|
250
|
-
ifKw,
|
|
257
|
+
ifKw, reqIfCond, g.ScssRules,
|
|
251
258
|
many(sequence(elseKw, choice(
|
|
252
259
|
sequence(ifWord, g.ScssCondOr, g.ScssRules),
|
|
253
260
|
g.ScssRules
|
|
@@ -265,23 +272,32 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
265
272
|
const forKw = regex(/@for(?![-\w])/i);
|
|
266
273
|
const whileKw = regex(/@while(?![-\w])/i);
|
|
267
274
|
|
|
275
|
+
// A REQUIRED loop variable. `@each in $list { … }` (no variable) is a real error.
|
|
276
|
+
// `not(inKw | '{')` asserts a variable is actually present (missing → we are at
|
|
277
|
+
// `in` or the block); `expect` reports it and recovers zero-width so `in $list
|
|
278
|
+
// { … }` still parses as an `@each` with a recovered error.
|
|
279
|
+
const reqEachVars = expect(
|
|
280
|
+
sequence(not(choice(inKw, literal('{'))), sepBy(scssVar, literal(','))), 'variable');
|
|
268
281
|
const ScssEach = node(
|
|
269
282
|
sequence(
|
|
270
283
|
eachKw,
|
|
271
|
-
|
|
284
|
+
reqEachVars,
|
|
272
285
|
inKw,
|
|
273
286
|
g.valueSequence,
|
|
274
287
|
g.ScssRules
|
|
275
288
|
));
|
|
276
289
|
|
|
290
|
+
// A REQUIRED `from … through/to …` range. `@for $i { … }` (no range) is a real
|
|
291
|
+
// error. The whole range tail is wrapped in one `expect`: on failure it recovers
|
|
292
|
+
// zero-width (as a unit — `fromKw` is a hard token that fails at `{` without
|
|
293
|
+
// consuming) so the trailing `{ … }` block still parses as a `@for` with a
|
|
294
|
+
// recovered error rather than the rule failing and falling through.
|
|
295
|
+
const forRangeTail = sequence(fromKw, g.topSum, choice(forThrough, forTo), g.topSum);
|
|
277
296
|
const ScssFor = node(
|
|
278
297
|
sequence(
|
|
279
298
|
forKw,
|
|
280
|
-
scssVar,
|
|
281
|
-
|
|
282
|
-
g.topSum,
|
|
283
|
-
choice(forThrough, forTo),
|
|
284
|
-
g.topSum,
|
|
299
|
+
expect(scssVar, 'variable'),
|
|
300
|
+
expect(forRangeTail, '"from"'),
|
|
285
301
|
g.ScssRules
|
|
286
302
|
));
|
|
287
303
|
|
|
@@ -341,9 +357,12 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
341
357
|
const ScssDeclBody = node(
|
|
342
358
|
sequence(literal('{'), g.declarationList, expect(literal('}'), '}')));
|
|
343
359
|
|
|
360
|
+
// A REQUIRED mixin name. `@mixin { … }` (no name) is a real error. `expect` reports
|
|
361
|
+
// the missing name and recovers zero-width so the `{ … }` body still parses (as a
|
|
362
|
+
// `@mixin` with a recovered error) rather than the rule falling through.
|
|
344
363
|
const ScssMixin = node(
|
|
345
364
|
sequence(
|
|
346
|
-
mixinKw, scssMixinIdent, optional(g.ScssMixinParams), g.ScssDeclBody
|
|
365
|
+
mixinKw, expect(scssMixinIdent, 'name'), optional(g.ScssMixinParams), g.ScssDeclBody
|
|
347
366
|
));
|
|
348
367
|
|
|
349
368
|
const ScssIncludeUsing = node(
|
|
@@ -351,9 +370,12 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
351
370
|
usingKw, literal('('), sepBy(scssVar, literal(',')), expect(literal(')'))
|
|
352
371
|
));
|
|
353
372
|
|
|
373
|
+
// A REQUIRED mixin name. `@include ;` and `.a { @include }` (no name) are real
|
|
374
|
+
// errors. `expect` reports the missing name and recovers zero-width so the trailing
|
|
375
|
+
// `;`/`}` still closes the statement rather than the rule falling through.
|
|
354
376
|
const ScssInclude = node(
|
|
355
377
|
sequence(
|
|
356
|
-
includeKw, g.ScssMixinName, optionalCallParens,
|
|
378
|
+
includeKw, expect(g.ScssMixinName, 'name'), optionalCallParens,
|
|
357
379
|
optional(g.ScssIncludeUsing), optional(g.ScssRules), optional(literal(';'))
|
|
358
380
|
));
|
|
359
381
|
|
|
@@ -369,8 +391,16 @@ export const scssGrammar = compose([lessGrammar, rules({ trivia: rw }, (g: any)
|
|
|
369
391
|
functionKw, scssMixinIdent, optional(g.ScssMixinParams), g.ScssDeclBody
|
|
370
392
|
));
|
|
371
393
|
|
|
394
|
+
// A REQUIRED return value. `@return }` / `@return ;` (no expression) is a real
|
|
395
|
+
// error. `not('}' | ';')` asserts a value is actually present (valueList can match
|
|
396
|
+
// zero-width); `expect` reports it and recovers zero-width so the enclosing block's
|
|
397
|
+
// `}` still closes.
|
|
372
398
|
const ScssReturn = node(
|
|
373
|
-
sequence(
|
|
399
|
+
sequence(
|
|
400
|
+
returnKw,
|
|
401
|
+
expect(sequence(not(choice(literal('}'), literal(';'))), g.valueList), 'expression'),
|
|
402
|
+
optional(literal(';'))
|
|
403
|
+
));
|
|
374
404
|
|
|
375
405
|
// ── @use / @forward / @import / @extend ───────────────────────────────────
|
|
376
406
|
// Faithful ports of scssUseAtRule / scssForwardAtRule / importAtRule /
|