Browse Source

Allow defining mixin inside other mixin

master
Dylan Baker 5 years ago
parent
commit
8593655f56
3 changed files with 60 additions and 4 deletions
  1. 1
    1
      src/ast.ts
  2. 6
    3
      src/parser.ts
  3. 53
    0
      src/tests/parser.test.ts

+ 1
- 1
src/ast.ts View File

10
 import { Rule } from './ast/rule';
10
 import { Rule } from './ast/rule';
11
 import { RuleSet } from './ast/ruleSet';
11
 import { RuleSet } from './ast/ruleSet';
12
 
12
 
13
-export type Child = Rule | RuleSet | Application | MediaQuery;
13
+export type Child = Rule | RuleSet | Application | MediaQuery | Mixin;
14
 export type Value = Literal | Identifier | Application;
14
 export type Value = Literal | Identifier | Application;
15
 export type Node
15
 export type Node
16
   = Application
16
   = Application

+ 6
- 3
src/parser.ts View File

316
 
316
 
317
       return new AST.Rule(property, value);
317
       return new AST.Rule(property, value);
318
     } else if (this.currentToken().type === TokenTypes.LPAREN) {
318
     } else if (this.currentToken().type === TokenTypes.LPAREN) {
319
-      if (this.nextToken().type === TokenTypes.LITERAL) {
319
+      const next = this.nextToken();
320
+      if (next.type === TokenTypes.LITERAL) {
320
         return this.ruleSet(parents);
321
         return this.ruleSet(parents);
321
-      } else if (this.nextToken().type === TokenTypes.FUNCTION_NAME) {
322
-        if (this.nextToken().value === 'media') {
322
+      } else if (next.type === TokenTypes.FUNCTION_NAME) {
323
+        if (next.value === 'media') {
323
           return this.mediaQuery();
324
           return this.mediaQuery();
325
+        } else if (next.value === 'mixin') {
326
+          return this.mixin();
324
         }
327
         }
325
         return this.application();
328
         return this.application();
326
       }
329
       }

+ 53
- 0
src/tests/parser.test.ts View File

401
     );
401
     );
402
   }
402
   }
403
 });
403
 });
404
+
405
+test('mixin as child', (t) => {
406
+  t.plan(2);
407
+  const result = parse('(div (@mixin m () (div :color blue)))');
408
+  t.false(result instanceof ParserError);
409
+  if (!(result instanceof LexerError) && !(result instanceof ParserError)) {
410
+    t.deepEqual(
411
+      result.tree[0],
412
+      new AST.RuleSet(
413
+        [new AST.Selector(literalToken('div'))],
414
+        [
415
+          new AST.Mixin(
416
+            literalToken('m'),
417
+            [],
418
+            [
419
+              new AST.RuleSet(
420
+                [new AST.Selector(literalToken('div'))],
421
+                [new AST.Rule(property('color'), literalNode('blue'))]
422
+              ),
423
+            ]
424
+          )
425
+        ]
426
+      )
427
+    );
428
+  }
429
+});
430
+
431
+test('define a mixin inside another mixin', (t) => {
432
+  t.plan(2);
433
+  const result = parse('(@mixin outer ($x) (@mixin inner ($y) (div :color $y)))');
434
+  t.false(result instanceof ParserError);
435
+  if (!(result instanceof LexerError) && !(result instanceof ParserError)) {
436
+    t.deepEqual(
437
+      result.tree[0],
438
+      new AST.Mixin(
439
+        literalToken('outer'),
440
+        [identifierNode('x')],
441
+        [
442
+          new AST.Mixin(
443
+            literalToken('inner'),
444
+            [identifierNode('y')],
445
+            [
446
+              new AST.RuleSet(
447
+                [new AST.Selector(literalToken('div'))],
448
+                [new AST.Rule(property('color'), identifierNode('y'))]
449
+              ),
450
+            ]
451
+          ),
452
+        ]
453
+      )
454
+    );
455
+  }
456
+});

Loading…
Cancel
Save