Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -107,3 +107,6 @@ dist
/lib
/.nyc_output
/coverage

# svelte-eslint-parser virtual code cache
.svelte-eslint-parser/
1 change: 1 addition & 0 deletions eslint.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
"!.github",
"explorer-v2/.svelte-kit",
".changeset/pre.json",
".svelte-eslint-parser",
],
},
...myPlugin.config({
Expand All @@ -46,7 +47,7 @@
"@typescript-eslint/no-shadow": "off",
"no-warning-comments": "warn",
"jsdoc/require-jsdoc": "off",
// FIXME: Turning off this rule because it causes `TypeError: aVer.compare is not a function` error.

Check warning on line 50 in eslint.config.mjs

View workflow job for this annotation

GitHub Actions / lint

Unexpected 'fixme' comment: 'FIXME: Turning off this rule because it...'
// Most likely the root cause needs to be fixed on the rule side.
"node-dependencies/compat-engines": "off",
complexity: "off",
Expand Down
7 changes: 5 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -62,14 +62,17 @@
"eslint-scope": "^8.2.0",
"eslint-visitor-keys": "^4.0.0",
"espree": "^10.0.0",
"ignore": "^7.0.5",
"postcss": "^8.4.49",
"postcss-scss": "^4.0.9",
"postcss-selector-parser": "^7.0.0"
"postcss-selector-parser": "^7.0.0",
"proper-lockfile": "^4.1.2"
},
"devDependencies": {
"@changesets/changelog-github": "^0.5.1",
"@changesets/cli": "^2.29.7",
"@changesets/get-release-plan": "^4.0.13",
"@eslint-community/eslint-plugin-eslint-comments": "4.3.0",
"@ota-meshi/eslint-plugin": "^0.19.0",
"@ota-meshi/test-snapshot": "^1.1.1",
"@types/benchmark": "^2.1.5",
Expand All @@ -80,6 +83,7 @@
"@types/estree": "^1.0.8",
"@types/mocha": "^10.0.10",
"@types/node": "^24.0.0",
"@types/proper-lockfile": "^4.1.4",
"@types/semver": "^7.7.1",
"@typescript-eslint/parser": "^8.46.1",
"@typescript-eslint/scope-manager": "^8.46.1",
Expand All @@ -91,7 +95,6 @@
"esbuild": "^0.27.0",
"eslint": "^9.37.0",
"eslint-config-prettier": "^10.1.8",
"eslint-plugin-eslint-comments": "^3.2.0",
"eslint-plugin-jsdoc": "^62.0.0",
"eslint-plugin-json-schema-validator": "^6.0.0",
"eslint-plugin-jsonc": "^2.20.1",
Expand Down
77 changes: 50 additions & 27 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

17 changes: 17 additions & 0 deletions src/parser/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ import {
} from "./svelte-parse-context.js";
import type { SvelteConfig } from "../svelte-config/index.js";
import { resolveSvelteConfigFromOption } from "../svelte-config/index.js";
import { getVirtualCodeCacheManager } from "../virtual-code/index.js";
import { initializeVirtualCodeCache } from "./virtual-code-initializer.js";

export {
StyleContext,
Expand Down Expand Up @@ -116,6 +118,21 @@ export function parseForESLint(code: string, options?: any): ParseResult {
const svelteConfig = resolveSvelteConfigFromOption(options);
const parserOptions = normalizeParserOptions(options);

// Initialize virtual code cache for TypeScript type-aware linting
// Only enabled when svelteFeatures.experimentalGenerateVirtualCodeCache is true
// Note: We only initialize the cache here; the actual tsconfig/filePath replacement
// happens in parseTypeScriptInSvelte to ensure we have a valid virtual file path
if (
parserOptions.svelteFeatures?.experimentalGenerateVirtualCodeCache &&
(parserOptions.projectService || parserOptions.project)
) {
const cacheManager = getVirtualCodeCacheManager();

if (!cacheManager.isInitialized() && parserOptions.filePath) {
initializeVirtualCodeCache(parserOptions.filePath, parserOptions);
}
}

if (
parserOptions.filePath &&
(parserOptions.filePath.endsWith(".svelte.js") ||
Expand Down
8 changes: 8 additions & 0 deletions src/parser/parser-options.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,11 @@ export type NormalizedParserOptions = {
// If not configured this option, The parser will try to read the option from `compilerOptions.runes` from `svelte.config.js`.
// If `parserOptions.svelteConfig` is not specified and the file cannot be parsed by static analysis, it will behave as `true`.
runes?: boolean;
// Enable virtual code caching to speed up type-aware linting.
// When enabled, the parser generates virtual TypeScript files for all Svelte files
// in the project and creates a tsconfig that includes them.
// Default: false
experimentalGenerateVirtualCodeCache?: boolean;
};
loc: boolean;
range: boolean;
Expand All @@ -36,6 +41,9 @@ export type NormalizedParserOptions = {
eslintVisitorKeys: boolean;
eslintScopeManager: boolean;
filePath?: string;

// Internal use: tsconfig paths for import rewriting
__tsconfigPaths?: Record<string, string[]> | null;
};

/** Normalize parserOptions */
Expand Down
13 changes: 12 additions & 1 deletion src/parser/typescript/analyze/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,10 @@ import {
sortedLastIndex,
} from "../../../utils/index.js";
import { parseScriptWithoutAnalyzeScope } from "../../script.js";
import { VirtualTypeScriptContext } from "../context.js";
import {
VirtualTypeScriptContext,
extractSvelteImportsFromAST,
} from "../context.js";
import type { TSESParseForESLintResult } from "../types.js";
import type ESTree from "estree";
import type { SvelteAttribute, SvelteHTMLElement } from "../../../ast/index.js";
Expand Down Expand Up @@ -99,6 +102,10 @@ export function analyzeTypeScriptInSvelte(

ctx.appendOriginalToEnd();

// Extract .svelte imports from AST and compute their positions in virtual code
const svelteImportPaths = extractSvelteImportsFromAST(result.ast);
ctx.computeSvelteImportPositions(svelteImportPaths);

return ctx;
}
/**
Expand Down Expand Up @@ -132,6 +139,10 @@ export function analyzeTypeScript(

ctx.appendOriginalToEnd();

// Extract .svelte imports from AST and compute their positions in virtual code
const svelteImportPaths = extractSvelteImportsFromAST(result.ast);
ctx.computeSvelteImportPositions(svelteImportPaths);

return ctx;
}

Expand Down
Loading
Loading