From b84790cf9272d6d29f50f464ad92744c38767964 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Mon, 22 May 2023 19:42:44 +0200 Subject: [PATCH 01/31] Added postcss and postcss-scss as dependencies --- package.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/package.json b/package.json index 0bd97eff..2064f601 100644 --- a/package.json +++ b/package.json @@ -55,7 +55,9 @@ "dependencies": { "eslint-scope": "^7.0.0", "eslint-visitor-keys": "^3.0.0", - "espree": "^9.0.0" + "espree": "^9.0.0", + "postcss": "^8.4.23", + "postcss-scss": "^4.0.6" }, "devDependencies": { "@changesets/changelog-github": "^0.4.6", From cef3dd921e13434852815722adcb1730b33820fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Mon, 22 May 2023 22:05:00 +0200 Subject: [PATCH 02/31] Parsing style AST as part of parser services --- src/parser/index.ts | 58 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/src/parser/index.ts b/src/parser/index.ts index 72361fa3..66e6a7b1 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -4,6 +4,7 @@ import type { Comment, SvelteProgram, SvelteScriptElement, + SvelteStyleElement, Token, } from "../ast"; import type { Program } from "estree"; @@ -21,6 +22,9 @@ import { import { ParseError } from "../errors"; import { parseTypeScript } from "./typescript"; import { addReference } from "../scope"; +import type { Parser, Root } from "postcss"; +import postcss from "postcss"; +import { parse as SCSSparse } from "postcss-scss"; export interface ESLintProgram extends Program { comments: Comment[]; @@ -50,6 +54,7 @@ export function parseForESLint( services: Record & { isSvelte: true; getSvelteHtmlAst: () => SvAST.Fragment; + getStyleSourceAst: () => Root | null; }; visitorKeys: { [type: string]: string[] }; scopeManager: ScopeManager; @@ -166,12 +171,21 @@ export function parseForESLint( ); } + const styleElement = ast.body.find( + (b): b is SvelteStyleElement => b.type === "SvelteStyleElement" + ); + const styleSourceAst: Root | null = + styleElement !== undefined ? parseStyleAst(styleElement, ctx) : null; + resultScript.ast = ast as any; resultScript.services = Object.assign(resultScript.services || {}, { isSvelte: true, getSvelteHtmlAst() { return resultTemplate.svelteAst.html; }, + getStyleSourceAst() { + return styleSourceAst; + }, }); resultScript.visitorKeys = Object.assign({}, KEYS, resultScript.visitorKeys); @@ -214,3 +228,47 @@ function extractTokens(ctx: Context) { return /^[^\w$]$/iu.test(c); } } + +function parseStyleAst( + styleElement: SvelteStyleElement, + ctx: Context +): Root | null { + if (!styleElement.endTag) { + return null; + } + let lang = "css"; + for (const attribute of styleElement.startTag.attributes) { + if ( + attribute.type === "SvelteAttribute" && + attribute.key.name === "lang" && + attribute.value.length > 0 && + attribute.value[0].type === "SvelteLiteral" + ) { + lang = attribute.value[0].value; + } + } + let parseFn: Parser | undefined = postcss.parse; + switch (lang) { + case "css": + parseFn = postcss.parse; + break; + case "scss": + parseFn = SCSSparse; + break; + default: + console.warn(`Unknown diff --git a/tests/fixtures/parser/style-context/simple-css-output.json b/tests/fixtures/parser/style-context/simple-css-output.json new file mode 100644 index 00000000..103cd5ef --- /dev/null +++ b/tests/fixtures/parser/style-context/simple-css-output.json @@ -0,0 +1,127 @@ +{ + "status": "success", + "sourceLang": "css", + "sourceAst": { + "raws": { + "semicolon": false, + "after": "\n" + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 107, + "line": 11, + "column": 5 + }, + "end": { + "offset": 117, + "line": 11, + "column": 15 + } + }, + "prop": "color", + "value": "red" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 92, + "line": 10, + "column": 3 + }, + "end": { + "offset": 121, + "line": 12, + "column": 3 + } + }, + "selector": ".myClass", + "lastEach": 1, + "indexes": {} + }, + { + "raws": { + "before": "\n\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 134, + "line": 15, + "column": 5 + }, + "end": { + "offset": 153, + "line": 15, + "column": 24 + } + }, + "prop": "font-size", + "value": "xx-large" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 126, + "line": 14, + "column": 3 + }, + "end": { + "offset": 157, + "line": 16, + "column": 3 + } + }, + "selector": "b", + "lastEach": 1, + "indexes": {} + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 89, + "line": 9, + "column": 8 + } + }, + "lastEach": 1, + "indexes": {}, + "inputs": [ + { + "hasBOM": false, + "css": "\n .myClass {\n color: red;\n }\n\n b {\n font-size: xx-large;\n }\n" + } + ] + } +} From 202760e8b17c426cc82d3861e360aeaf66d08de9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:06:52 +0200 Subject: [PATCH 18/31] Added a PostCSS AST test with empty diff --git a/tests/fixtures/parser/style-context/empty-style-element-output.json b/tests/fixtures/parser/style-context/empty-style-element-output.json new file mode 100644 index 00000000..2e17f778 --- /dev/null +++ b/tests/fixtures/parser/style-context/empty-style-element-output.json @@ -0,0 +1,27 @@ +{ + "status": "success", + "sourceLang": "css", + "sourceAst": { + "raws": { + "after": "" + }, + "type": "root", + "nodes": [], + "source": { + "inputId": 0, + "start": { + "offset": 52, + "line": 7, + "column": 8 + } + }, + "lastEach": 1, + "indexes": {}, + "inputs": [ + { + "hasBOM": false, + "css": "" + } + ] + } +} From 82425f7ab36a224e329089b1cf6ab79d054df2fc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:10:31 +0200 Subject: [PATCH 19/31] Fixed column offset in one-line styles --- src/parser/style-context.ts | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/parser/style-context.ts b/src/parser/style-context.ts index bbc1f9df..a09b216d 100644 --- a/src/parser/style-context.ts +++ b/src/parser/style-context.ts @@ -110,4 +110,7 @@ function fixPostCSSNodeLocation( if (node.source?.start?.line === styleElement.loc.start.line) { node.source.start.column += styleElement.startTag.loc.end.column; } + if (node.source?.end?.line === styleElement.loc.start.line) { + node.source.end.column += styleElement.startTag.loc.end.column; + } } From 9700b224c1b819c7606ab4cf1e76b69b1d0036b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:17:08 +0200 Subject: [PATCH 20/31] Added a test for one-line style --- .../style-context/one-line-css-input.svelte | 7 ++ .../style-context/one-line-css-output.json | 78 +++++++++++++++++++ 2 files changed, 85 insertions(+) create mode 100644 tests/fixtures/parser/style-context/one-line-css-input.svelte create mode 100644 tests/fixtures/parser/style-context/one-line-css-output.json diff --git a/tests/fixtures/parser/style-context/one-line-css-input.svelte b/tests/fixtures/parser/style-context/one-line-css-input.svelte new file mode 100644 index 00000000..0bd7cd09 --- /dev/null +++ b/tests/fixtures/parser/style-context/one-line-css-input.svelte @@ -0,0 +1,7 @@ + + +Hello! + + diff --git a/tests/fixtures/parser/style-context/one-line-css-output.json b/tests/fixtures/parser/style-context/one-line-css-output.json new file mode 100644 index 00000000..669a9c69 --- /dev/null +++ b/tests/fixtures/parser/style-context/one-line-css-output.json @@ -0,0 +1,78 @@ +{ + "status": "success", + "sourceLang": "css", + "sourceAst": { + "raws": { + "semicolon": false, + "after": " " + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": " ", + "between": " ", + "semicolon": true, + "after": " " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": " ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 89, + "line": 7, + "column": 20 + }, + "end": { + "offset": 99, + "line": 7, + "column": 30 + } + }, + "prop": "color", + "value": "red" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 78, + "line": 7, + "column": 9 + }, + "end": { + "offset": 101, + "line": 7, + "column": 32 + } + }, + "selector": ".myClass", + "lastEach": 1, + "indexes": {} + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 77, + "line": 7, + "column": 8 + } + }, + "lastEach": 1, + "indexes": {}, + "inputs": [ + { + "hasBOM": false, + "css": " .myClass { color: red; } " + } + ] + } +} From 2f20d8c0232ec9ea07c744b3011846dceb256dfe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:26:25 +0200 Subject: [PATCH 21/31] Ignoring another possible filename location in style-context tests --- tests/src/parser/style-context.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/src/parser/style-context.ts b/tests/src/parser/style-context.ts index 7f430321..da37c11c 100644 --- a/tests/src/parser/style-context.ts +++ b/tests/src/parser/style-context.ts @@ -44,7 +44,7 @@ function styleContextToJson(styleContext: StyleContext): string { } function nodeReplacer(key: string, value: any): any { - if (key === "file") { + if (key === "file" || key === "url") { return undefined; } return value; From 43f0697c5860d74cd6e2a85117b775e3b94f8f09 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:26:54 +0200 Subject: [PATCH 22/31] Added tests with invalid style --- .../style-context/parse-error-input.svelte | 17 ++++++++++++++++ .../style-context/parse-error-output.json | 20 +++++++++++++++++++ 2 files changed, 37 insertions(+) create mode 100644 tests/fixtures/parser/style-context/parse-error-input.svelte create mode 100644 tests/fixtures/parser/style-context/parse-error-output.json diff --git a/tests/fixtures/parser/style-context/parse-error-input.svelte b/tests/fixtures/parser/style-context/parse-error-input.svelte new file mode 100644 index 00000000..cf61e87d --- /dev/null +++ b/tests/fixtures/parser/style-context/parse-error-input.svelte @@ -0,0 +1,17 @@ +
+
Hello
+ World! +
+ + diff --git a/tests/fixtures/parser/style-context/parse-error-output.json b/tests/fixtures/parser/style-context/parse-error-output.json new file mode 100644 index 00000000..694cc9e0 --- /dev/null +++ b/tests/fixtures/parser/style-context/parse-error-output.json @@ -0,0 +1,20 @@ +{ + "status": "parse-error", + "sourceLang": "css", + "error": { + "name": "CssSyntaxError", + "reason": "Unknown word", + "source": "\n // This syntax is intentionally invalid CSS - this is to be used to test resiliency against invalid input\n .container {\n class .div-class/35\n # Weird comment\n color: red;\n\n .span-class begin\n font-weight: bold;\n end\n }\n", + "line": 4, + "column": 11, + "endLine": 4, + "endColumn": 24, + "input": { + "line": 4, + "column": 11, + "endLine": 4, + "endColumn": 24, + "source": "\n // This syntax is intentionally invalid CSS - this is to be used to test resiliency against invalid input\n .container {\n class .div-class/35\n # Weird comment\n color: red;\n\n .span-class begin\n font-weight: bold;\n end\n }\n" + } + } +} From da929b10ba747d311329761cc631010ed6b719fd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:29:07 +0200 Subject: [PATCH 23/31] Added tests with unknown style lang --- .../style-context/unknown-lang-input.svelte | 17 +++++++++++++++++ .../style-context/unknown-lang-output.json | 4 ++++ 2 files changed, 21 insertions(+) create mode 100644 tests/fixtures/parser/style-context/unknown-lang-input.svelte create mode 100644 tests/fixtures/parser/style-context/unknown-lang-output.json diff --git a/tests/fixtures/parser/style-context/unknown-lang-input.svelte b/tests/fixtures/parser/style-context/unknown-lang-input.svelte new file mode 100644 index 00000000..0c3b211e --- /dev/null +++ b/tests/fixtures/parser/style-context/unknown-lang-input.svelte @@ -0,0 +1,17 @@ +
+
Hello
+ World! +
+ + diff --git a/tests/fixtures/parser/style-context/unknown-lang-output.json b/tests/fixtures/parser/style-context/unknown-lang-output.json new file mode 100644 index 00000000..89682316 --- /dev/null +++ b/tests/fixtures/parser/style-context/unknown-lang-output.json @@ -0,0 +1,4 @@ +{ + "status": "unknown-lang", + "sourceLang": "invalid-lang" +} From 222caedec6ef2218110535215adb908be024417c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:33:13 +0200 Subject: [PATCH 24/31] Added a test for parsing SCSS --- .../style-context/simple-scss-input.svelte | 18 ++ .../style-context/simple-scss-output.json | 178 ++++++++++++++++++ 2 files changed, 196 insertions(+) create mode 100644 tests/fixtures/parser/style-context/simple-scss-input.svelte create mode 100644 tests/fixtures/parser/style-context/simple-scss-output.json diff --git a/tests/fixtures/parser/style-context/simple-scss-input.svelte b/tests/fixtures/parser/style-context/simple-scss-input.svelte new file mode 100644 index 00000000..45bbe860 --- /dev/null +++ b/tests/fixtures/parser/style-context/simple-scss-input.svelte @@ -0,0 +1,18 @@ +
+
Hello
+ + World! +
+ + diff --git a/tests/fixtures/parser/style-context/simple-scss-output.json b/tests/fixtures/parser/style-context/simple-scss-output.json new file mode 100644 index 00000000..a3c34918 --- /dev/null +++ b/tests/fixtures/parser/style-context/simple-scss-output.json @@ -0,0 +1,178 @@ +{ + "status": "success", + "sourceLang": "scss", + "sourceAst": { + "raws": { + "semicolon": false, + "after": "\n" + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": " ", + "semicolon": false, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "inline": true, + "left": " ", + "right": "", + "text": "This is an inline comment" + }, + "type": "comment", + "source": { + "inputId": 0, + "start": { + "offset": 169, + "line": 10, + "column": 7 + }, + "end": { + "offset": 196, + "line": 10, + "column": 34 + } + }, + "text": "This is an inline comment" + }, + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 204, + "line": 11, + "column": 7 + }, + "end": { + "offset": 214, + "line": 11, + "column": 17 + } + }, + "prop": "color", + "value": "red" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 150, + "line": 9, + "column": 5 + }, + "end": { + "offset": 220, + "line": 12, + "column": 5 + } + }, + "selector": ".div-class", + "lastEach": 1, + "indexes": {} + }, + { + "raws": { + "before": "\n\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 247, + "line": 15, + "column": 7 + }, + "end": { + "offset": 264, + "line": 15, + "column": 24 + } + }, + "prop": "font-weight", + "value": "bold" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 227, + "line": 14, + "column": 5 + }, + "end": { + "offset": 270, + "line": 16, + "column": 5 + } + }, + "selector": ".span-class", + "lastEach": 1, + "indexes": {} + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 133, + "line": 8, + "column": 3 + }, + "end": { + "offset": 274, + "line": 17, + "column": 3 + } + }, + "selector": ".container", + "lastEach": 1, + "indexes": {} + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 130, + "line": 7, + "column": 20 + } + }, + "lastEach": 1, + "indexes": {}, + "inputs": [ + { + "hasBOM": false, + "css": "\n .container {\n .div-class {\n // This is an inline comment\n color: red;\n }\n\n .span-class {\n font-weight: bold;\n }\n }\n" + } + ] + } +} From 330792debee18c2ae25e85480231a8391158f379 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:38:05 +0200 Subject: [PATCH 25/31] Added a test with unrelated style attribute --- .../unrelated-style-attr-input.svelte | 17 +++ .../unrelated-style-attr-output.json | 127 ++++++++++++++++++ 2 files changed, 144 insertions(+) create mode 100644 tests/fixtures/parser/style-context/unrelated-style-attr-input.svelte create mode 100644 tests/fixtures/parser/style-context/unrelated-style-attr-output.json diff --git a/tests/fixtures/parser/style-context/unrelated-style-attr-input.svelte b/tests/fixtures/parser/style-context/unrelated-style-attr-input.svelte new file mode 100644 index 00000000..cb0a6f96 --- /dev/null +++ b/tests/fixtures/parser/style-context/unrelated-style-attr-input.svelte @@ -0,0 +1,17 @@ + + +Hello! + +{a} + + diff --git a/tests/fixtures/parser/style-context/unrelated-style-attr-output.json b/tests/fixtures/parser/style-context/unrelated-style-attr-output.json new file mode 100644 index 00000000..1d6c539a --- /dev/null +++ b/tests/fixtures/parser/style-context/unrelated-style-attr-output.json @@ -0,0 +1,127 @@ +{ + "status": "success", + "sourceLang": "css", + "sourceAst": { + "raws": { + "semicolon": false, + "after": "\n" + }, + "type": "root", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 124, + "line": 11, + "column": 5 + }, + "end": { + "offset": 134, + "line": 11, + "column": 15 + } + }, + "prop": "color", + "value": "red" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 109, + "line": 10, + "column": 3 + }, + "end": { + "offset": 138, + "line": 12, + "column": 3 + } + }, + "selector": ".myClass", + "lastEach": 1, + "indexes": {} + }, + { + "raws": { + "before": "\n\n ", + "between": " ", + "semicolon": true, + "after": "\n " + }, + "type": "rule", + "nodes": [ + { + "raws": { + "before": "\n ", + "between": ": " + }, + "type": "decl", + "source": { + "inputId": 0, + "start": { + "offset": 151, + "line": 15, + "column": 5 + }, + "end": { + "offset": 170, + "line": 15, + "column": 24 + } + }, + "prop": "font-size", + "value": "xx-large" + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 143, + "line": 14, + "column": 3 + }, + "end": { + "offset": 174, + "line": 16, + "column": 3 + } + }, + "selector": "b", + "lastEach": 1, + "indexes": {} + } + ], + "source": { + "inputId": 0, + "start": { + "offset": 106, + "line": 9, + "column": 25 + } + }, + "lastEach": 1, + "indexes": {}, + "inputs": [ + { + "hasBOM": false, + "css": "\n .myClass {\n color: red;\n }\n\n b {\n font-size: xx-large;\n }\n" + } + ] + } +} From bc91e406591be5e25d1b89fe7bdde21d694ecd4e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Tue, 30 May 2023 16:45:47 +0200 Subject: [PATCH 26/31] ESLint fix --- src/parser/style-context.ts | 19 ++++--------------- 1 file changed, 4 insertions(+), 15 deletions(-) diff --git a/src/parser/style-context.ts b/src/parser/style-context.ts index a09b216d..95b6f2ea 100644 --- a/src/parser/style-context.ts +++ b/src/parser/style-context.ts @@ -3,7 +3,7 @@ import postcss from "postcss"; import { parse as SCSSparse } from "postcss-scss"; import type { Context } from "../context"; -import type { SourceLocation, SvelteStyleElement } from "../ast"; +import type { SvelteStyleElement } from "../ast"; export type StyleContext = | StyleContextNoStyleElement @@ -75,26 +75,15 @@ export function parseStyleContext( } catch (error) { return { status: "parse-error", sourceLang, error }; } - fixPostCSSNodeLocation( - sourceAst, - styleElement - ); - sourceAst.walk((node) => - fixPostCSSNodeLocation( - node, - styleElement - ) - ); + fixPostCSSNodeLocation(sourceAst, styleElement); + sourceAst.walk((node) => fixPostCSSNodeLocation(node, styleElement)); return { status: "success", sourceLang, sourceAst }; } /** * Fixes PostCSS AST locations to be relative to the whole file instead of relative to the diff --git a/tests/fixtures/parser/style-location-converter/simple-css-output.json b/tests/fixtures/parser/style-location-converter/simple-css-output.json new file mode 100644 index 00000000..af8eed52 --- /dev/null +++ b/tests/fixtures/parser/style-location-converter/simple-css-output.json @@ -0,0 +1,78 @@ +[ + [ + { + "start": { + "line": 9, + "column": 7 + } + }, + [ + 89, + null + ] + ], + [ + { + "start": { + "line": 10, + "column": 2 + }, + "end": { + "line": 12, + "column": 3 + } + }, + [ + 92, + 122 + ] + ], + [ + { + "start": { + "line": 11, + "column": 4 + }, + "end": { + "line": 11, + "column": 15 + } + }, + [ + 107, + 118 + ] + ], + [ + { + "start": { + "line": 14, + "column": 2 + }, + "end": { + "line": 16, + "column": 3 + } + }, + [ + 126, + 158 + ] + ], + [ + { + "start": { + "line": 15, + "column": 4 + }, + "end": { + "line": 15, + "column": 24 + } + }, + [ + 134, + 154 + ] + ] +] diff --git a/tests/fixtures/parser/style-location-converter/simple-scss-input.svelte b/tests/fixtures/parser/style-location-converter/simple-scss-input.svelte new file mode 100644 index 00000000..45bbe860 --- /dev/null +++ b/tests/fixtures/parser/style-location-converter/simple-scss-input.svelte @@ -0,0 +1,18 @@ +
+
Hello
+ + World! +
+ + diff --git a/tests/fixtures/parser/style-location-converter/simple-scss-output.json b/tests/fixtures/parser/style-location-converter/simple-scss-output.json new file mode 100644 index 00000000..2e622e5c --- /dev/null +++ b/tests/fixtures/parser/style-location-converter/simple-scss-output.json @@ -0,0 +1,110 @@ +[ + [ + { + "start": { + "line": 7, + "column": 19 + } + }, + [ + 130, + null + ] + ], + [ + { + "start": { + "line": 8, + "column": 2 + }, + "end": { + "line": 17, + "column": 3 + } + }, + [ + 133, + 275 + ] + ], + [ + { + "start": { + "line": 9, + "column": 4 + }, + "end": { + "line": 12, + "column": 5 + } + }, + [ + 150, + 221 + ] + ], + [ + { + "start": { + "line": 10, + "column": 6 + }, + "end": { + "line": 10, + "column": 34 + } + }, + [ + 169, + 197 + ] + ], + [ + { + "start": { + "line": 11, + "column": 6 + }, + "end": { + "line": 11, + "column": 17 + } + }, + [ + 204, + 215 + ] + ], + [ + { + "start": { + "line": 14, + "column": 4 + }, + "end": { + "line": 16, + "column": 5 + } + }, + [ + 227, + 271 + ] + ], + [ + { + "start": { + "line": 15, + "column": 6 + }, + "end": { + "line": 15, + "column": 24 + } + }, + [ + 247, + 265 + ] + ] +] diff --git a/tests/src/parser/style-location-coverter.ts b/tests/src/parser/style-location-coverter.ts new file mode 100644 index 00000000..34fe2c58 --- /dev/null +++ b/tests/src/parser/style-location-coverter.ts @@ -0,0 +1,61 @@ +import assert from "assert"; +import fs from "fs"; +import path from "path"; +import type { Node } from "postcss"; + +import { parseForESLint } from "../../../src"; +import type { SourceLocation } from "../../../src/ast"; +import { + styleNodeLoc, + styleNodeRange, +} from "../../../src/parser/style-context"; +import { generateParserOptions, listupFixtures } from "./test-utils"; + +const STYLE_CONTEXT_FIXTURE_ROOT = path.resolve( + __dirname, + "../../fixtures/parser/style-location-converter" +); + +function parse(code: string, filePath: string, config: any) { + return parseForESLint(code, generateParserOptions({ filePath }, config)); +} + +describe("Check for AST.", () => { + for (const { + input, + inputFileName, + outputFileName, + config, + meetRequirements, + } of listupFixtures(STYLE_CONTEXT_FIXTURE_ROOT)) { + describe(inputFileName, () => { + let result: any; + + it("most to generate the expected style context.", () => { + result = parse(input, inputFileName, config); + if (!meetRequirements("test")) { + return; + } + const styleContext = result.services.getStyleContext(); + assert.strictEqual(styleContext.status, "success"); + const locations: [ + Partial, + [number | undefined, number | undefined] + ][] = [ + [ + styleNodeLoc(styleContext.sourceAst), + styleNodeRange(styleContext.sourceAst), + ], + ]; + styleContext.sourceAst.walk((node: Node) => { + locations.push([styleNodeLoc(node), styleNodeRange(node)]); + }); + const output = fs.readFileSync(outputFileName, "utf8"); + assert.strictEqual( + `${JSON.stringify(locations, undefined, 2)}\n`, + output + ); + }); + }); + } +}); From 3b7a64c4829afcdecc83c1fef379e60fbc958ff4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Thu, 8 Jun 2023 15:21:05 +0200 Subject: [PATCH 30/31] Exposing the StyleContext interface --- src/index.ts | 11 ++++++++--- src/parser/index.ts | 17 ++++++++++++++++- tests/src/parser/style-context.ts | 2 +- 3 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/index.ts b/src/index.ts index f60afaf4..08290598 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,15 +1,20 @@ -import { parseForESLint } from "./parser"; import * as AST from "./ast"; import { traverseNodes } from "./traverse"; import { KEYS } from "./visitor-keys"; import { ParseError } from "./errors"; +export { + parseForESLint, + StyleContext, + StyleContextNoStyleElement, + StyleContextParseError, + StyleContextSuccess, + StyleContextUnknownLang, +} from "./parser"; export * as meta from "./meta"; export { name } from "./meta"; export { AST, ParseError }; -// parser -export { parseForESLint }; // Keys // eslint-disable-next-line @typescript-eslint/naming-convention -- ignore export const VisitorKeys = KEYS; diff --git a/src/parser/index.ts b/src/parser/index.ts index cd960754..11f99f1b 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -22,7 +22,22 @@ import { import { ParseError } from "../errors"; import { parseTypeScript } from "./typescript"; import { addReference } from "../scope"; -import { parseStyleContext, type StyleContext } from "./style-context"; +import { + parseStyleContext, + type StyleContext, + type StyleContextNoStyleElement, + type StyleContextParseError, + type StyleContextSuccess, + type StyleContextUnknownLang, +} from "./style-context"; + +export { + StyleContext, + StyleContextNoStyleElement, + StyleContextParseError, + StyleContextSuccess, + StyleContextUnknownLang, +}; export interface ESLintProgram extends Program { comments: Comment[]; diff --git a/tests/src/parser/style-context.ts b/tests/src/parser/style-context.ts index da37c11c..157e3539 100644 --- a/tests/src/parser/style-context.ts +++ b/tests/src/parser/style-context.ts @@ -3,7 +3,7 @@ import fs from "fs"; import path from "path"; import { parseForESLint } from "../../../src"; -import type { StyleContext } from "../../../src/parser/style-context"; +import type { StyleContext } from "../../../src/parser"; import { generateParserOptions, listupFixtures } from "./test-utils"; const STYLE_CONTEXT_FIXTURE_ROOT = path.resolve( From 9d280d21d617d5b4b76878560da584da4ff4bfc5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Marek=20D=C4=9Bdi=C4=8D?= Date: Thu, 8 Jun 2023 15:37:21 +0200 Subject: [PATCH 31/31] Exposing styleNodeLoc and styleNodeRange functions as part of the parser services --- src/parser/index.ts | 4 ++++ tests/src/parser/style-location-coverter.ts | 19 +++++++++---------- 2 files changed, 13 insertions(+), 10 deletions(-) diff --git a/src/parser/index.ts b/src/parser/index.ts index 11f99f1b..49346cf1 100644 --- a/src/parser/index.ts +++ b/src/parser/index.ts @@ -29,6 +29,8 @@ import { type StyleContextParseError, type StyleContextSuccess, type StyleContextUnknownLang, + styleNodeLoc, + styleNodeRange, } from "./style-context"; export { @@ -198,6 +200,8 @@ export function parseForESLint( getStyleContext() { return styleContext; }, + styleNodeLoc, + styleNodeRange, }); resultScript.visitorKeys = Object.assign({}, KEYS, resultScript.visitorKeys); diff --git a/tests/src/parser/style-location-coverter.ts b/tests/src/parser/style-location-coverter.ts index 34fe2c58..361aa507 100644 --- a/tests/src/parser/style-location-coverter.ts +++ b/tests/src/parser/style-location-coverter.ts @@ -5,10 +5,6 @@ import type { Node } from "postcss"; import { parseForESLint } from "../../../src"; import type { SourceLocation } from "../../../src/ast"; -import { - styleNodeLoc, - styleNodeRange, -} from "../../../src/parser/style-context"; import { generateParserOptions, listupFixtures } from "./test-utils"; const STYLE_CONTEXT_FIXTURE_ROOT = path.resolve( @@ -29,26 +25,29 @@ describe("Check for AST.", () => { meetRequirements, } of listupFixtures(STYLE_CONTEXT_FIXTURE_ROOT)) { describe(inputFileName, () => { - let result: any; + let services: any; it("most to generate the expected style context.", () => { - result = parse(input, inputFileName, config); + services = parse(input, inputFileName, config).services; if (!meetRequirements("test")) { return; } - const styleContext = result.services.getStyleContext(); + const styleContext = services.getStyleContext(); assert.strictEqual(styleContext.status, "success"); const locations: [ Partial, [number | undefined, number | undefined] ][] = [ [ - styleNodeLoc(styleContext.sourceAst), - styleNodeRange(styleContext.sourceAst), + services.styleNodeLoc(styleContext.sourceAst), + services.styleNodeRange(styleContext.sourceAst), ], ]; styleContext.sourceAst.walk((node: Node) => { - locations.push([styleNodeLoc(node), styleNodeRange(node)]); + locations.push([ + services.styleNodeLoc(node), + services.styleNodeRange(node), + ]); }); const output = fs.readFileSync(outputFileName, "utf8"); assert.strictEqual(