Skip to content

Commit

Permalink
[scss] support interpolation in layer name. For #180631 (#370)
Browse files Browse the repository at this point in the history
aeschli authored Nov 7, 2023

Verified

This commit was created on GitHub.com and signed with GitHub’s verified signature. The key has expired.
1 parent 0f2dfc4 commit 0443e38
Showing 5 changed files with 134 additions and 127 deletions.
5 changes: 5 additions & 0 deletions src/parser/cssParser.ts
Original file line number Diff line number Diff line change
@@ -704,6 +704,11 @@ export class Parser {
return this.finish(node, ParseError.URIOrStringExpected);
}

return this._completeParseImport(node);
}


public _completeParseImport(node: nodes.Import): nodes.Node | null {
if (this.acceptIdent('layer')) {
if (this.accept(TokenType.ParenthesisL)) {
if (!node.addChild(this._parseLayerName())) {
2 changes: 1 addition & 1 deletion src/parser/lessParser.ts
Original file line number Diff line number Diff line change
@@ -65,7 +65,7 @@ export class LESSParser extends cssParser.Parser {
node.setMedialist(this._parseMediaQueryList());
}

return this.finish(node);
return this._completeParseImport(node);
}

public _parsePlugin(): nodes.Node | null {
6 changes: 1 addition & 5 deletions src/parser/scssParser.ts
Original file line number Diff line number Diff line change
@@ -55,11 +55,7 @@ export class SCSSParser extends cssParser.Parser {
}
}

if (!this.peek(TokenType.SemiColon) && !this.peek(TokenType.EOF)) {
node.setMedialist(this._parseMediaQueryList());
}

return this.finish(node);
return this._completeParseImport(node);
}

// scss variables: $font-size: 12px;
99 changes: 52 additions & 47 deletions src/test/less/parser.test.ts
Original file line number Diff line number Diff line change
@@ -12,7 +12,7 @@ import { assertNode, assertNoNode, assertError } from '../css/parser.test';
suite('LESS - Parser', () => {

test('Variable', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('@color', parser, parser._parseVariable.bind(parser));
assertNode('$color', parser, parser._parseVariable.bind(parser));
assertNode('$$color', parser, parser._parseVariable.bind(parser));
@@ -36,7 +36,7 @@ suite('LESS - Parser', () => {
});

test('Media', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('@media @phone {}', parser, parser._parseMedia.bind(parser));
assertNode('@media(max-width: 767px) { .mixinRef() }', parser, parser._parseMedia.bind(parser));
assertNode('@media(max-width: 767px) { .mixinDec() {} }', parser, parser._parseMedia.bind(parser));
@@ -48,7 +48,7 @@ suite('LESS - Parser', () => {
});

test('VariableDeclaration', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('@color: #F5F5F5', parser, parser._parseVariableDeclaration.bind(parser));
assertNode('@color: 0', parser, parser._parseVariableDeclaration.bind(parser));
assertNode('@color: 255', parser, parser._parseVariableDeclaration.bind(parser));
@@ -67,7 +67,7 @@ suite('LESS - Parser', () => {
});

test('MixinDeclaration', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.color (@color: 25.5px) { }', parser, parser._tryParseMixinDeclaration.bind(parser));
assertNode('.color(@color: 25.5px) { }', parser, parser._tryParseMixinDeclaration.bind(parser));
assertNode('.color(@color) { }', parser, parser._tryParseMixinDeclaration.bind(parser));
@@ -90,7 +90,7 @@ suite('LESS - Parser', () => {
});

test('MixinReference', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.box-shadow(0 0 5px, 30%)', parser, parser._tryParseMixinReference.bind(parser));
assertNode('.box-shadow', parser, parser._tryParseMixinReference.bind(parser));
assertNode('.mixin(10) !important', parser, parser._tryParseMixinReference.bind(parser));
@@ -105,7 +105,7 @@ suite('LESS - Parser', () => {
});

test('DetachedRuleSet', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.foo { @greeting(); }', parser, parser._parseStylesheet.bind(parser));
assertNode('.media-switch(@styles) { @media(orientation:landscape){ @styles(); @foo: 9; } }', parser, parser._parseStylesheet.bind(parser));
assertNode('.media-switch({ flex-direction: row; });', parser, parser._parseStylesheet.bind(parser));
@@ -120,10 +120,10 @@ suite('LESS - Parser', () => {
});

test('MixinParameter', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('@_', parser, parser._parseMixinParameter.bind(parser));
assertNode('@let: value', parser, parser._parseMixinParameter.bind(parser));
assertNode('@let', parser, parser._parseMixinParameter.bind(parser));
assertNode('@const: value', parser, parser._parseMixinParameter.bind(parser));
assertNode('@const', parser, parser._parseMixinParameter.bind(parser));
assertNode('@rest...', parser, parser._parseMixinParameter.bind(parser));
assertNode('...', parser, parser._parseMixinParameter.bind(parser));
assertNode('value', parser, parser._parseMixinParameter.bind(parser));
@@ -132,7 +132,7 @@ suite('LESS - Parser', () => {
});

test('Function', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('%()', parser, parser._parseFunction.bind(parser));
assertNoNode('% ()', parser, parser._parseFunction.bind(parser));

@@ -145,25 +145,25 @@ suite('LESS - Parser', () => {
});

test('Expr', function () {
let parser = new LESSParser();
assertNode('(@let + 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@let - 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@let * 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@let / 20)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 - @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 * @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 / @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 / 20 + @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + 20 + @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + 20 + 20 + @let)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + @let + 20 + 20 + @let)', parser, parser._parseExpr.bind(parser));
const parser = new LESSParser();
assertNode('(@const + 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@const - 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@const * 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@const / 20)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 - @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 * @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 / @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 / 20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + 20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + 20 + 20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20 + @const + 20 + 20 + @const)', parser, parser._parseExpr.bind(parser));
assertNode('(20 + 20)', parser, parser._parseExpr.bind(parser));
assertNode('(@var1 + @var2)', parser, parser._parseExpr.bind(parser));
assertNode('((@let + 5) * 2)', parser, parser._parseExpr.bind(parser));
assertNode('((@let + (5 + 2)) * 2)', parser, parser._parseExpr.bind(parser));
assertNode('(@let + ((5 + 2) * 2))', parser, parser._parseExpr.bind(parser));
assertNode('((@const + 5) * 2)', parser, parser._parseExpr.bind(parser));
assertNode('((@const + (5 + 2)) * 2)', parser, parser._parseExpr.bind(parser));
assertNode('(@const + ((5 + 2) * 2))', parser, parser._parseExpr.bind(parser));
assertNode('@color', parser, parser._parseExpr.bind(parser));
assertNode('@color, @color', parser, parser._parseExpr.bind(parser));
assertNode('@color, 42%', parser, parser._parseExpr.bind(parser));
@@ -175,15 +175,15 @@ suite('LESS - Parser', () => {
});

test('LessOperator', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('>=', parser, parser._parseOperator.bind(parser));
assertNode('>', parser, parser._parseOperator.bind(parser));
assertNode('<', parser, parser._parseOperator.bind(parser));
assertNode('=<', parser, parser._parseOperator.bind(parser));
});

test('Extend', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('nav { &:extend(.inline); }', parser, parser._parseRuleset.bind(parser));
assertNode('nav { &:extend(.test all); }', parser, parser._parseRuleset.bind(parser));
assertNode('.big-bucket:extend(.bucket all) { }', parser, parser._parseRuleset.bind(parser));
@@ -193,12 +193,12 @@ suite('LESS - Parser', () => {
});

test('Declaration', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('border: thin solid 1px', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: @color', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: blue', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: (20 / @let)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: (20 / 20 + @let)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: (20 / @const)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: (20 / 20 + @const)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: func(@red)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: desaturate(@red, 10%)', parser, parser._parseDeclaration.bind(parser));
assertNode('dummy: desaturate(16, 10%)', parser, parser._parseDeclaration.bind(parser));
@@ -218,7 +218,7 @@ suite('LESS - Parser', () => {
});

test('Stylesheet', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.color (@radius: 5px){ -border-radius: #F5F5F5 }', parser, parser._parseStylesheet.bind(parser));
assertNode('.color (@radius: 5px){ -border-radius: @radius }', parser, parser._parseStylesheet.bind(parser));
assertNode('.color (@radius: 5px){ -border-radius: #F5F5F5 } .color (@radius: 5px) { -border-radius: #F5F5F5 }', parser, parser._parseStylesheet.bind(parser));
@@ -236,6 +236,11 @@ suite('LESS - Parser', () => {
assertNode('@color: #F5F5F5; @color: #F5F5F5;', parser, parser._parseStylesheet.bind(parser));
assertNode('@color: #F5F5F5; @color: #F5F5F5; @color: #F5F5F5;', parser, parser._parseStylesheet.bind(parser));
assertNode('@color: #F5F5F5; .color (@radius: 5px) { -border-radius: #F5F5F5 } @color: #F5F5F5;', parser, parser._parseStylesheet.bind(parser));
});

test('@iport', function () {
const parser = new LESSParser();
assertNode('@import url("override.css") layer;', parser, parser._parseStylesheet.bind(parser));
assertNode('@import-once "lib";', parser, parser._parseStylesheet.bind(parser));
assertNode('@import-once (css) "hello";', parser, parser._parseStylesheet.bind(parser));
assertError('@import-once () "hello";', parser, parser._parseStylesheet.bind(parser), ParseError.IdentifierExpected);
@@ -247,8 +252,8 @@ suite('LESS - Parser', () => {
});

test('Ruleset', function () {
let parser = new LESSParser();
assertNode('.selector { prop: erty @let 1px; }', parser, parser._parseRuleset.bind(parser));
const parser = new LESSParser();
assertNode('.selector { prop: erty @const 1px; }', parser, parser._parseRuleset.bind(parser));
assertNode('selector { .mixin; }', parser, parser._parseRuleset.bind(parser));
assertNode('selector { .mixin(1px); .mixin(blue, 1px, \'farboo\') }', parser, parser._parseRuleset.bind(parser));
assertNode('selector { .mixin(blue; 1px;\'farboo\') }', parser, parser._parseRuleset.bind(parser));
@@ -264,24 +269,24 @@ suite('LESS - Parser', () => {
});

test('term', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('%(\'repetitions: %S file: %S\', 1 + 2, "directory/file.less")', parser, parser._parseTerm.bind(parser));
assertNode('~"ms:alwaysHasItsOwnSyntax.For.Stuff()"', parser, parser._parseTerm.bind(parser)); // less syntax
assertNode('~`colorPalette("@{blue}", 1)`', parser, parser._parseTerm.bind(parser)); // less syntax
assertNode('~`colorPaconstte("@{blue}", 1)`', parser, parser._parseTerm.bind(parser)); // less syntax
});

test('Nested Ruleset', function () {
let parser = new LESSParser();
assertNode('.class1 { @let: 1; .class { @let: 2; three: @let; let: 3; } one: @let; }', parser, parser._parseRuleset.bind(parser));
assertNode('.class1 { @let: 1; > .class2 { display: none; } }', parser, parser._parseRuleset.bind(parser));
const parser = new LESSParser();
assertNode('.class1 { @const: 1; .class { @const: 2; three: @const; const: 3; } one: @const; }', parser, parser._parseRuleset.bind(parser));
assertNode('.class1 { @const: 1; > .class2 { display: none; } }', parser, parser._parseRuleset.bind(parser));
assertNode('.foo { @supports(display: grid) { .bar { display: none; }}}', parser, parser._parseRuleset.bind(parser));
assertNode('.foo { @supports(display: grid) { display: none; }}', parser, parser._parseRuleset.bind(parser));
assertNode('.parent { color:green; @document url-prefix() { .child { color:red; }}}', parser, parser._parseStylesheet.bind(parser));
assertNode('@supports (property: value) { .outOfMedia & { @media (max-size: 2px) { @supports (whatever: something) { property: value;}}}}', parser, parser._parseStylesheet.bind(parser));
});

test('Interpolation', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.@{name} { }', parser, parser._parseRuleset.bind(parser));
assertNode('.${name} { }', parser, parser._parseRuleset.bind(parser));
assertNode('.my-element:not(.prefix-@{sub-element}) { }', parser, parser._parseStylesheet.bind(parser));
@@ -294,7 +299,7 @@ suite('LESS - Parser', () => {
});

test('Selector Combinator', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('&:hover', parser, parser._parseSimpleSelector.bind(parser));
assertNode('&.float', parser, parser._parseSimpleSelector.bind(parser));
assertNode('&-foo', parser, parser._parseSimpleSelector.bind(parser));
@@ -307,20 +312,20 @@ suite('LESS - Parser', () => {
});

test('CSS Guards', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('button when (@my-option = true) { color: white; }', parser, parser._parseStylesheet.bind(parser));
assertNode('.something .other when (@my-option = true) { color: white; }', parser, parser._parseStylesheet.bind(parser));
assertNode('& when (@my-option = true) { button { color: white; } }', parser, parser._parseStylesheet.bind(parser));
});

test('Merge', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('.mixin() { transform+_: scale(2); }', parser, parser._parseStylesheet.bind(parser));
assertNode('.myclass { box-shadow+: inset 0 0 10px #555; }', parser, parser._parseStylesheet.bind(parser));
});

test('url', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('url(//yourdomain/yourpath.png)', parser, parser._parseURILiteral.bind(parser));
assertNode('url(\'http://msft.com\')', parser, parser._parseURILiteral.bind(parser));
assertNode('url("http://msft.com")', parser, parser._parseURILiteral.bind(parser));
@@ -339,7 +344,7 @@ suite('LESS - Parser', () => {
});

test('@plugin', function () {
let parser = new LESSParser();
const parser = new LESSParser();
assertNode('@plugin "my-plugin";', parser, parser._parseStylesheet.bind(parser));
});
});
});
149 changes: 75 additions & 74 deletions src/test/scss/parser.test.ts

Large diffs are not rendered by default.

0 comments on commit 0443e38

Please sign in to comment.