diff --git a/packages/vscode-css-languageservice/src/parser/cssErrors.ts b/packages/vscode-css-languageservice/src/parser/cssErrors.ts index ff5f4ec3..0fb3f859 100644 --- a/packages/vscode-css-languageservice/src/parser/cssErrors.ts +++ b/packages/vscode-css-languageservice/src/parser/cssErrors.ts @@ -58,5 +58,4 @@ export const ParseError = { IdentifierOrWildcardExpected: new CSSIssueType("css-idorwildcardexpected", l10n.t("identifier or wildcard expected")), WildcardExpected: new CSSIssueType("css-wildcardexpected", l10n.t("wildcard expected")), IdentifierOrVariableExpected: new CSSIssueType("css-idorvarexpected", l10n.t("identifier or variable expected")), - UnexpectedSemicolon: new CSSIssueType("css-nosemi", l10n.t("';' is not allowed in indented syntax")), }; diff --git a/packages/vscode-css-languageservice/src/parser/cssParser.ts b/packages/vscode-css-languageservice/src/parser/cssParser.ts index 62ad358a..bb69ee03 100644 --- a/packages/vscode-css-languageservice/src/parser/cssParser.ts +++ b/packages/vscode-css-languageservice/src/parser/cssParser.ts @@ -834,9 +834,7 @@ export class Parser { return this.finish(node, ParseError.IdentifierExpected); } - if (this.syntax === "indented" && this.accept(TokenType.SemiColon)) { - return this.finish(node, ParseError.UnexpectedSemicolon); - } else if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { + if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { return this.finish(node, ParseError.SemiColonExpected); } @@ -914,9 +912,7 @@ export class Parser { } } - if (this.syntax === "indented" && this.accept(TokenType.SemiColon)) { - return this.finish(node, ParseError.UnexpectedSemicolon); - } else if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { + if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { return this.finish(node, ParseError.SemiColonExpected); } @@ -1081,9 +1077,7 @@ export class Parser { if ((!names || names.getChildren().length === 1) && (this.peek(TokenType.CurlyL) || this.peek(TokenType.Indent))) { return this._parseBody(node, this._parseLayerDeclaration.bind(this, isNested)); } - if (this.syntax === "indented" && this.accept(TokenType.SemiColon)) { - return this.finish(node, ParseError.UnexpectedSemicolon); - } else if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { + if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon)) { return this.finish(node, ParseError.SemiColonExpected); } return this.finish(node); diff --git a/packages/vscode-css-languageservice/src/parser/sassParser.ts b/packages/vscode-css-languageservice/src/parser/sassParser.ts index 031c8ff7..4d99a912 100644 --- a/packages/vscode-css-languageservice/src/parser/sassParser.ts +++ b/packages/vscode-css-languageservice/src/parser/sassParser.ts @@ -111,10 +111,6 @@ export class SassParser extends cssParser.Parser { } if (this.peek(TokenType.SemiColon)) { - if (this.syntax === "indented") { - return this.finish(node, ParseError.UnexpectedSemicolon); - } - node.semicolonPosition = this.token.offset; // not part of the declaration, but useful information for code assist } @@ -925,14 +921,8 @@ export class SassParser extends cssParser.Parser { } } - if (this.syntax === "indented") { - if (this.accept(TokenType.SemiColon)) { - return this.finish(node, ParseError.UnexpectedSemicolon); - } - } else { - if (!this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { - return this.finish(node, ParseError.SemiColonExpected); - } + if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { + return this.finish(node, ParseError.SemiColonExpected); } return this.finish(node); @@ -1019,14 +1009,8 @@ export class SassParser extends cssParser.Parser { } } - if (this.syntax === "indented") { - if (this.accept(TokenType.SemiColon)) { - return this.finish(node, ParseError.UnexpectedSemicolon); - } - } else { - if (!this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { - return this.finish(node, ParseError.SemiColonExpected); - } + if (this.syntax !== "indented" && !this.accept(TokenType.SemiColon) && !this.accept(TokenType.EOF)) { + return this.finish(node, ParseError.SemiColonExpected); } return this.finish(node); diff --git a/packages/vscode-css-languageservice/src/test/sass/parserIndented.test.ts b/packages/vscode-css-languageservice/src/test/sass/parserIndented.test.ts index 468faec7..13cc99d1 100644 --- a/packages/vscode-css-languageservice/src/test/sass/parserIndented.test.ts +++ b/packages/vscode-css-languageservice/src/test/sass/parserIndented.test.ts @@ -18,7 +18,6 @@ suite("Sass - Parser", () => { test("@charset", () => { assertNode('@charset "demo"', parser, parser._parseStylesheet.bind(parser)); assertError("@charset", parser, parser._parseStylesheet.bind(parser), ParseError.IdentifierExpected); - assertError('@charset "demo";', parser, parser._parseStylesheet.bind(parser), ParseError.UnexpectedSemicolon); }); test("newline before at-rule", () => { @@ -3346,7 +3345,43 @@ body ); }); - test("flags semicolon as error in variable declaration", async () => { - assertError(`$font-size: 20px;`, parser, parser._parseStylesheet.bind(parser), ParseError.UnexpectedSemicolon); + test("allows semicolon to explicitly end statements", () => { + assertNode('@charset "demo";', parser, parser._parseStylesheet.bind(parser)); + assertNode(`$font-size: 20px;`, parser, parser._parseStylesheet.bind(parser)); + }); + + suite("multiline", () => { + test("where statements can't end", () => { + assertNode( + ` +@each $item in + 1 2 3 + .item-#{ + $item + } + content: $item * + 10 + `, + parser, + parser._parseStylesheet.bind(parser), + ); + }); + + test("with parentheses", () => { + assertNode( + ` +@font-face + font-family: "Leatherman" + src: ( + local("Leatherman"), + url("leatherman-COLRv1.otf") format("opentype") tech(color-COLRv1), + url("leatherman-outline.otf") format("opentype"), + url("leatherman-outline.woff") format("woff") + ) + `, + parser, + parser._parseStylesheet.bind(parser), + ); + }); }); });