Skip to content

feat: add no-export-load-in-svelte-module-in-kit-pages #281

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
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
bdd3580
feat: add no-export-load-in-svelte-module-in-kit-pages
baseballyama Oct 29, 2022
ab5e4d2
chore: add changeset
baseballyama Oct 29, 2022
c92a052
chore: add test
baseballyama Oct 29, 2022
07dbc08
fix: check devDependencies also
baseballyama Oct 29, 2022
08fc369
fix: adjust for test
baseballyama Oct 29, 2022
4cf5a14
feat: add config
baseballyama Oct 29, 2022
f8de8bc
chore: fix typo
baseballyama Oct 29, 2022
203bf8e
fix: bug
baseballyama Oct 30, 2022
a9fb99d
fix: bug
baseballyama Oct 30, 2022
59d3097
chore: uupdate docus
baseballyama Oct 30, 2022
4fc4c22
chore: update docs
baseballyama Oct 30, 2022
332c4bc
chore: add kit helper
baseballyama Oct 30, 2022
d5bdacd
fix: fix for demo
baseballyama Oct 30, 2022
f321a12
chore: adjust doc style
baseballyama Oct 30, 2022
dc451d3
Merge branch 'main' into feature/no-export-load-in-svelte-module-in-k…
baseballyama Oct 31, 2022
d0d21e7
chore: revert .eslintrc.js
baseballyama Oct 31, 2022
38c2690
chore: update uppercase -> lowercase
baseballyama Oct 31, 2022
2eb81df
fix: update recommended
baseballyama Oct 31, 2022
3137c67
fix: i did not know :exit
baseballyama Oct 31, 2022
5353b32
fix: project root path finding logic
baseballyama Oct 31, 2022
d68a1cf
chore: utilize
baseballyama Oct 31, 2022
20ad311
chore: yarn update
baseballyama Oct 31, 2022
7584b10
fix: remove needless logic
baseballyama Oct 31, 2022
cfaf58c
chore: simplify
baseballyama Oct 31, 2022
a903027
fix: false positive
baseballyama Nov 1, 2022
7d870c0
Merge branch 'main' into feature/no-export-load-in-svelte-module-in-k…
ota-meshi Nov 1, 2022
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/orange-months-sparkle.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

feat: add `no-export-load-in-svelte-module-in-kit-pages` rule
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -216,6 +216,28 @@ module.exports = {
}
```

#### settings.kit

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.

e.g.

```js
module.exports = {
// ...
settings: {
kit: {
files: {
routes: "src/routes",
},
},
},
// ...
}
Comment on lines +228 to +238
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I choose that I added shared configuration for kit routes path.
I think over 95% of users use default settings src/routes.
So only a few users need to config it.

And for 5% users, we discussed that we will use espree but it may fail to get the path if they rely to env of some external information. So for now I didn't implement this logic.
#241 (comment)

```

### Running ESLint from the command line

If you want to run `eslint` from the command line, make sure you include the `.svelte` extension using [the `--ext` option](https://eslint.org/docs/user-guide/configuring#specifying-file-extensions-to-lint) or a glob pattern, because ESLint targets only `.js` files by default.
Expand Down Expand Up @@ -266,6 +288,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-dupe-else-if-blocks](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
| [svelte/no-dupe-style-properties](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dupe-style-properties/) | disallow duplicate style properties | :star: |
| [svelte/no-dynamic-slot-name](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-dynamic-slot-name/) | disallow dynamic slot name | :star::wrench: |
| [svelte/no-export-load-in-svelte-module-in-kit-pages](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-export-load-in-svelte-module-in-kit-pages/) | Disallow exporting load functions in `*.svelte` module in Svelte Kit page components. | :star: |
| [svelte/no-not-function-handler](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-not-function-handler/) | disallow use of not function in event handler | :star: |
| [svelte/no-object-in-text-mustaches](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-object-in-text-mustaches/) | disallow objects in text mustache interpolation | :star: |
| [svelte/no-shorthand-style-property-overrides](https://ota-meshi.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ These rules relate to possible syntax or logic errors in Svelte code:
| [svelte/no-dupe-else-if-blocks](./rules/no-dupe-else-if-blocks.md) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
| [svelte/no-dupe-style-properties](./rules/no-dupe-style-properties.md) | disallow duplicate style properties | :star: |
| [svelte/no-dynamic-slot-name](./rules/no-dynamic-slot-name.md) | disallow dynamic slot name | :star::wrench: |
| [svelte/no-export-load-in-svelte-module-in-kit-pages](./rules/no-export-load-in-svelte-module-in-kit-pages.md) | Disallow exporting load functions in `*.svelte` module in Svelte Kit page components. | :star: |
| [svelte/no-not-function-handler](./rules/no-not-function-handler.md) | disallow use of not function in event handler | :star: |
| [svelte/no-object-in-text-mustaches](./rules/no-object-in-text-mustaches.md) | disallow objects in text mustache interpolation | :star: |
| [svelte/no-shorthand-style-property-overrides](./rules/no-shorthand-style-property-overrides.md) | disallow shorthand style properties that override related longhand properties | :star: |
Expand Down
49 changes: 49 additions & 0 deletions docs/rules/no-export-load-in-svelte-module-in-kit-pages.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
---
pageClass: "rule-details"
sidebarDepth: 0
title: "svelte/no-export-load-in-svelte-module-in-kit-pages"
description: "Disallow exporting load functions in `*.svelte` module in Svelte Kit page components."
---

# svelte/no-export-load-in-svelte-module-in-kit-pages

> Disallow exporting load functions in `*.svelte` module in Svelte Kit page components.

- :gear: This rule is included in `"plugin:svelte/recommended"`.

## :book: Rule Details

This rule reports unexpected exported `load` function at `<script context="module">`.
At SvelteKit v1.0.0-next.405, `load` function has been moved into a separate file — `+page.js` for pages, `+layout.js` for layouts.
And the API has changed.

<ESLintCodeBlock>

<!--eslint-skip-->

```svelte
<script context="module">
/* eslint svelte/no-export-load-in-svelte-module-in-kit-pages: "error" */
/* ✓ GOOD */
export function foo() {}
export function bar() {}
/* ✗ BAD */
export function load() {}
// export const load = () => {}
</script>
```

</ESLintCodeBlock>

## :wrench: Options

Nothing. But if use are using not default routes folder, please set configuration according to the [user guide](../user-guide.md#settings-kit).

## :books: Further Reading

- [SvelteKit Migration Guide (v1.0.0-next.405)](https://github.com/sveltejs/kit/discussions/5774#discussioncomment-3292693)

## :mag: Implementation

- [Rule source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/src/rules/no-export-load-in-svelte-module-in-kit-pages.ts)
- [Test source](https://github.com/ota-meshi/eslint-plugin-svelte/blob/main/tests/src/rules/no-export-load-in-svelte-module-in-kit-pages.ts)
22 changes: 22 additions & 0 deletions docs/user-guide.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,6 +168,28 @@ module.exports = {
}
```

#### settings.kit

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.

e.g.

```js
module.exports = {
// ...
settings: {
kit: {
files: {
routes: "src/routes",
},
},
},
// ...
}
```

### Running ESLint from the command line

If you want to run `eslint` from the command line, make sure you include the `.svelte` extension using [the `--ext` option](https://eslint.org/docs/user-guide/configuring#specifying-file-extensions-to-lint) or a glob pattern, because ESLint targets only `.js` files by default.
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@
"access": "public"
},
"typeCoverage": {
"atLeast": 98.71,
"atLeast": 98.69,
"cache": true,
"detail": true,
"ignoreAsAssertion": true,
Expand Down
1 change: 1 addition & 0 deletions src/configs/recommended.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ export = {
"svelte/no-dupe-else-if-blocks": "error",
"svelte/no-dupe-style-properties": "error",
"svelte/no-dynamic-slot-name": "error",
"svelte/no-export-load-in-svelte-module-in-kit-pages": "error",
"svelte/no-inner-declarations": "error",
"svelte/no-not-function-handler": "error",
"svelte/no-object-in-text-mustaches": "error",
Expand Down
80 changes: 80 additions & 0 deletions src/rules/no-export-load-in-svelte-module-in-kit-pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import type * as ESTree from "estree"
import { createRule } from "../utils"
import fs from "fs"

const hasSvelteKit = (() => {
try {
const packageJson = JSON.parse(fs.readFileSync("./package.json", "utf8"))
// Hack: CI removes `@sveltejs/kit` and it returns false and test failed.
// So always it returns true if it runs on the package.
if (packageJson.name === "eslint-plugin-svelte") return true
return Boolean(
packageJson.dependencies["@sveltejs/kit"] ??
packageJson.devDependencies["@sveltejs/kit"],
)
} catch (_e) {
return false
}
})()
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a user doesn't use SvelteKit, I don't want to show an error, so I added to check package.json.
Is it the correct way?
And in the CI removes SvelteKit, so for the test, I added chack logic with packageJson.name
I think this is a bad idea but I don't have a better idea.

If correct, I will move it to utils for other SvelteKit-related rules.


export default createRule("no-export-load-in-svelte-module-in-kit-pages", {
meta: {
docs: {
description:
"Disallow exporting load functions in `*.svelte` module in Svelte Kit page components.",
category: "Possible Errors",
recommended: true,
},
schema: [],
messages: {
unexpected:
"Disallow exporting load functions in `*.svelte` module in Svelte Kit page components.",
},
type: "problem",
},
create(context) {
if (!hasSvelteKit) return {}
let isModule = false

// return false if it's not a Svelte Kit page component.
const routes =
context.settings?.kit?.files?.routes?.replace(/^\//, "") || "src/routes"

const filePath = context
.getFilename()
.replace(context.getCwd?.() ?? "", "")
.replace(/^\//, "")
if (!filePath.startsWith(routes)) return {}

return {
// <script context="module">
[`Program > SvelteScriptElement > SvelteStartTag > SvelteAttribute > SvelteLiteral[value="module"]`]:
() => {
isModule = true
},

// <script>
[`Program > SvelteScriptElement > SvelteStartTag > SvelteAttribute > SvelteLiteral[value!="module"]`]:
() => {
isModule = false
},

// </script>
["SvelteEndTag"]: () => {
isModule = false
},

// export function load() {}
// export const load = () => {}
[`ExportNamedDeclaration :matches(FunctionDeclaration, VariableDeclaration > VariableDeclarator) > Identifier[name="load"]`]:
(node: ESTree.Identifier) => {
if (!isModule) return {}
return context.report({
node,
loc: node.loc!,
messageId: "unexpected",
})
},
}
},
})
5 changes: 5 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,11 @@ export type RuleContext = {
postcss?: false | { configFilePath?: unknown }
}
}
["kit"]?: {
files?: {
routes?: string
}
}
}
parserPath: string
parserOptions: Linter.ParserOptions
Expand Down
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ import noAtHtmlTags from "../rules/no-at-html-tags"
import noDupeElseIfBlocks from "../rules/no-dupe-else-if-blocks"
import noDupeStyleProperties from "../rules/no-dupe-style-properties"
import noDynamicSlotName from "../rules/no-dynamic-slot-name"
import noExportLoadInSvelteModuleInKitPages from "../rules/no-export-load-in-svelte-module-in-kit-pages"
import noExtraReactiveCurlies from "../rules/no-extra-reactive-curlies"
import noInnerDeclarations from "../rules/no-inner-declarations"
import noNotFunctionHandler from "../rules/no-not-function-handler"
Expand Down Expand Up @@ -58,6 +59,7 @@ export const rules = [
noDupeElseIfBlocks,
noDupeStyleProperties,
noDynamicSlotName,
noExportLoadInSvelteModuleInKitPages,
noExtraReactiveCurlies,
noInnerDeclarations,
noNotFunctionHandler,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- message: Disallow self-closing on HTML elements.
line: 3
column: 3
suggestions: null
- message: Require self-closing on HTML void elements.
line: 4
column: 3
suggestions: null
- message: Disallow self-closing on Svelte custom components.
line: 5
column: 3
suggestions: null
- message: Require self-closing on Svelte special elements.
line: 8
column: 1
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
- message: Disallow self-closing on HTML elements.
line: 3
column: 3
suggestions: null
- message: Disallow self-closing on Svelte custom components.
line: 4
column: 3
suggestions: null
- message: Disallow self-closing on HTML void elements.
line: 5
column: 3
suggestions: null
- message: Disallow self-closing on Svelte special elements.
line: 8
column: 1
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"settings": {
"kit": {
"files": {
"routes": "tests/fixtures"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: "Disallow exporting load functions in `*.svelte` module in Svelte Kit page components."
line: 2
column: 19
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,4 @@
- message: "Disallow exporting load functions in `*.svelte` module in Svelte Kit page components."
line: 2
column: 16
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
export const load = () => {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"settings": {
"kit": {
"files": {
"routes": "tests/fixtures"
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"settings": {
"kit": {
"files": {
"routes": "some-path"
}
}
}
}
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,3 @@
<script context="module">
export const load = () => {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
export function load() {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
export const load = () => {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
function load() {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
const load = () => {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script context="module">
export function foo() {}
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
<script context="module">
export function foo() {}
</script>

<script>
export function load() {}
</script>
16 changes: 16 additions & 0 deletions tests/src/rules/no-export-load-in-svelte-module-in-kit-pages.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import { RuleTester } from "eslint"
import rule from "../../../src/rules/no-export-load-in-svelte-module-in-kit-pages"
import { loadTestCases } from "../../utils/utils"

const tester = new RuleTester({
parserOptions: {
ecmaVersion: 2020,
sourceType: "module",
},
})

tester.run(
"no-export-load-in-svelte-module-in-kit-pages",
rule as any,
loadTestCases("no-export-load-in-svelte-module-in-kit-pages"),
)