Skip to content

Commit ff242c4

Browse files
authored
feat: Support runes (#425)
1 parent 9f02d12 commit ff242c4

File tree

142 files changed

+106377
-16
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

142 files changed

+106377
-16
lines changed

.changeset/blue-pets-play.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"svelte-eslint-parser": minor
3+
---
4+
5+
feat: Support runes

.eslintignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
/node_modules
55
/tests/fixtures/**/*.json
66
/tests/fixtures/**/*.svelte
7+
/tests/fixtures/**/*.js
8+
/tests/fixtures/**/*.ts
79
/explorer/dist
810
/explorer/node_modules
911
/explorer-v2/build

.eslintrc.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ module.exports = {
2020
"no-lonely-if": "off",
2121
"no-shadow": "off",
2222
"no-warning-comments": "warn",
23-
"require-jsdoc": "error",
23+
"require-jsdoc": "off",
2424
"prettier/prettier": [
2525
"error",
2626
{},

.github/workflows/NodeCI.yml

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,27 @@ jobs:
3535
run: pnpm install
3636
- name: Test
3737
run: pnpm run test
38-
test-for-svelte-v4:
38+
test-for-svelte-v5:
3939
runs-on: ubuntu-latest
4040
steps:
4141
- uses: actions/checkout@v4
4242
- uses: pnpm/action-setup@v2
4343
- name: Use Node.js
4444
uses: actions/setup-node@v4
45+
- name: Install Packages
46+
run: pnpm install
47+
- name: Test
48+
run: pnpm run test
49+
50+
test-for-svelte-v4:
51+
runs-on: ubuntu-latest
52+
steps:
53+
- uses: actions/checkout@v4
54+
- uses: pnpm/action-setup@v2
55+
- name: Use Node.js ${{ matrix.node-version }}
56+
uses: actions/setup-node@v4
57+
with:
58+
node-version: ${{ matrix.node-version }}
4559
- name: Install Svelte v4
4660
run: |+
4761
pnpm install -D svelte@4
@@ -50,6 +64,7 @@ jobs:
5064
run: pnpm install
5165
- name: Test
5266
run: pnpm run test
67+
5368
test-for-svelte-v3:
5469
runs-on: ubuntu-latest
5570
strategy:
@@ -138,12 +153,17 @@ jobs:
138153
- uses: actions/setup-node@v4
139154
with:
140155
node-version: 18
156+
- name: Install Svelte v4
157+
run: |+
158+
pnpm install -D svelte@4
159+
rm -rf node_modules
141160
- name: Install Packages
142161
run: pnpm install
143162
- name: Update fixtures
144163
run: pnpm run update-fixtures
145164
- name: Check changes
146165
run: |
166+
git checkout package.json && \
147167
git add --all && \
148168
git diff-index --cached HEAD --stat --exit-code
149169
test-and-coverage:

benchmark/index.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
// eslint-disable-next-line eslint-comments/disable-enable-pair -- ignore
2-
/* eslint-disable require-jsdoc, no-console -- ignore */
2+
/* eslint-disable no-console -- ignore */
33
import * as Benchmark from "benchmark";
44
import fs from "fs";
55
import { parseForESLint } from "../src/index";

explorer-v2/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818
"eslint-scope": "^7.0.0",
1919
"esquery": "^1.5.0",
2020
"pako": "^2.0.3",
21-
"svelte": "^4.0.0",
21+
"svelte": "^5.0.0-next.2",
2222
"svelte-eslint-parser": "link:..",
2323
"tslib": "^2.5.0"
2424
},

src/parser/globals.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
import { VERSION as SVELTE_VERSION } from "svelte/compiler";
2+
3+
const globalsForSvelte4: Readonly<string[]> = [
4+
"$$slots",
5+
"$$props",
6+
"$$restProps",
7+
] as const;
8+
export const globalsForSvelte5 = [
9+
"$state",
10+
"$derived",
11+
"$effect",
12+
"$props",
13+
] as const;
14+
export const globals = SVELTE_VERSION.startsWith("5")
15+
? [...globalsForSvelte4, ...globalsForSvelte5]
16+
: globalsForSvelte4;

src/parser/index.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ import {
3232
styleNodeLoc,
3333
styleNodeRange,
3434
} from "./style-context";
35+
import { globals } from "./globals";
3536

3637
export {
3738
StyleContext,
@@ -122,7 +123,7 @@ export function parseForESLint(
122123
analyzeStoreScope(resultScript.scopeManager!); // for reactive vars
123124

124125
// Add $$xxx variable
125-
for (const $$name of ["$$slots", "$$props", "$$restProps"]) {
126+
for (const $$name of globals) {
126127
const globalScope = resultScript.scopeManager!.globalScope;
127128
const variable = new Variable();
128129
variable.name = $$name;

src/parser/typescript/analyze/index.ts

Lines changed: 109 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,12 +16,12 @@ import { VirtualTypeScriptContext } from "../context";
1616
import type { TSESParseForESLintResult } from "../types";
1717
import type ESTree from "estree";
1818
import type { SvelteAttribute, SvelteHTMLElement } from "../../../ast";
19+
import { globalsForSvelte5, globals } from "../../../parser/globals";
1920

2021
export type AnalyzeTypeScriptContext = {
2122
slots: Set<SvelteHTMLElement>;
2223
};
2324

24-
const RESERVED_NAMES = new Set<string>(["$$props", "$$restProps", "$$slots"]);
2525
/**
2626
* Analyze TypeScript source code.
2727
* Generate virtual code to provide correct type information for Svelte store reference namess and scopes.
@@ -75,8 +75,8 @@ function analyzeStoreReferenceNames(
7575
if (
7676
// Begin with `$`.
7777
reference.identifier.name.startsWith("$") &&
78-
// Ignore it is a reserved variable.
79-
!RESERVED_NAMES.has(reference.identifier.name) &&
78+
// Ignore globals
79+
!globals.includes(reference.identifier.name) &&
8080
// Ignore if it is already defined.
8181
!programScope.set.has(reference.identifier.name)
8282
) {
@@ -215,6 +215,59 @@ function analyzeDollarDollarVariables(
215215
);
216216
}
217217

218+
addSvelte5Globals();
219+
220+
function addSvelte5Globals() {
221+
for (const svelte5Global of globalsForSvelte5) {
222+
if (
223+
!scopeManager.globalScope!.through.some(
224+
(reference) => reference.identifier.name === svelte5Global,
225+
)
226+
) {
227+
continue;
228+
}
229+
switch (svelte5Global) {
230+
case "$state": {
231+
appendDeclareFunctionVirtualScript(
232+
svelte5Global,
233+
"<T>(initial: T): T",
234+
);
235+
appendDeclareFunctionVirtualScript(
236+
svelte5Global,
237+
"<T>(): T | undefined",
238+
);
239+
break;
240+
}
241+
case "$derived": {
242+
appendDeclareFunctionVirtualScript(
243+
svelte5Global,
244+
"<T>(expression: T): T",
245+
);
246+
break;
247+
}
248+
case "$effect": {
249+
appendDeclareFunctionVirtualScript(
250+
svelte5Global,
251+
"(fn: () => void | (() => void)): void",
252+
);
253+
appendDeclareNamespaceVirtualScript(
254+
svelte5Global,
255+
"export function pre(fn: () => void | (() => void)): void;",
256+
);
257+
break;
258+
}
259+
case "$props": {
260+
appendDeclareFunctionVirtualScript(svelte5Global, "<T>(): T");
261+
break;
262+
}
263+
default: {
264+
const _: never = svelte5Global;
265+
throw Error(`Unknown global: ${_}`);
266+
}
267+
}
268+
}
269+
}
270+
218271
/** Append declare virtual script */
219272
function appendDeclareVirtualScript(name: string, type: string) {
220273
ctx.appendVirtualScript(`declare let ${name}: ${type};`);
@@ -242,6 +295,59 @@ function analyzeDollarDollarVariables(
242295
return true;
243296
});
244297
}
298+
299+
/** Append declare virtual script */
300+
function appendDeclareFunctionVirtualScript(name: string, type: string) {
301+
ctx.appendVirtualScript(`declare function ${name}${type};`);
302+
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
303+
if (
304+
node.type !== "TSDeclareFunction" ||
305+
!node.declare ||
306+
node.id?.type !== "Identifier" ||
307+
node.id.name !== name
308+
) {
309+
return false;
310+
}
311+
const program = result.ast;
312+
program.body.splice(program.body.indexOf(node), 1);
313+
314+
const scopeManager = result.scopeManager as ScopeManager;
315+
316+
// Remove `declare` variable
317+
removeAllScopeAndVariableAndReference(node, {
318+
visitorKeys: result.visitorKeys,
319+
scopeManager,
320+
});
321+
322+
return true;
323+
});
324+
}
325+
326+
function appendDeclareNamespaceVirtualScript(name: string, script: string) {
327+
ctx.appendVirtualScript(`declare namespace $effect { ${script} }`);
328+
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
329+
if (
330+
node.type !== "TSModuleDeclaration" ||
331+
!node.declare ||
332+
node.id?.type !== "Identifier" ||
333+
node.id.name !== name
334+
) {
335+
return false;
336+
}
337+
const program = result.ast;
338+
program.body.splice(program.body.indexOf(node), 1);
339+
340+
const scopeManager = result.scopeManager as ScopeManager;
341+
342+
// Remove `declare` variable
343+
removeAllScopeAndVariableAndReference(node, {
344+
visitorKeys: result.visitorKeys,
345+
scopeManager,
346+
});
347+
348+
return true;
349+
});
350+
}
245351
}
246352

247353
/**
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
{
2+
"variables": [
3+
{
4+
"name": "$$slots",
5+
"identifiers": [],
6+
"defs": [],
7+
"references": [
8+
{
9+
"identifier": {
10+
"type": "Identifier",
11+
"name": "$$slots",
12+
"range": [5, 12],
13+
"loc": {
14+
"start": {
15+
"line": 1,
16+
"column": 5
17+
},
18+
"end": {
19+
"line": 1,
20+
"column": 12
21+
}
22+
}
23+
},
24+
"from": "module",
25+
"init": null,
26+
"resolved": null
27+
}
28+
]
29+
},
30+
{
31+
"name": "$$props",
32+
"identifiers": [],
33+
"defs": [],
34+
"references": []
35+
},
36+
{
37+
"name": "$$restProps",
38+
"identifiers": [],
39+
"defs": [],
40+
"references": []
41+
},
42+
{
43+
"name": "$state",
44+
"identifiers": [],
45+
"defs": [],
46+
"references": []
47+
},
48+
{
49+
"name": "$derived",
50+
"identifiers": [],
51+
"defs": [],
52+
"references": []
53+
},
54+
{
55+
"name": "$effect",
56+
"identifiers": [],
57+
"defs": [],
58+
"references": []
59+
},
60+
{
61+
"name": "$props",
62+
"identifiers": [],
63+
"defs": [],
64+
"references": []
65+
}
66+
]
67+
}

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy