-
-
Notifications
You must be signed in to change notification settings - Fork 58
feat: add control for executing rules based on Svelte/SvelteKit context #980
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 4 commits
0b44be4
4ca476a
4fbe97d
cb70fea
910effd
ad3dfc3
f1a1cca
531911a
a36d935
bbfae0e
8a02534
0707e79
280ae67
afd422d
f686b4d
ae40057
4640ef5
d7b588f
0e28cc1
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,5 @@ | ||
--- | ||
'eslint-plugin-svelte': minor | ||
--- | ||
|
||
feat: Implement util to conditionally run lint based on Svelte version and SvelteKit routes etc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,182 @@ | ||
import type { RuleContext } from '../types.js'; | ||
import fs from 'fs'; | ||
import path from 'path'; | ||
import { getPackageJson } from './get-package-json.js'; | ||
import { getFilename, getSourceCode } from './compat.js'; | ||
|
||
const isRunOnBrowser = !fs.readFileSync; | ||
|
||
export type SvelteContext = { | ||
svelteVersion: string; | ||
fileType: '.svelte' | '.svelte.[js|ts]'; | ||
|
||
runes: boolean; | ||
svelteKitVersion: string | null; | ||
svelteKitFileType: | ||
| '+page.svelte' | ||
| '+page.js' | ||
| '+page.server.js' | ||
| '+error.svelte' | ||
| '+layout.svelte' | ||
| '+layout.js' | ||
| '+layout.server.js' | ||
| '+server.js' | ||
| null; | ||
}; | ||
|
||
function getFileType(filePath: string): SvelteContext['fileType'] | null { | ||
if (filePath.endsWith('.svelte')) { | ||
return '.svelte'; | ||
} | ||
|
||
if (filePath.endsWith('.svelte.js') || filePath.endsWith('.svelte.ts')) { | ||
return '.svelte.[js|ts]'; | ||
} | ||
|
||
return null; | ||
} | ||
|
||
function getSvelteKitFileTypeFromFilePath(filePath: string): SvelteContext['svelteKitFileType'] { | ||
const fileName = filePath.split('/').pop(); | ||
switch (fileName) { | ||
case '+page.svelte': { | ||
return '+page.svelte'; | ||
} | ||
case '+page.js': | ||
case '+page.ts': { | ||
return '+page.js'; | ||
} | ||
case '+page.server.js': | ||
case '+page.server.ts': { | ||
return '+page.server.js'; | ||
} | ||
case '+error.svelte': { | ||
return '+error.svelte'; | ||
} | ||
case '+layout.svelte': { | ||
return '+layout.svelte'; | ||
} | ||
case '+layout.js': | ||
case '+layout.ts': { | ||
return '+layout.js'; | ||
} | ||
case '+layout.server.js': | ||
case '+layout.server.ts': { | ||
return '+layout.server.js'; | ||
} | ||
case '+server.js': | ||
case '+server.ts': { | ||
return '+server.js'; | ||
} | ||
default: { | ||
return null; | ||
} | ||
} | ||
} | ||
|
||
function getSvelteKitContext( | ||
context: RuleContext | ||
): Pick<SvelteContext, 'svelteKitFileType' | 'svelteKitVersion'> { | ||
const filePath = getFilename(context); | ||
const svelteKitVersion = gteSvelteKitVersion(filePath); | ||
if (svelteKitVersion == null) { | ||
return { | ||
svelteKitFileType: null, | ||
svelteKitVersion: null | ||
}; | ||
} | ||
if (isRunOnBrowser) { | ||
return { | ||
svelteKitVersion, | ||
// Judge by only file path if it runs on browser. | ||
svelteKitFileType: getSvelteKitFileTypeFromFilePath(filePath) | ||
}; | ||
} | ||
|
||
const routes = | ||
( | ||
context.settings?.svelte?.kit?.files?.routes ?? | ||
getSourceCode(context).parserServices.svelteParseContext?.svelteConfig?.kit?.files?.routes | ||
)?.replace(/^\//, '') ?? 'src/routes'; | ||
const projectRootDir = getProjectRootDir(getFilename(context)) ?? ''; | ||
|
||
if (!filePath.startsWith(path.join(projectRootDir, routes))) { | ||
return { | ||
svelteKitVersion, | ||
svelteKitFileType: null | ||
}; | ||
} | ||
|
||
return { | ||
svelteKitVersion, | ||
svelteKitFileType: getSvelteKitFileTypeFromFilePath(filePath) | ||
}; | ||
} | ||
|
||
/** | ||
* Check givin file is under SvelteKit project. | ||
* | ||
* If it runs on browser, it always returns true. | ||
* | ||
* @param filePath A file path. | ||
* @returns | ||
*/ | ||
function gteSvelteKitVersion(filePath: string): string | null { | ||
baseballyama marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
// Hack: if it runs on browser, it regards as SvelteKit project. | ||
if (isRunOnBrowser) return '2.15.1'; | ||
baseballyama marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
try { | ||
const packageJson = getPackageJson(filePath); | ||
if (!packageJson) return null; | ||
if (packageJson.name === 'eslint-plugin-svelte') | ||
// Hack: CI removes `@sveltejs/kit` and it returns false and test failed. | ||
// So always it returns true if it runs on the package. | ||
return '2.15.1'; | ||
|
||
const version = | ||
packageJson.dependencies?.['@sveltejs/kit'] ?? packageJson.devDependencies?.['@sveltejs/kit']; | ||
return typeof version === 'string' ? version : null; | ||
} catch { | ||
return null; | ||
} | ||
} | ||
|
||
/** | ||
* Gets a project root folder path. | ||
* @param filePath A file path to lookup. | ||
* @returns A found project root folder path or null. | ||
*/ | ||
function getProjectRootDir(filePath: string): string | null { | ||
if (isRunOnBrowser) return null; | ||
const packageJsonFilePath = getPackageJson(filePath)?.filePath; | ||
if (!packageJsonFilePath) return null; | ||
return path.dirname(path.resolve(packageJsonFilePath)); | ||
} | ||
|
||
export function getSvelteContext(context: RuleContext): SvelteContext | null { | ||
const { parserServices } = getSourceCode(context); | ||
const { svelteParseContext } = parserServices; | ||
if (svelteParseContext === undefined) { | ||
return null; | ||
} | ||
|
||
const { compilerVersion } = svelteParseContext; | ||
if (compilerVersion === undefined) { | ||
return null; | ||
} | ||
|
||
const filePath = getFilename(context); | ||
const svelteKitContext = getSvelteKitContext(context); | ||
|
||
const runes = svelteParseContext.runes === true; | ||
const fileType = getFileType(filePath); | ||
if (fileType === null) { | ||
return null; | ||
} | ||
|
||
return { | ||
svelteVersion: compilerVersion, | ||
runes, | ||
fileType, | ||
svelteKitVersion: svelteKitContext.svelteKitVersion, | ||
svelteKitFileType: svelteKitContext.svelteKitFileType | ||
}; | ||
} |
Uh oh!
There was an error while loading. Please reload this page.