Skip to content

feat: add svelte/no-svelte-internal rule #749

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 8 commits into from
May 9, 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/chilly-bats-allow.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"eslint-plugin-svelte": minor
---

feat: add `svelte/no-svelte-internal` rule
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -385,6 +385,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [svelte/no-inline-styles](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inline-styles/) | disallow attributes and directives that produce inline styles | |
| [svelte/no-reactive-functions](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-reactive-functions/) | it's not necessary to define functions in reactive statements | :bulb: |
| [svelte/no-reactive-literals](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-reactive-literals/) | don't assign literal values in reactive statements | :bulb: |
| [svelte/no-svelte-internal](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-svelte-internal/) | svelte/internal will be removed in Svelte 6. | |
| [svelte/no-unused-class-name](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unused-class-name/) | disallow the use of a class in the template without a corresponding style | |
| [svelte/no-unused-svelte-ignore](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-useless-mustaches/) | disallow unnecessary mustache interpolations | :wrench: |
Expand Down
1 change: 1 addition & 0 deletions docs/rules.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ These rules relate to better ways of doing things to help you avoid problems:
| [svelte/no-inline-styles](./rules/no-inline-styles.md) | disallow attributes and directives that produce inline styles | |
| [svelte/no-reactive-functions](./rules/no-reactive-functions.md) | it's not necessary to define functions in reactive statements | :bulb: |
| [svelte/no-reactive-literals](./rules/no-reactive-literals.md) | don't assign literal values in reactive statements | :bulb: |
| [svelte/no-svelte-internal](./rules/no-svelte-internal.md) | svelte/internal will be removed in Svelte 6. | |
| [svelte/no-unused-class-name](./rules/no-unused-class-name.md) | disallow the use of a class in the template without a corresponding style | |
| [svelte/no-unused-svelte-ignore](./rules/no-unused-svelte-ignore.md) | disallow unused svelte-ignore comments | :star: |
| [svelte/no-useless-mustaches](./rules/no-useless-mustaches.md) | disallow unnecessary mustache interpolations | :wrench: |
Expand Down
55 changes: 55 additions & 0 deletions docs/rules/no-svelte-internal.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
pageClass: 'rule-details'
sidebarDepth: 0
title: 'svelte/no-svelte-internal'
description: 'svelte/internal will be removed in Svelte 6.'
---

# svelte/no-svelte-internal

> svelte/internal will be removed in Svelte 6.

- :exclamation: <badge text="This rule has not been released yet." vertical="middle" type="error"> **_This rule has not been released yet._** </badge>

## :book: Rule Details

This rule reports the use of the deprecated API `svelte/internal` and `svelte/internal/xxx`. `svelte/internal` is deprecated in Svelte 5. And it will be deleted in Svelte 6. These APIs can change in breaking ways at any time without notice.

<ESLintCodeBlock>

<!--eslint-skip-->

```svelte
<script>
/* eslint svelte/no-svelte-internal: "error" */
// ✓ GOOD
import { mount } from 'svelte';

// ✗ BAD
import { get_current_component } from 'svelte/internal';
import { inspect } from 'svelte/internal/client';
import('svelte/internal');
import('svelte/internal/disclose-version');

export * from 'svelte/internal';
export { listen } from 'svelte/internal';
export * from 'svelte/internal/server';
</script>
```

</ESLintCodeBlock>

## :wrench: Options

Nothing.

## :books: Further Reading

<!--TODO: update here when relevant statements are added in Svelte 5 documentation -->

Nothing.

## :mag: Implementation

- [Rule source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/src/rules/no-svelte-internal.ts)
- [Test source](https://github.com/sveltejs/eslint-plugin-svelte/blob/main/tests/src/rules/no-svelte-internal.ts)
5 changes: 5 additions & 0 deletions src/rule-types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,11 @@ export interface RuleOptions {
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-store-async/
*/
'svelte/no-store-async'?: Linter.RuleEntry<[]>
/**
* svelte/internal will be removed in Svelte 6.
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-svelte-internal/
*/
'svelte/no-svelte-internal'?: Linter.RuleEntry<[]>
/**
* disallow `target="_blank"` attribute without `rel="noopener noreferrer"`
* @see https://sveltejs.github.io/eslint-plugin-svelte/rules/no-target-blank/
Expand Down
59 changes: 59 additions & 0 deletions src/rules/no-svelte-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
import { createRule } from '../utils';
import type { TSESTree } from '@typescript-eslint/types';

export default createRule('no-svelte-internal', {
meta: {
docs: {
description: 'svelte/internal will be removed in Svelte 6.',
category: 'Best Practices',
// TODO Switch to recommended in the major version.

Check warning on line 9 in src/rules/no-svelte-internal.ts

View workflow job for this annotation

GitHub Actions / lint

Unexpected 'todo' comment: 'TODO Switch to recommended in the major...'
// recommended: true,
recommended: false
},
schema: [],
messages: {
unexpected: 'Using svelte/internal is prohibited. This will be removed in Svelte 6.'
},
type: 'problem'
},
create(context) {
function report(node: TSESTree.Node) {
context.report({
node,
messageId: 'unexpected'
});
}

function isSvelteInternal(value: string) {
return value === 'svelte/internal' || value.startsWith('svelte/internal/');
}

return {
ImportDeclaration(node) {
Copy link
Member

Choose a reason for hiding this comment

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

We should probably also check export * from 'svelte/internal'.

Copy link
Member

@ota-meshi ota-meshi May 9, 2024

Choose a reason for hiding this comment

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

I don't expect anyone to do that, but I think it would be even better if we also check import('svelte/internal').

Copy link
Member Author

Choose a reason for hiding this comment

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

Good! updated: fca148a

if (node.source && isSvelteInternal(node.source.value)) {
report(node);
}
},
ImportExpression(node) {
if (
node.source &&
node.source.type === 'Literal' &&
typeof node.source.value === 'string' &&
isSvelteInternal(node.source.value)
) {
report(node);
}
},
ExportNamedDeclaration(node) {
if (node.source && isSvelteInternal(node.source.value)) {
report(node);
}
},
ExportAllDeclaration(node) {
if (node.source && isSvelteInternal(node.source.value)) {
report(node);
}
}
};
}
});
2 changes: 2 additions & 0 deletions src/utils/rules.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ import noRestrictedHtmlElements from '../rules/no-restricted-html-elements';
import noShorthandStylePropertyOverrides from '../rules/no-shorthand-style-property-overrides';
import noSpacesAroundEqualSignsInAttribute from '../rules/no-spaces-around-equal-signs-in-attribute';
import noStoreAsync from '../rules/no-store-async';
import noSvelteInternal from '../rules/no-svelte-internal';
import noTargetBlank from '../rules/no-target-blank';
import noTrailingSpaces from '../rules/no-trailing-spaces';
import noUnknownStyleDirectiveProperty from '../rules/no-unknown-style-directive-property';
Expand Down Expand Up @@ -105,6 +106,7 @@ export const rules = [
noShorthandStylePropertyOverrides,
noSpacesAroundEqualSignsInAttribute,
noStoreAsync,
noSvelteInternal,
noTargetBlank,
noTrailingSpaces,
noUnknownStyleDirectiveProperty,
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 3
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<script>
// eslint-disable-next-line camelcase -- this is a test
import { get_current_component } from 'svelte/internal';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
import { inspect } from 'svelte/internal/client';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
import * as svelteInternal from 'svelte/internal';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
export * from 'svelte/internal';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
export * from 'svelte/internal/client';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
export { inspect } from 'svelte/internal/client';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
- message: Using svelte/internal is prohibited. This will be removed in Svelte 6.
line: 2
column: 2
suggestions: null
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
import('svelte/internal');
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
<script>
import { mount } from 'svelte';
</script>
12 changes: 12 additions & 0 deletions tests/src/rules/no-svelte-internal.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import { RuleTester } from '../../utils/eslint-compat';
import rule from '../../../src/rules/no-svelte-internal';
import { loadTestCases } from '../../utils/utils';

const tester = new RuleTester({
languageOptions: {
ecmaVersion: 2020,
sourceType: 'module'
}
});

tester.run('no-svelte-internal', rule as any, loadTestCases('no-svelte-internal'));
Loading