Skip to content

Commit f686b4d

Browse files
committed
more robust
1 parent afd422d commit f686b4d

File tree

3 files changed

+127
-54
lines changed

3 files changed

+127
-54
lines changed

packages/eslint-plugin-svelte/src/utils/get-package-json.ts

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,8 @@ type PackageJson = {
1414
};
1515

1616
const isRunOnBrowser = !fs.readFileSync;
17-
const cache = createCache<PackageJson | null>();
17+
const packageJsonCache = createCache<PackageJson | null>();
18+
const packageJsonsCache = createCache<PackageJson[]>();
1819

1920
/**
2021
* Reads the `package.json` data in a given path.
@@ -49,34 +50,37 @@ function readPackageJson(dir: string): PackageJson | null {
4950
* @returns A found `package.json` data or `null`.
5051
* This object have additional property `filePath`.
5152
*/
52-
export function getPackageJson(startPath = 'a.js'): PackageJson | null {
53-
if (isRunOnBrowser) return null;
53+
export function getPackageJsons(startPath = 'a.js'): PackageJson[] {
54+
if (isRunOnBrowser) return [];
55+
56+
const cached = packageJsonsCache.get(startPath);
57+
if (cached) {
58+
return cached;
59+
}
60+
61+
const packageJsons: PackageJson[] = [];
5462
const startDir = path.dirname(path.resolve(startPath));
5563
let dir = startDir;
5664
let prevDir = '';
5765
let data = null;
5866

5967
do {
60-
data = cache.get(dir);
68+
data = packageJsonCache.get(dir);
6169
if (data) {
62-
if (dir !== startDir) {
63-
cache.set(startDir, data);
64-
}
65-
return data;
70+
packageJsons.push(data);
6671
}
6772

6873
data = readPackageJson(dir);
6974
if (data) {
70-
cache.set(dir, data);
71-
cache.set(startDir, data);
72-
return data;
75+
packageJsonCache.set(dir, data);
76+
packageJsons.push(data);
7377
}
7478

7579
// Go to next.
7680
prevDir = dir;
7781
dir = path.resolve(dir, '..');
7882
} while (dir !== prevDir);
7983

80-
cache.set(startDir, null);
81-
return null;
84+
packageJsonsCache.set(startDir, packageJsons);
85+
return packageJsons;
8286
}

packages/eslint-plugin-svelte/src/utils/svelte-context.ts

Lines changed: 109 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,40 @@
11
import type { RuleContext } from '../types.js';
22
import fs from 'fs';
33
import path from 'path';
4-
import { getPackageJson } from './get-package-json.js';
4+
import { getPackageJsons } from './get-package-json.js';
55
import { getFilename, getSourceCode } from './compat.js';
66

77
const isRunInBrowser = !fs.readFileSync;
88

9-
export type SvelteContext = {
10-
svelteVersion: '3/4' | '5' | 'undetermined';
11-
svelteFileType: '.svelte' | '.svelte.[js|ts]' | null;
12-
runes: boolean | 'undetermined';
13-
svelteKitVersion: '1-next' | '1' | '2' | null;
9+
export type SvelteContext = (
10+
| ({
11+
svelteVersion: '3/4';
12+
} & {
13+
svelteFileType: '.svelte' | 'other';
14+
runes: null;
15+
})
16+
| ({
17+
svelteVersion: '5';
18+
} & (
19+
| {
20+
svelteFileType: '.svelte' | '.svelte.[js|ts]';
21+
/** If a user uses a parser other than `svelte-eslint-parser`, `undetermined` will be set. */
22+
runes: boolean | 'undetermined';
23+
}
24+
| {
25+
/** e.g. `foo.js` / `package.json` */
26+
svelteFileType: 'other';
27+
runes: null;
28+
}
29+
))
30+
| {
31+
/** For projects that do not use Svelte. */
32+
svelteVersion: null;
33+
svelteFileType: null;
34+
runes: null;
35+
}
36+
) & {
37+
svelteKitVersion: '1.0.0-next' | '1' | '2' | null;
1438
svelteKitFileType:
1539
| '+page.svelte'
1640
| '+page.js'
@@ -23,7 +47,7 @@ export type SvelteContext = {
2347
| null;
2448
};
2549

26-
function getSvelteFileType(filePath: string): SvelteContext['svelteFileType'] | null {
50+
function getSvelteFileType(filePath: string): NonNullable<SvelteContext['svelteFileType']> {
2751
if (filePath.endsWith('.svelte')) {
2852
return '.svelte';
2953
}
@@ -32,7 +56,7 @@ function getSvelteFileType(filePath: string): SvelteContext['svelteFileType'] |
3256
return '.svelte.[js|ts]';
3357
}
3458

35-
return null;
59+
return 'other';
3660
}
3761

3862
function getSvelteKitFileTypeFromFilePath(filePath: string): SvelteContext['svelteKitFileType'] {
@@ -112,6 +136,29 @@ function getSvelteKitContext(
112136
};
113137
}
114138

139+
function getSvelteVersion(filePath: string): SvelteContext['svelteVersion'] {
140+
// Hack: if it runs in browser, it regards as Svelte project.
141+
if (isRunInBrowser) return '5';
142+
try {
143+
const packageJsons = getPackageJsons(filePath);
144+
for (const packageJson of packageJsons) {
145+
const version = packageJson.dependencies?.svelte ?? packageJson.devDependencies?.svelte;
146+
if (typeof version !== 'string') {
147+
continue;
148+
}
149+
const major = version.split('.')[0];
150+
if (major === '3' || major === '4') {
151+
return '3/4';
152+
}
153+
return major as SvelteContext['svelteVersion'];
154+
}
155+
} catch {
156+
/** do nothing */
157+
}
158+
159+
return null;
160+
}
161+
115162
/**
116163
* Check givin file is under SvelteKit project.
117164
*
@@ -124,41 +171,28 @@ function getSvelteKitVersion(filePath: string): SvelteContext['svelteKitVersion'
124171
// Hack: if it runs in browser, it regards as SvelteKit project.
125172
if (isRunInBrowser) return '2';
126173
try {
127-
const packageJson = getPackageJson(filePath);
128-
if (!packageJson) return null;
129-
if (packageJson.name === 'eslint-plugin-svelte')
174+
const packageJsons = getPackageJsons(filePath);
175+
if (packageJsons.length === 0) return null;
176+
if (packageJsons[0].name === 'eslint-plugin-svelte') {
130177
// Hack: CI removes `@sveltejs/kit` and it returns false and test failed.
131-
// So always it returns true if it runs on the package.
178+
// So always it returns 2 if it runs on the package.
132179
return '2';
133-
134-
const version =
135-
packageJson.dependencies?.['@sveltejs/kit'] ?? packageJson.devDependencies?.['@sveltejs/kit'];
136-
if (typeof version !== 'string') {
137-
return null;
138180
}
139-
if (version.startsWith('1.0.0-next.')) {
140-
return '1-next';
141-
} else if (version.startsWith('1.')) {
142-
return '1';
143-
} else if (version.startsWith('2.')) {
144-
return '2';
181+
182+
for (const packageJson of packageJsons) {
183+
const version =
184+
packageJson.dependencies?.['@sveltejs/kit'] ??
185+
packageJson.devDependencies?.['@sveltejs/kit'];
186+
if (typeof version !== 'string') {
187+
return null;
188+
}
189+
return version.split('.')[0] as SvelteContext['svelteKitVersion'];
145190
}
146-
// If unknown version, it recognize as v2.
147-
return '2';
148191
} catch {
149-
return null;
192+
/** do nothing */
150193
}
151-
}
152194

153-
function getSvelteVersion(compilerVersion: string | undefined): SvelteContext['svelteVersion'] {
154-
if (compilerVersion == null) {
155-
return 'undetermined';
156-
}
157-
const version = parseInt(compilerVersion.split('.')[0], 10);
158-
if (version === 3 || version === 4) {
159-
return '3/4';
160-
}
161-
return String(version) as '5';
195+
return null;
162196
}
163197

164198
/**
@@ -168,22 +202,57 @@ function getSvelteVersion(compilerVersion: string | undefined): SvelteContext['s
168202
*/
169203
function getProjectRootDir(filePath: string): string | null {
170204
if (isRunInBrowser) return null;
171-
const packageJsonFilePath = getPackageJson(filePath)?.filePath;
205+
const packageJsons = getPackageJsons(filePath);
206+
if (packageJsons.length === 0) {
207+
return null;
208+
}
209+
const packageJsonFilePath = packageJsons[0].filePath;
172210
if (!packageJsonFilePath) return null;
173211
return path.dirname(path.resolve(packageJsonFilePath));
174212
}
175213

176214
export function getSvelteContext(context: RuleContext): SvelteContext | null {
177215
const { parserServices } = getSourceCode(context);
178216
const { svelteParseContext } = parserServices;
179-
const compilerVersion = svelteParseContext?.compilerVersion;
180217
const filePath = getFilename(context);
181218
const svelteKitContext = getSvelteKitContext(context);
219+
const svelteVersion = getSvelteVersion(filePath);
220+
const svelteFileType = getSvelteFileType(filePath);
221+
222+
if (svelteVersion == null) {
223+
return {
224+
svelteVersion: null,
225+
svelteFileType: null,
226+
runes: null,
227+
svelteKitVersion: svelteKitContext.svelteKitVersion,
228+
svelteKitFileType: svelteKitContext.svelteKitFileType
229+
};
230+
}
231+
232+
if (svelteFileType === 'other') {
233+
return {
234+
svelteVersion,
235+
svelteFileType,
236+
runes: null,
237+
svelteKitVersion: svelteKitContext.svelteKitVersion,
238+
svelteKitFileType: svelteKitContext.svelteKitFileType
239+
};
240+
}
241+
242+
if (svelteVersion === '3/4') {
243+
return {
244+
svelteVersion,
245+
svelteFileType: svelteFileType === '.svelte' ? '.svelte' : 'other',
246+
runes: null,
247+
svelteKitVersion: svelteKitContext.svelteKitVersion,
248+
svelteKitFileType: svelteKitContext.svelteKitFileType
249+
};
250+
}
182251

183252
return {
184-
svelteVersion: getSvelteVersion(compilerVersion),
253+
svelteVersion,
185254
runes: svelteParseContext?.runes ?? 'undetermined',
186-
svelteFileType: getSvelteFileType(filePath),
255+
svelteFileType,
187256
svelteKitVersion: svelteKitContext.svelteKitVersion,
188257
svelteKitFileType: svelteKitContext.svelteKitFileType
189258
};

packages/eslint-plugin-svelte/tests/src/index.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { shouldRun } from '../../src/utils/index.js';
44
const actualSvelte3: Parameters<typeof shouldRun>[0] = {
55
svelteVersion: '3/4',
66
svelteFileType: '.svelte',
7-
runes: false,
7+
runes: null,
88
svelteKitVersion: null,
99
svelteKitFileType: null
1010
};

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