Skip to content

Commit df28a46

Browse files
authored
feat!: use @astrojs/compiler-rs (#568)
* feat!: use astro-eslint-parser v2 * Create seven-chicken-clap.md * update * fix * fix * update valid-compile * update * update astro-eslint-parser * format * update doc script * update changeset
1 parent f8cbb64 commit df28a46

17 files changed

Lines changed: 341 additions & 74 deletions

File tree

.changeset/seven-chicken-clap.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"eslint-plugin-astro": major
3+
---
4+
5+
Upgrade `astro-eslint-parser` to v3. Astro files are now parsed with Astro's
6+
Rust compiler (`@astrojs/compiler-rs`) instead of `@astrojs/compiler`.

astro.config.mjs

Lines changed: 81 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -51,33 +51,90 @@ export default defineConfig({
5151
server: {
5252
fs: { strict: false },
5353
},
54+
optimizeDeps: {
55+
// Do not prebundle compiler-rs: its WASI browser entry resolves a sibling
56+
// .wasm file, and prebundling rewrites that URL to node_modules/.vite/deps.
57+
exclude: [
58+
"@astrojs/compiler-binding",
59+
"@astrojs/compiler-binding-wasm32-wasi",
60+
"@astrojs/compiler-rs",
61+
],
62+
},
5463
resolve: {
55-
alias: {
56-
"astro-eslint-parser": path.join(
57-
dirname,
58-
"./docs-build/shim/astro-eslint-parser.mjs",
59-
),
60-
"eslint-plugin-jsx-a11y": path.join(
61-
dirname,
62-
"./docs-build/shim/eslint-plugin-jsx-a11y.mjs",
63-
),
64+
alias: [
65+
{
66+
find: "eslint-plugin-jsx-a11y",
67+
replacement: path.join(
68+
dirname,
69+
"./docs-build/shim/eslint-plugin-jsx-a11y.mjs",
70+
),
71+
},
6472
// node
65-
url: path.join(dirname, "./docs-build/shim/url.mjs"),
66-
module: path.join(dirname, "./docs-build/shim/module.mjs"),
67-
"node:url": path.join(dirname, "./docs-build/shim/url.mjs"),
68-
"node:module": path.join(dirname, "./docs-build/shim/module.mjs"),
69-
"fast-glob": path.join(dirname, "./docs-build/shim/fast-glob.mjs"),
70-
tinyglobby: path.join(dirname, "./docs-build/shim/tinyglobby.mjs"),
73+
{
74+
find: "url",
75+
replacement: path.join(dirname, "./docs-build/shim/url.mjs"),
76+
},
77+
{
78+
find: "module",
79+
replacement: path.join(dirname, "./docs-build/shim/module.mjs"),
80+
},
81+
{
82+
find: "node:url",
83+
replacement: path.join(dirname, "./docs-build/shim/url.mjs"),
84+
},
85+
{
86+
find: "node:module",
87+
replacement: path.join(dirname, "./docs-build/shim/module.mjs"),
88+
},
89+
{
90+
find: "fast-glob",
91+
replacement: path.join(dirname, "./docs-build/shim/fast-glob.mjs"),
92+
},
93+
{
94+
find: "tinyglobby",
95+
replacement: path.join(dirname, "./docs-build/shim/tinyglobby.mjs"),
96+
},
7197
// override tsconfig (it had no effect...)
72-
"@eslint-community/eslint-utils": path.join(
73-
dirname,
74-
"./node_modules/@eslint-community/eslint-utils",
75-
),
76-
"node:path": path.join(
77-
dirname,
78-
"./node_modules/vite-plugin-eslint4b/shim/path-shim.mjs",
79-
),
80-
},
98+
{
99+
find: "@eslint-community/eslint-utils",
100+
replacement: path.join(
101+
dirname,
102+
"./node_modules/@eslint-community/eslint-utils",
103+
),
104+
},
105+
{
106+
find: "node:path",
107+
replacement: path.join(
108+
dirname,
109+
"./node_modules/vite-plugin-eslint4b/shim/path-shim.mjs",
110+
),
111+
},
112+
// Force compiler-rs onto its browser binding; the default binding
113+
// imports node:module and native .node packages.
114+
{
115+
find: "@astrojs/compiler-binding",
116+
replacement: path.join(
117+
dirname,
118+
"./node_modules/@astrojs/compiler-binding/browser.js",
119+
),
120+
},
121+
// The wasm32-wasi binding is optional for Node installs, so the explorer
122+
// carries it directly and aliases exact imports to its browser files.
123+
{
124+
find: /^@astrojs\/compiler-binding-wasm32-wasi$/,
125+
replacement: path.join(
126+
dirname,
127+
"./node_modules/@astrojs/compiler-binding-wasm32-wasi/astro.wasi-browser.js",
128+
),
129+
},
130+
{
131+
find: /^@astrojs\/compiler-binding-wasm32-wasi\/wasi-worker-browser\.mjs$/,
132+
replacement: path.join(
133+
dirname,
134+
"./node_modules/@astrojs/compiler-binding-wasm32-wasi/wasi-worker-browser.mjs",
135+
),
136+
},
137+
],
81138
},
82139
plugins: [
83140
eslint4b(),

docs-build/build-system/build.mjs

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,17 @@ const __dirname = path.dirname(new URL(import.meta.url).pathname)
88
// const babelCore = require("@babel/core")
99
// const t = require("@babel/types")
1010

11-
build(
12-
require.resolve("./src/astro-eslint-parser.mjs"),
13-
path.join(__dirname, "../shim/astro-eslint-parser.mjs"),
14-
[
15-
"fs",
16-
"module",
17-
"fast-glob",
18-
"tinyglobby",
19-
{ name: "@typescript-eslint/parser", kind: "cjs" },
20-
],
21-
)
11+
// build(
12+
// require.resolve("./src/astro-eslint-parser.mjs"),
13+
// path.join(__dirname, "../shim/astro-eslint-parser.mjs"),
14+
// [
15+
// "fs",
16+
// "module",
17+
// "fast-glob",
18+
// "tinyglobby",
19+
// { name: "@typescript-eslint/parser", kind: "cjs" },
20+
// ],
21+
// )
2222
build(
2323
require.resolve("./src/eslint-plugin-jsx-a11y.mjs"),
2424
path.join(__dirname, "../shim/eslint-plugin-jsx-a11y.mjs"),

docs-build/build-system/src/astro-eslint-parser.mjs

Lines changed: 0 additions & 7 deletions
This file was deleted.

docs-build/src/components/eslint/scripts/linter.mts

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,6 @@ export function rulesMap(): Map<string, Rule.RuleModule> {
143143
export async function createLinterConfig(): Promise<Linter.Config[]> {
144144
const tsParser = await import("@typescript-eslint/parser")
145145

146-
await (astroEslintParser as any).setup()
147146
return [
148147
{
149148
files: ["**"],

package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@
7272
"@eslint-community/eslint-utils": "^4.5.1",
7373
"@jridgewell/sourcemap-codec": "^1.5.0",
7474
"@typescript-eslint/types": "^8.61.0",
75-
"astro-eslint-parser": "^2.0.0",
75+
"astro-eslint-parser": "^3.0.0",
7676
"espree": "^11.0.0",
7777
"globals": "^17.0.0",
7878
"postcss": "^8.5.3",
@@ -94,6 +94,7 @@
9494
"devDependencies": {
9595
"@actions/github": "^9.0.0",
9696
"@astrojs/compiler": "^4.0.0",
97+
"@astrojs/compiler-binding-wasm32-wasi": "^0.3.1",
9798
"@astrojs/markdown-satteri": "0.3.3",
9899
"@astrojs/mdx": "^7.0.0",
99100
"@astrojs/svelte": "^9.0.0",

src/processor/astro/node.ts

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
import type {
2+
AstroFrontmatterNode,
3+
AstroScriptNode,
4+
JSXClosingElementNode,
5+
JSXElementNode,
6+
JSXOpeningElementNode,
7+
UnknownNode,
8+
} from "./types.ts"
9+
10+
/** Check whether the given node is a JSX element */
11+
export function isJSXElement(node: UnknownNode): node is JSXElementNode {
12+
return node.type === "JSXElement"
13+
}
14+
15+
/** Check whether the given node is a JSX opening element. */
16+
export function isJSXOpeningElement(
17+
node: UnknownNode,
18+
): node is JSXOpeningElementNode {
19+
return node.type === "JSXOpeningElement"
20+
}
21+
22+
/** Check whether the given node is a JSX closing element. */
23+
export function isJSXClosingElement(
24+
node: UnknownNode,
25+
): node is JSXClosingElementNode {
26+
return node.type === "JSXClosingElement"
27+
}
28+
29+
/** Check whether the given node is a Astro frontmatter node. */
30+
export function isAstroFrontmatter(
31+
node: UnknownNode,
32+
): node is AstroFrontmatterNode {
33+
return node.type === "AstroFrontmatter"
34+
}
35+
36+
/** Check whether the given node is a Astro script node. */
37+
export function isAstroScriptNode(node: UnknownNode): node is AstroScriptNode {
38+
return node.type === "AstroScript"
39+
}

src/processor/astro/types.ts

Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
export type DiagnosticSeverity = "error" | "warning" | "information" | "hint"
2+
3+
export type DiagnosticLabel = {
4+
text: string | null
5+
start: number
6+
end: number
7+
line: number
8+
column: number
9+
}
10+
11+
export type DiagnosticMessage = {
12+
severity: DiagnosticSeverity
13+
text: string
14+
hint?: string
15+
labels?: DiagnosticLabel[]
16+
}
17+
18+
export type ParseResult = {
19+
ast: AstroRootNode
20+
diagnostics: DiagnosticMessage[]
21+
}
22+
23+
export type LocatedNode = {
24+
start: number
25+
end: number
26+
}
27+
28+
export type UnknownNode = LocatedNode & {
29+
type: unknown
30+
}
31+
32+
export type ProgramNode = LocatedNode & {
33+
type: "Program"
34+
body: UnknownNode[]
35+
}
36+
37+
export type AstroRootNode = LocatedNode & {
38+
type: "AstroRoot"
39+
frontmatter?: AstroFrontmatterNode
40+
body: UnknownNode[]
41+
}
42+
43+
export type AstroFrontmatterNode = LocatedNode & {
44+
type: "AstroFrontmatter"
45+
program: ProgramNode
46+
}
47+
48+
export type AstroScriptNode = LocatedNode & {
49+
type: "AstroScript"
50+
program: ProgramNode
51+
}
52+
53+
export type JSXElementNode = LocatedNode & {
54+
type: "JSXElement"
55+
openingElement: JSXOpeningElementNode
56+
closingElement: JSXClosingElementNode | null
57+
children: UnknownNode[]
58+
}
59+
60+
export type JSXOpeningElementNode = LocatedNode & {
61+
type: "JSXOpeningElement"
62+
name: JSXNameNode
63+
attributes: AttributeNode[]
64+
selfClosing: boolean
65+
}
66+
67+
export type JSXClosingElementNode = LocatedNode & {
68+
type: "JSXClosingElement"
69+
name: JSXNameNode
70+
}
71+
72+
export type JSXExpressionContainerNode = LocatedNode & {
73+
type: "JSXExpressionContainer"
74+
expression: UnknownNode
75+
}
76+
77+
export type AttributeNode = JSXAttributeNode | JSXSpreadAttributeNode
78+
79+
export type JSXAttributeNode = LocatedNode & {
80+
type: "JSXAttribute"
81+
name: JSXNameNode
82+
value: JSXExpressionContainerNode | LiteralNode | null
83+
}
84+
85+
export type JSXSpreadAttributeNode = LocatedNode & {
86+
type: "JSXSpreadAttribute"
87+
argument: LocatedNode
88+
}
89+
90+
export type LiteralNode = LocatedNode & {
91+
type: "Literal"
92+
value: unknown
93+
raw?: string
94+
}
95+
96+
export type JSXNameNode =
97+
JSXIdentifierNode | JSXMemberExpressionNode | JSXNamespacedNameNode
98+
99+
export type JSXIdentifierNode = LocatedNode & {
100+
type: "JSXIdentifier"
101+
name: string
102+
}
103+
104+
export type JSXMemberExpressionNode = LocatedNode & {
105+
type: "JSXMemberExpression"
106+
object: JSXIdentifierNode | JSXMemberExpressionNode
107+
property: JSXIdentifierNode
108+
}
109+
110+
export type JSXNamespacedNameNode = LocatedNode & {
111+
type: "JSXNamespacedName"
112+
namespace: JSXIdentifierNode
113+
name: JSXIdentifierNode
114+
}

src/processor/index.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,13 @@ import { parseTemplate } from "astro-eslint-parser"
33
import type { Linter } from "eslint"
44
import { beginShared, terminateShared } from "../shared/index.ts"
55
import * as meta from "../meta.ts"
6+
import {
7+
isAstroFrontmatter,
8+
isAstroScriptNode,
9+
isJSXClosingElement,
10+
isJSXElement,
11+
isJSXOpeningElement,
12+
} from "./astro/node.ts"
613

714
export const astroProcessor: Linter.Processor = {
815
preprocess(code: string, filename: string) {
@@ -38,17 +45,32 @@ function preprocess(
3845
return [code]
3946
}
4047

41-
parsed.walk(parsed.result.ast, (node) => {
48+
parsed.walk(parsed.result.ast, (node, _, ctx) => {
4249
if (
43-
node.type === "element" &&
44-
node.name === "script" &&
45-
node.children.length &&
46-
!node.attributes.some(
47-
({ name, value }) =>
48-
name === "type" && /json$|importmap/i.test(value),
49-
)
50+
isAstroFrontmatter(node) ||
51+
isJSXOpeningElement(node) ||
52+
isJSXClosingElement(node) ||
53+
isAstroScriptNode(node)
5054
) {
51-
shared.addClientScript(code, node, parsed)
55+
ctx.skipChildren()
56+
return
57+
}
58+
if (isJSXElement(node)) {
59+
if (
60+
node.openingElement.name.type === "JSXIdentifier" &&
61+
node.openingElement.name.name === "script" &&
62+
node.children.length &&
63+
!node.openingElement.attributes.some(
64+
(attr) =>
65+
attr.type === "JSXAttribute" &&
66+
attr.name.type === "JSXIdentifier" &&
67+
attr.name.name === "type" &&
68+
attr.value?.type === "Literal" &&
69+
/json$|importmap/i.test(String(attr.value.value)),
70+
)
71+
) {
72+
shared.addClientScript(code, node, parsed)
73+
}
5274
}
5375
})
5476
return [

0 commit comments

Comments
 (0)