Skip to content

Commit

Permalink
feat: Support runes (#425)
Browse files Browse the repository at this point in the history
  • Loading branch information
baseballyama committed Nov 17, 2023
1 parent 9f02d12 commit ff242c4
Show file tree
Hide file tree
Showing 142 changed files with 106,377 additions and 16 deletions.
5 changes: 5 additions & 0 deletions .changeset/blue-pets-play.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"svelte-eslint-parser": minor
---

feat: Support runes
2 changes: 2 additions & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
/node_modules
/tests/fixtures/**/*.json
/tests/fixtures/**/*.svelte
/tests/fixtures/**/*.js
/tests/fixtures/**/*.ts
/explorer/dist
/explorer/node_modules
/explorer-v2/build
Expand Down
2 changes: 1 addition & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ module.exports = {
"no-lonely-if": "off",
"no-shadow": "off",
"no-warning-comments": "warn",
"require-jsdoc": "error",
"require-jsdoc": "off",
"prettier/prettier": [
"error",
{},
Expand Down
22 changes: 21 additions & 1 deletion .github/workflows/NodeCI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -35,13 +35,27 @@ jobs:
run: pnpm install
- name: Test
run: pnpm run test
test-for-svelte-v4:
test-for-svelte-v5:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- name: Use Node.js
uses: actions/setup-node@v4
- name: Install Packages
run: pnpm install
- name: Test
run: pnpm run test

test-for-svelte-v4:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: pnpm/action-setup@v2
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- name: Install Svelte v4
run: |+
pnpm install -D svelte@4
Expand All @@ -50,6 +64,7 @@ jobs:
run: pnpm install
- name: Test
run: pnpm run test

test-for-svelte-v3:
runs-on: ubuntu-latest
strategy:
Expand Down Expand Up @@ -138,12 +153,17 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 18
- name: Install Svelte v4
run: |+
pnpm install -D svelte@4
rm -rf node_modules
- name: Install Packages
run: pnpm install
- name: Update fixtures
run: pnpm run update-fixtures
- name: Check changes
run: |
git checkout package.json && \
git add --all && \
git diff-index --cached HEAD --stat --exit-code
test-and-coverage:
Expand Down
2 changes: 1 addition & 1 deletion benchmark/index.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// eslint-disable-next-line eslint-comments/disable-enable-pair -- ignore
/* eslint-disable require-jsdoc, no-console -- ignore */
/* eslint-disable no-console -- ignore */
import * as Benchmark from "benchmark";
import fs from "fs";
import { parseForESLint } from "../src/index";
Expand Down
2 changes: 1 addition & 1 deletion explorer-v2/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
"eslint-scope": "^7.0.0",
"esquery": "^1.5.0",
"pako": "^2.0.3",
"svelte": "^4.0.0",
"svelte": "^5.0.0-next.2",
"svelte-eslint-parser": "link:..",
"tslib": "^2.5.0"
},
Expand Down
16 changes: 16 additions & 0 deletions src/parser/globals.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { VERSION as SVELTE_VERSION } from "svelte/compiler";

const globalsForSvelte4: Readonly<string[]> = [
"$$slots",
"$$props",
"$$restProps",
] as const;
export const globalsForSvelte5 = [
"$state",
"$derived",
"$effect",
"$props",
] as const;
export const globals = SVELTE_VERSION.startsWith("5")
? [...globalsForSvelte4, ...globalsForSvelte5]
: globalsForSvelte4;
3 changes: 2 additions & 1 deletion src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ import {
styleNodeLoc,
styleNodeRange,
} from "./style-context";
import { globals } from "./globals";

export {
StyleContext,
Expand Down Expand Up @@ -122,7 +123,7 @@ export function parseForESLint(
analyzeStoreScope(resultScript.scopeManager!); // for reactive vars

// Add $$xxx variable
for (const $$name of ["$$slots", "$$props", "$$restProps"]) {
for (const $$name of globals) {
const globalScope = resultScript.scopeManager!.globalScope;
const variable = new Variable();
variable.name = $$name;
Expand Down
112 changes: 109 additions & 3 deletions src/parser/typescript/analyze/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,12 +16,12 @@ import { VirtualTypeScriptContext } from "../context";
import type { TSESParseForESLintResult } from "../types";
import type ESTree from "estree";
import type { SvelteAttribute, SvelteHTMLElement } from "../../../ast";
import { globalsForSvelte5, globals } from "../../../parser/globals";

export type AnalyzeTypeScriptContext = {
slots: Set<SvelteHTMLElement>;
};

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

addSvelte5Globals();

function addSvelte5Globals() {
for (const svelte5Global of globalsForSvelte5) {
if (
!scopeManager.globalScope!.through.some(
(reference) => reference.identifier.name === svelte5Global,
)
) {
continue;
}
switch (svelte5Global) {
case "$state": {
appendDeclareFunctionVirtualScript(
svelte5Global,
"<T>(initial: T): T",
);
appendDeclareFunctionVirtualScript(
svelte5Global,
"<T>(): T | undefined",
);
break;
}
case "$derived": {
appendDeclareFunctionVirtualScript(
svelte5Global,
"<T>(expression: T): T",
);
break;
}
case "$effect": {
appendDeclareFunctionVirtualScript(
svelte5Global,
"(fn: () => void | (() => void)): void",
);
appendDeclareNamespaceVirtualScript(
svelte5Global,
"export function pre(fn: () => void | (() => void)): void;",
);
break;
}
case "$props": {
appendDeclareFunctionVirtualScript(svelte5Global, "<T>(): T");
break;
}
default: {
const _: never = svelte5Global;
throw Error(`Unknown global: ${_}`);
}
}
}
}

/** Append declare virtual script */
function appendDeclareVirtualScript(name: string, type: string) {
ctx.appendVirtualScript(`declare let ${name}: ${type};`);
Expand Down Expand Up @@ -242,6 +295,59 @@ function analyzeDollarDollarVariables(
return true;
});
}

/** Append declare virtual script */
function appendDeclareFunctionVirtualScript(name: string, type: string) {
ctx.appendVirtualScript(`declare function ${name}${type};`);
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
if (
node.type !== "TSDeclareFunction" ||
!node.declare ||
node.id?.type !== "Identifier" ||
node.id.name !== name
) {
return false;
}
const program = result.ast;
program.body.splice(program.body.indexOf(node), 1);

const scopeManager = result.scopeManager as ScopeManager;

// Remove `declare` variable
removeAllScopeAndVariableAndReference(node, {
visitorKeys: result.visitorKeys,
scopeManager,
});

return true;
});
}

function appendDeclareNamespaceVirtualScript(name: string, script: string) {
ctx.appendVirtualScript(`declare namespace $effect { ${script} }`);
ctx.restoreContext.addRestoreStatementProcess((node, result) => {
if (
node.type !== "TSModuleDeclaration" ||
!node.declare ||
node.id?.type !== "Identifier" ||
node.id.name !== name
) {
return false;
}
const program = result.ast;
program.body.splice(program.body.indexOf(node), 1);

const scopeManager = result.scopeManager as ScopeManager;

// Remove `declare` variable
removeAllScopeAndVariableAndReference(node, {
visitorKeys: result.visitorKeys,
scopeManager,
});

return true;
});
}
}

/**
Expand Down
67 changes: 67 additions & 0 deletions tests/fixtures/parser/ast/$$slots-scope-output-svelte5.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
{
"variables": [
{
"name": "$$slots",
"identifiers": [],
"defs": [],
"references": [
{
"identifier": {
"type": "Identifier",
"name": "$$slots",
"range": [5, 12],
"loc": {
"start": {
"line": 1,
"column": 5
},
"end": {
"line": 1,
"column": 12
}
}
},
"from": "module",
"init": null,
"resolved": null
}
]
},
{
"name": "$$props",
"identifiers": [],
"defs": [],
"references": []
},
{
"name": "$$restProps",
"identifiers": [],
"defs": [],
"references": []
},
{
"name": "$state",
"identifiers": [],
"defs": [],
"references": []
},
{
"name": "$derived",
"identifiers": [],
"defs": [],
"references": []
},
{
"name": "$effect",
"identifiers": [],
"defs": [],
"references": []
},
{
"name": "$props",
"identifiers": [],
"defs": [],
"references": []
}
]
}

0 comments on commit ff242c4

Please sign in to comment.