Skip to content

feat: improve svelte/valid-prop-names-in-kit-pages and svelte/no-export-load-in-svelte-module-in-kit-pages to use svelte.config.js data #794

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

Merged
merged 1 commit into from
Jun 17, 2024
Merged
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
5 changes: 5 additions & 0 deletions .changeset/silent-lamps-chew.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-svelte': minor
---

feat: improve `svelte/valid-prop-names-in-kit-pages` to use `svelte.config.js` data from the parser.
5 changes: 5 additions & 0 deletions .changeset/silent-lamps-chew2.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'eslint-plugin-svelte': minor
---

feat: improve `svelte/no-export-load-in-svelte-module-in-kit-pages` to use `svelte.config.js` data from the parser.
36 changes: 36 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -229,6 +229,36 @@ for some context.

:::

#### Specify `svelte.config.js`

If you are using `eslint.config.js`, we recommend that you import and specify `svelte.config.js`.
By specifying it, some rules of `eslint-plugin-svelte` will read it and try to behave well for you by default.
Some Svelte configurations will be statically loaded from `svelte.config.js` even if you don't specify it, but you need to specify it to make it work better.

Example **eslint.config.js**:

```js
import eslintPluginSvelte from 'eslint-plugin-svelte';
import svelteConfig from './svelte.config.js';
export default [
...eslintPluginSvelte.configs['flat/recommended'],
{
files: [
'**/*.svelte',
'*.svelte'
// Add more files if you need.
// '**/*.svelte.ts', '*.svelte.ts', '**/*.svelte.js', '*.svelte.js',
],
languageOptions: {
parserOptions: {
// Specify the `svelte.config.js`.
svelteConfig
}
}
}
];
```

#### settings.svelte

You can change the behavior of this plugin with some settings.
Expand Down Expand Up @@ -274,6 +304,12 @@ Specifies options for Svelte compile. Effects rules that use Svelte compile. The

#### settings.svelte.kit

::: warning

Even if you don't specify `settings.svelte.kit`, the rules will try to load information from `svelte.config.js`, so specify `settings.svelte.kit` if the default doesn't work.

:::

If you use SvelteKit with not default configuration, you need to set below configurations.
The schema is subset of SvelteKit's configuration.
Therefore please check [SvelteKit docs](https://kit.svelte.dev/docs/configuration) for more details.
Expand Down
36 changes: 36 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -180,6 +180,36 @@ for some context.

:::

#### Specify `svelte.config.js`

If you are using `eslint.config.js`, we recommend that you import and specify `svelte.config.js`.
By specifying it, some rules of `eslint-plugin-svelte` will read it and try to behave well for you by default.
Some Svelte configurations will be statically loaded from `svelte.config.js` even if you don't specify it, but you need to specify it to make it work better.

Example **eslint.config.js**:

```js
import eslintPluginSvelte from 'eslint-plugin-svelte';
import svelteConfig from './svelte.config.js';
export default [
...eslintPluginSvelte.configs['flat/recommended'],
{
files: [
'**/*.svelte',
'*.svelte'
// Add more files if you need.
// '**/*.svelte.ts', '*.svelte.ts', '**/*.svelte.js', '*.svelte.js',
],
languageOptions: {
parserOptions: {
// Specify the `svelte.config.js`.
svelteConfig
}
}
}
];
```

#### settings.svelte

You can change the behavior of this plugin with some settings.
Expand Down Expand Up @@ -225,6 +255,12 @@ Specifies options for Svelte compile. Effects rules that use Svelte compile. The

#### settings.svelte.kit

::: warning

Even if you don't specify `settings.svelte.kit`, the rules will try to load information from `svelte.config.js`, so specify `settings.svelte.kit` if the default doesn't work.

:::

If you use SvelteKit with not default configuration, you need to set below configurations.
The schema is subset of SvelteKit's configuration.
Therefore please check [SvelteKit docs](https://kit.svelte.dev/docs/configuration) for more details.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,12 @@ export default createRule('no-unused-class-name', {
}
},
'Program:exit'() {
const styleContext = sourceCode.parserServices.getStyleContext();
if (['parse-error', 'unknown-lang'].includes(styleContext.status)) {
const styleContext = sourceCode.parserServices.getStyleContext!();
if (styleContext.status === 'parse-error' || styleContext.status === 'unknown-lang') {
return;
}
const classesUsedInStyle =
styleContext.sourceAst != null ? findClassesInPostCSSNode(styleContext.sourceAst) : [];
styleContext.status === 'success' ? findClassesInPostCSSNode(styleContext.sourceAst) : [];
for (const className in classesUsedInTemplate) {
if (!allowedClassNames.includes(className) && !classesUsedInStyle.includes(className)) {
context.report({
Expand Down
27 changes: 25 additions & 2 deletions packages/eslint-plugin-svelte/src/types.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import type { JSONSchema4 } from 'json-schema';
import type { Linter, Rule, SourceCode as ESLintSourceCode } from 'eslint';
import type { AST } from 'svelte-eslint-parser';
import type { AST, StyleContext, SvelteConfig } from 'svelte-eslint-parser';
import type { TSESTree } from '@typescript-eslint/types';
import type { ScopeManager, Scope, Variable } from '@typescript-eslint/scope-manager';
import type { ASTNode, ASTNodeWithParent, ASTNodeListener } from './types-for-node';
import type * as TS from 'typescript';

export type { ASTNode, ASTNodeWithParent, ASTNodeListener };
export interface RuleListener extends ASTNodeListener {
Expand Down Expand Up @@ -201,7 +202,29 @@ export interface SourceCode {
ast: AST.SvelteProgram;
lines: string[];
hasBOM: boolean;
parserServices: ESLintSourceCode.ParserServices;
parserServices: {
isSvelte?: boolean;
isSvelteScript?: boolean;
getSvelteHtmlAst?: () => unknown;
getStyleContext?: () => StyleContext;
svelteParseContext?: {
/**
* Whether to use Runes mode.
* May be `true` if the user is using Svelte v5.
* Resolved from `svelte.config.js` or `parserOptions`, but may be overridden by `<svelte:options>`.
*/
runes?: boolean;
/** The version of "svelte/compiler". */
compilerVersion?: string;
/** The result of static analysis of `svelte.config.js`. */
svelteConfig?: SvelteConfig | null;
};
program?: TS.Program;
esTreeNodeToTSNodeMap?: ReadonlyMap<unknown, TS.Node>;
tsNodeToESTreeNodeMap?: ReadonlyMap<TS.Node, ASTNode>;
hasFullTypeInformation?: boolean; // Old typescript-eslint
[key: string]: unknown;
};
scopeManager: ScopeManager;
visitorKeys: ESLintSourceCode.VisitorKeys;

Expand Down
8 changes: 6 additions & 2 deletions packages/eslint-plugin-svelte/src/utils/svelte-kit.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import type { RuleContext } from '../types';
import fs from 'fs';
import path from 'path';
import { getPackageJson } from './get-package-json';
import { getFilename } from './compat';
import { getFilename, getSourceCode } from './compat';

const isRunOnBrowser = !fs.readFileSync;

Expand All @@ -19,7 +19,11 @@ export function isKitPageComponent(context: RuleContext): boolean {
// Hack: if it runs on browser, it regards as SvelteKit project.
if (isRunOnBrowser) return true;
if (!hasSvelteKit(getFilename(context))) return false;
const routes = context.settings?.svelte?.kit?.files?.routes?.replace(/^\//, '') ?? 'src/routes';
const routes =
(
context.settings?.svelte?.kit?.files?.routes ??
getSourceCode(context).parserServices.svelteParseContext?.svelteConfig?.kit?.files?.routes
)?.replace(/^\//, '') ?? 'src/routes';
const filePath = getFilename(context);
const projectRootDir = getProjectRootDir(getFilename(context)) ?? '';
const fileName = path.basename(filePath);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- message: disallow exporting load functions in `*.svelte` module in SvelteKit
page components.
line: 2
column: 18
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
export function load() {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"languageOptions": {
"parserOptions": {
"svelteConfig": {
"kit": {
"files": {
"routes": "tests/fixtures/rules/no-export-load-in-svelte-module-in-kit-pages/invalid/svelte-config-from-parser-options"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
- message: disallow exporting load functions in `*.svelte` module in SvelteKit
page components.
line: 2
column: 18
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
export function load() {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default {
kit: {
files: {
routes:
'tests/fixtures/rules/no-export-load-in-svelte-module-in-kit-pages/invalid/svelte-config'
}
}
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- message: disallow props other than data or errors in SvelteKit page components.
line: 2
column: 13
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 3
column: 13
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 4
column: 15
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 4
column: 20
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 5
column: 21
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 5
column: 36
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
export let foo;
export let bar;
export let { baz, qux } = data;
export let { data: data2, errors: errors2 } = { data: {}, errors: {} };
</script>

{foo}, {bar}
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
{
"languageOptions": {
"parserOptions": {
"svelteConfig": {
"kit": {
"files": {
"routes": "tests/fixtures/rules/valid-prop-names-in-kit-pages/invalid/svelte-config-from-parser-options"
}
}
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
- message: disallow props other than data or errors in SvelteKit page components.
line: 2
column: 13
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 3
column: 13
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 4
column: 15
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 4
column: 20
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 5
column: 21
suggestions: null
- message: disallow props other than data or errors in SvelteKit page components.
line: 5
column: 36
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
<script>
export let foo;
export let bar;
export let { baz, qux } = data;
export let { data: data2, errors: errors2 } = { data: {}, errors: {} };
</script>

{foo}, {bar}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
export default {
kit: {
files: {
routes: 'tests/fixtures/rules/valid-prop-names-in-kit-pages/invalid/svelte-config'
}
}
};
Loading