feat: docker compose maybe

This commit is contained in:
2023-11-13 16:10:04 -05:00
parent 180b261e40
commit b625ccd8d6
8031 changed files with 2182966 additions and 0 deletions

21
node_modules/eslint-plugin-svelte/LICENSE generated vendored Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2021 Yosuke Ota
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

443
node_modules/eslint-plugin-svelte/README.md generated vendored Normal file
View File

@ -0,0 +1,443 @@
# Introduction
`eslint-plugin-svelte` is the official [ESLint] plugin for [Svelte].
It provides many unique check rules by using the template AST.
You can check on the [Online DEMO](https://sveltejs.github.io/eslint-plugin-svelte/playground/).
[![NPM license](https://img.shields.io/npm/l/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
[![NPM version](https://img.shields.io/npm/v/eslint-plugin-svelte.svg)](https://www.npmjs.com/package/eslint-plugin-svelte)
[![NPM downloads](https://img.shields.io/badge/dynamic/json.svg?label=downloads&colorB=green&suffix=/day&query=$.downloads&uri=https://api.npmjs.org//downloads/point/last-day/eslint-plugin-svelte&maxAge=3600)](http://www.npmtrends.com/eslint-plugin-svelte)
[![NPM downloads](https://img.shields.io/npm/dw/eslint-plugin-svelte.svg)](http://www.npmtrends.com/eslint-plugin-svelte)
[![NPM downloads](https://img.shields.io/npm/dm/eslint-plugin-svelte.svg)](http://www.npmtrends.com/eslint-plugin-svelte)
[![NPM downloads](https://img.shields.io/npm/dy/eslint-plugin-svelte.svg)](http://www.npmtrends.com/eslint-plugin-svelte)
[![NPM downloads](https://img.shields.io/npm/dt/eslint-plugin-svelte.svg)](http://www.npmtrends.com/eslint-plugin-svelte)
[![Build Status](https://github.com/sveltejs/eslint-plugin-svelte/workflows/CI/badge.svg?branch=main)](https://github.com/sveltejs/eslint-plugin-svelte/actions?query=workflow%3ACI)
[![type-coverage](https://img.shields.io/badge/dynamic/json.svg?label=type-coverage&prefix=%E2%89%A5&suffix=%&query=$.typeCoverage.atLeast&uri=https%3A%2F%2Fraw.githubusercontent.com%2Fsveltejs%2Feslint-plugin-svelte%2Fmain%2Fpackage.json)](https://github.com/plantain-00/type-coverage)
[![Conventional Commits](https://img.shields.io/badge/conventional%20commits-1.0.0-yellow.svg)](https://conventionalcommits.org)
[![Code Style: Prettier](https://img.shields.io/badge/code_style-prettier-ff69b4.svg)](https://github.com/prettier/prettier)
[![changesets](https://img.shields.io/badge/maintained%20with-changesets-176de3.svg)](https://github.com/atlassian/changesets)
## :name_badge: What is this plugin?
[ESLint] plugin for [Svelte].
It provides many unique check rules using the AST generated by [svelte-eslint-parser].
### ❗ Attention
The [svelte-eslint-parser] and the `eslint-plugin-svelte` can not be used with the [eslint-plugin-svelte3].
[svelte-eslint-parser]: https://github.com/sveltejs/svelte-eslint-parser
[eslint-plugin-svelte3]: https://github.com/sveltejs/eslint-plugin-svelte3
<!--DOCS_IGNORE_START-->
## Migration Guide
To migrate from `eslint-plugin-svelte` v1, or [`@ota-meshi/eslint-plugin-svelte`](https://www.npmjs.com/package/@ota-meshi/eslint-plugin-svelte), please refer to the [migration guide](https://sveltejs.github.io/eslint-plugin-svelte/migration/).
## :book: Documentation
See [documents](https://sveltejs.github.io/eslint-plugin-svelte/).
## :cd: Installation
```bash
npm install --save-dev eslint eslint-plugin-svelte svelte
```
> **Requirements**
>
> - ESLint v7.0.0 and above
> - Node.js v14.17.x, v16.x and above
<!--DOCS_IGNORE_END-->
## :book: Usage
<!--USAGE_SECTION_START-->
<!--USAGE_GUIDE_START-->
### Configuration
Use `.eslintrc.*` file to configure rules. See also: <https://eslint.org/docs/user-guide/configuring>.
Example **.eslintrc.js**:
```js
module.exports = {
extends: [
// add more generic rule sets here, such as:
// 'eslint:recommended',
'plugin:svelte/recommended'
],
rules: {
// override/add rules settings here, such as:
// 'svelte/rule-name': 'error'
}
};
```
This plugin provides configs:
- `plugin:svelte/base` ... Configuration to enable correct Svelte parsing.
- `plugin:svelte/recommended` ... Above, plus rules to prevent errors or unintended behavior.
- `plugin:svelte/prettier` ... Turns off rules that may conflict with [Prettier](https://prettier.io/) (You still need to configure prettier to work with svelte yourself, for example by using [prettier-plugin-svelte](https://github.com/sveltejs/prettier-plugin-svelte).).
- `plugin:svelte/all` ... All rules. This configuration is not recommended for production use because it changes with every minor and major version of `eslint-plugin-svelte`. Use it at your own risk.
See [the rule list](https://sveltejs.github.io/eslint-plugin-svelte/rules/) to get the `rules` that this plugin provides.
::: warning ❗ Attention
The `eslint-plugin-svelte` can not be used with the [eslint-plugin-svelte3].
If you are using [eslint-plugin-svelte3] you need to remove it.
```diff
"plugins": [
- "svelte3"
]
```
:::
#### Parser Configuration
If you have specified a parser, you need to configure a parser for `.svelte`.
For example, if you are using the `"@babel/eslint-parser"`, configure it as follows:
```js
module.exports = {
// ...
extends: ['plugin:svelte/recommended'],
// ...
parser: '@babel/eslint-parser',
// Add an `overrides` section to add a parser configuration for svelte.
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser'
}
// ...
]
// ...
};
```
For example, if you are using the `"@typescript-eslint/parser"`, and if you want to use TypeScript in `<script>` of `.svelte`, you need to add more `parserOptions` configuration.
```js
module.exports = {
// ...
extends: ['plugin:svelte/recommended'],
// ...
parser: '@typescript-eslint/parser',
parserOptions: {
// ...
project: 'path/to/your/tsconfig.json',
extraFileExtensions: ['.svelte'] // This is a required setting in `@typescript-eslint/parser` v4.24.0.
},
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
// Parse the `<script>` in `.svelte` as TypeScript by adding the following configuration.
parserOptions: {
parser: '@typescript-eslint/parser'
}
}
// ...
]
// ...
};
```
If you have a mix of TypeScript and JavaScript in your project, use a multiple parser configuration.
```js
module.exports = {
// ...
overrides: [
{
files: ['*.svelte'],
parser: 'svelte-eslint-parser',
parserOptions: {
parser: {
// Specify a parser for each lang.
ts: '@typescript-eslint/parser',
js: 'espree',
typescript: '@typescript-eslint/parser'
}
}
}
// ...
]
// ...
};
```
See also <https://github.com/sveltejs/svelte-eslint-parser#readme>.
::: warning ❗ Attention
The TypeScript parser uses a singleton internally and it will only use the
options given to it when it was first initialized. If trying to change the
options for a different file or override, the parser will simply ignore the new
options (which may result in an error). See
[typescript-eslint/typescript-eslint#6778](https://github.com/typescript-eslint/typescript-eslint/issues/6778)
for some context.
:::
#### settings.svelte
You can change the behavior of this plugin with some settings.
e.g.
```js
module.exports = {
// ...
settings: {
svelte: {
ignoreWarnings: [
'@typescript-eslint/no-unsafe-assignment',
'@typescript-eslint/no-unsafe-member-access'
],
compileOptions: {
postcss: {
configFilePath: './path/to/my/postcss.config.js'
}
},
kit: {
files: {
routes: 'src/routes'
}
}
}
}
// ...
};
```
#### settings.svelte.ignoreWarnings
Specifies an array of rules that ignore reports in the template.
For example, set rules on the template that cannot avoid false positives.
#### settings.svelte.compileOptions
Specifies options for Svelte compile. Effects rules that use Svelte compile. The target rules are [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) and [svelte/no-unused-svelte-ignore](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unused-svelte-ignore/). **Note that it has no effect on ESLint's custom parser**.
- `postcss` ... Specifies options related to PostCSS. You can disable the PostCSS process by specifying `false`.
- `configFilePath` ... Specifies the path of the directory containing the PostCSS configuration.
#### settings.svelte.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: {
svelte: {
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.
Examples:
```bash
eslint --ext .js,.svelte src
eslint "src/**/*.{js,svelte}"
```
## :computer: Editor Integrations
### Visual Studio Code
Use the [dbaeumer.vscode-eslint](https://marketplace.visualstudio.com/items?itemName=dbaeumer.vscode-eslint) extension that Microsoft provides officially.
You have to configure the `eslint.validate` option of the extension to check `.svelte` files, because the extension targets only `*.js` or `*.jsx` files by default.
Example **.vscode/settings.json**:
```json
{
"eslint.validate": ["javascript", "javascriptreact", "svelte"]
}
```
<!--USAGE_GUIDE_END-->
<!--USAGE_SECTION_END-->
## :white_check_mark: Rules
<!-- prettier-ignore-start -->
<!--RULES_SECTION_START-->
:wrench: Indicates that the rule is fixable, and using `--fix` option on the [command line](https://eslint.org/docs/user-guide/command-line-interface#fixing-problems) can automatically fix some of the reported problems.
:bulb: Indicates that some problems reported by the rule are manually fixable by editor [suggestions](https://eslint.org/docs/developer-guide/working-with-rules#providing-suggestions).
:star: Indicates that the rule is included in the `plugin:svelte/recommended` config.
<!--RULES_TABLE_START-->
## Possible Errors
These rules relate to possible syntax or logic errors in Svelte code:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/infinite-reactive-loop](https://sveltejs.github.io/eslint-plugin-svelte/rules/infinite-reactive-loop/) | Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent. | |
| [svelte/no-dom-manipulating](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dom-manipulating/) | disallow DOM manipulating | |
| [svelte/no-dupe-else-if-blocks](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-else-if-blocks/) | disallow duplicate conditions in `{#if}` / `{:else if}` chains | :star: |
| [svelte/no-dupe-on-directives](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-on-directives/) | disallow duplicate `on:` directives | |
| [svelte/no-dupe-style-properties](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-style-properties/) | disallow duplicate style properties | :star: |
| [svelte/no-dupe-use-directives](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-dupe-use-directives/) | disallow duplicate `use:` directives | |
| [svelte/no-dynamic-slot-name](https://sveltejs.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://sveltejs.github.io/eslint-plugin-svelte/rules/no-export-load-in-svelte-module-in-kit-pages/) | disallow exporting load functions in `*.svelte` module in SvelteKit page components. | |
| [svelte/no-not-function-handler](https://sveltejs.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://sveltejs.github.io/eslint-plugin-svelte/rules/no-object-in-text-mustaches/) | disallow objects in text mustache interpolation | :star: |
| [svelte/no-reactive-reassign](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-reactive-reassign/) | disallow reassigning reactive values | |
| [svelte/no-shorthand-style-property-overrides](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-shorthand-style-property-overrides/) | disallow shorthand style properties that override related longhand properties | :star: |
| [svelte/no-store-async](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-store-async/) | disallow using async/await inside svelte stores because it causes issues with the auto-unsubscribing features | |
| [svelte/no-unknown-style-directive-property](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-unknown-style-directive-property/) | disallow unknown `style:property` | :star: |
| [svelte/require-store-callbacks-use-set-param](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-callbacks-use-set-param/) | store callbacks must use `set` param | |
| [svelte/require-store-reactive-access](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-store-reactive-access/) | disallow to use of the store itself as an operand. Need to use $ prefix or get function. | :wrench: |
| [svelte/valid-compile](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-compile/) | disallow warnings when compiling. | :star: |
| [svelte/valid-prop-names-in-kit-pages](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-prop-names-in-kit-pages/) | disallow props other than data or errors in SvelteKit page components. | |
## Security Vulnerability
These rules relate to security vulnerabilities in Svelte code:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/no-at-html-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-html-tags/) | disallow use of `{@html}` to prevent XSS attack | :star: |
| [svelte/no-target-blank](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-target-blank/) | disallow `target="_blank"` attribute without `rel="noopener noreferrer"` | |
## Best Practices
These rules relate to better ways of doing things to help you avoid problems:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/block-lang](https://sveltejs.github.io/eslint-plugin-svelte/rules/block-lang/) | disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks. | |
| [svelte/button-has-type](https://sveltejs.github.io/eslint-plugin-svelte/rules/button-has-type/) | disallow usage of button without an explicit type attribute | |
| [svelte/no-at-debug-tags](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-at-debug-tags/) | disallow the use of `{@debug}` | :star: |
| [svelte/no-ignored-unsubscribe](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-ignored-unsubscribe/) | disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores. | |
| [svelte/no-immutable-reactive-statements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-immutable-reactive-statements/) | disallow reactive statements that don't reference reactive values. | |
| [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-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: |
| [svelte/prefer-destructured-store-props](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-destructured-store-props/) | destructure values from object stores for better change tracking & fewer redraws | :bulb: |
| [svelte/require-each-key](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-each-key/) | require keyed `{#each}` block | |
| [svelte/require-event-dispatcher-types](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-event-dispatcher-types/) | require type parameters for `createEventDispatcher` | |
| [svelte/require-optimized-style-attribute](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-optimized-style-attribute/) | require style attributes that can be optimized | |
| [svelte/require-stores-init](https://sveltejs.github.io/eslint-plugin-svelte/rules/require-stores-init/) | require initial value in store | |
| [svelte/valid-each-key](https://sveltejs.github.io/eslint-plugin-svelte/rules/valid-each-key/) | enforce keys to use variables defined in the `{#each}` block | |
## Stylistic Issues
These rules relate to style guidelines, and are therefore quite subjective:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/derived-has-same-inputs-outputs](https://sveltejs.github.io/eslint-plugin-svelte/rules/derived-has-same-inputs-outputs/) | derived store should use same variable names between values and callback | |
| [svelte/first-attribute-linebreak](https://sveltejs.github.io/eslint-plugin-svelte/rules/first-attribute-linebreak/) | enforce the location of first attribute | :wrench: |
| [svelte/html-closing-bracket-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-closing-bracket-spacing/) | require or disallow a space before tag's closing brackets | :wrench: |
| [svelte/html-quotes](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-quotes/) | enforce quotes style of HTML attributes | :wrench: |
| [svelte/html-self-closing](https://sveltejs.github.io/eslint-plugin-svelte/rules/html-self-closing/) | enforce self-closing style | :wrench: |
| [svelte/indent](https://sveltejs.github.io/eslint-plugin-svelte/rules/indent/) | enforce consistent indentation | :wrench: |
| [svelte/max-attributes-per-line](https://sveltejs.github.io/eslint-plugin-svelte/rules/max-attributes-per-line/) | enforce the maximum number of attributes per line | :wrench: |
| [svelte/mustache-spacing](https://sveltejs.github.io/eslint-plugin-svelte/rules/mustache-spacing/) | enforce unified spacing in mustache | :wrench: |
| [svelte/no-extra-reactive-curlies](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-extra-reactive-curlies/) | disallow wrapping single reactive statements in curly braces | :bulb: |
| [svelte/no-restricted-html-elements](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-restricted-html-elements/) | disallow specific HTML elements | |
| [svelte/no-spaces-around-equal-signs-in-attribute](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-spaces-around-equal-signs-in-attribute/) | disallow spaces around equal signs in attribute | :wrench: |
| [svelte/prefer-class-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-class-directive/) | require class directives instead of ternary expressions | :wrench: |
| [svelte/prefer-style-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/prefer-style-directive/) | require style directives instead of style attribute | :wrench: |
| [svelte/shorthand-attribute](https://sveltejs.github.io/eslint-plugin-svelte/rules/shorthand-attribute/) | enforce use of shorthand syntax in attribute | :wrench: |
| [svelte/shorthand-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/shorthand-directive/) | enforce use of shorthand syntax in directives | :wrench: |
| [svelte/sort-attributes](https://sveltejs.github.io/eslint-plugin-svelte/rules/sort-attributes/) | enforce order of attributes | :wrench: |
| [svelte/spaced-html-comment](https://sveltejs.github.io/eslint-plugin-svelte/rules/spaced-html-comment/) | enforce consistent spacing after the `<!--` and before the `-->` in a HTML comment | :wrench: |
## Extension Rules
These rules extend the rules provided by ESLint itself, or other plugins to work well in Svelte:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/no-inner-declarations](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-inner-declarations/) | disallow variable or `function` declarations in nested blocks | :star: |
| [svelte/no-trailing-spaces](https://sveltejs.github.io/eslint-plugin-svelte/rules/no-trailing-spaces/) | disallow trailing whitespace at the end of lines | :wrench: |
## Experimental
:warning: These rules are considered experimental and may change or be removed in the future:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/experimental-require-slot-types](https://sveltejs.github.io/eslint-plugin-svelte/rules/experimental-require-slot-types/) | require slot type declaration using the `$$Slots` interface | |
| [svelte/experimental-require-strict-events](https://sveltejs.github.io/eslint-plugin-svelte/rules/experimental-require-strict-events/) | require the strictEvents attribute on `<script>` tags | |
## System
These rules relate to this plugin works:
| Rule ID | Description | |
|:--------|:------------|:---|
| [svelte/comment-directive](https://sveltejs.github.io/eslint-plugin-svelte/rules/comment-directive/) | support comment-directives in HTML template | :star: |
| [svelte/system](https://sveltejs.github.io/eslint-plugin-svelte/rules/system/) | system rule for working this plugin | :star: |
## Deprecated
- :warning: We're going to remove deprecated rules in the next major release. Please migrate to successor/new rules.
- :innocent: We don't fix bugs which are in deprecated rules since we don't have enough resources.
| Rule ID | Replaced by |
|:--------|:------------|
| [svelte/@typescript-eslint/no-unnecessary-condition](https://sveltejs.github.io/eslint-plugin-svelte/rules/@typescript-eslint/no-unnecessary-condition/) | This rule is no longer needed when using svelte-eslint-parser>=v0.19.0. |
<!--RULES_TABLE_END-->
<!--RULES_SECTION_END-->
<!-- prettier-ignore-end -->
<!--DOCS_IGNORE_START-->
## :beers: Contributing
Welcome contributing!
Please use GitHub's Issues/PRs.
See also [CONTRIBUTING.md](./CONTRIBUTING.md)
### Working With Rules
This plugin uses [svelte-eslint-parser](https://github.com/sveltejs/svelte-eslint-parser) for the parser. Check [here](https://sveltejs.github.io/svelte-eslint-parser/) to find out about AST.
<!--DOCS_IGNORE_END-->
## :lock: License
See the [LICENSE](LICENSE) file for license rights and limitations (MIT).
[svelte]: https://svelte.dev/
[eslint]: https://eslint.org/

View File

@ -0,0 +1,5 @@
declare const _default: {
extends: string[];
rules: any;
};
export = _default;

16
node_modules/eslint-plugin-svelte/lib/configs/all.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const rules_1 = require("../utils/rules");
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: Object.fromEntries(rules_1.rules
.map((rule) => [`svelte/${rule.meta.docs.ruleName}`, 'error'])
.filter(([ruleName]) => ![
'svelte/no-restricted-html-elements'
].includes(ruleName)))
};

View File

@ -0,0 +1,14 @@
declare const _default: {
plugins: string[];
overrides: {
files: string[];
parser: string;
rules: {
'no-inner-declarations': string;
'no-self-assign': string;
'svelte/comment-directive': string;
'svelte/system': string;
};
}[];
};
export = _default;

16
node_modules/eslint-plugin-svelte/lib/configs/base.js generated vendored Normal file
View File

@ -0,0 +1,16 @@
"use strict";
module.exports = {
plugins: ['svelte'],
overrides: [
{
files: ['*.svelte'],
parser: require.resolve('svelte-eslint-parser'),
rules: {
'no-inner-declarations': 'off',
'no-self-assign': 'off',
'svelte/comment-directive': 'error',
'svelte/system': 'error'
}
}
]
};

View File

@ -0,0 +1,17 @@
declare const _default: {
extends: string[];
rules: {
'svelte/first-attribute-linebreak': string;
'svelte/html-closing-bracket-spacing': string;
'svelte/html-quotes': string;
'svelte/html-self-closing': string;
'svelte/indent': string;
'svelte/max-attributes-per-line': string;
'svelte/mustache-spacing': string;
'svelte/no-spaces-around-equal-signs-in-attribute': string;
'svelte/no-trailing-spaces': string;
'svelte/shorthand-attribute': string;
'svelte/shorthand-directive': string;
};
};
export = _default;

View File

@ -0,0 +1,23 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: {
'svelte/first-attribute-linebreak': 'off',
'svelte/html-closing-bracket-spacing': 'off',
'svelte/html-quotes': 'off',
'svelte/html-self-closing': 'off',
'svelte/indent': 'off',
'svelte/max-attributes-per-line': 'off',
'svelte/mustache-spacing': 'off',
'svelte/no-spaces-around-equal-signs-in-attribute': 'off',
'svelte/no-trailing-spaces': 'off',
'svelte/shorthand-attribute': 'off',
'svelte/shorthand-directive': 'off'
}
};

View File

@ -0,0 +1,20 @@
declare const _default: {
extends: string[];
rules: {
'svelte/comment-directive': string;
'svelte/no-at-debug-tags': string;
'svelte/no-at-html-tags': string;
'svelte/no-dupe-else-if-blocks': string;
'svelte/no-dupe-style-properties': string;
'svelte/no-dynamic-slot-name': string;
'svelte/no-inner-declarations': string;
'svelte/no-not-function-handler': string;
'svelte/no-object-in-text-mustaches': string;
'svelte/no-shorthand-style-property-overrides': string;
'svelte/no-unknown-style-directive-property': string;
'svelte/no-unused-svelte-ignore': string;
'svelte/system': string;
'svelte/valid-compile': string;
};
};
export = _default;

View File

@ -0,0 +1,26 @@
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const path_1 = __importDefault(require("path"));
const base = require.resolve('./base');
const baseExtend = path_1.default.extname(`${base}`) === '.ts' ? 'plugin:svelte/base' : base;
module.exports = {
extends: [baseExtend],
rules: {
'svelte/comment-directive': 'error',
'svelte/no-at-debug-tags': 'warn',
'svelte/no-at-html-tags': 'error',
'svelte/no-dupe-else-if-blocks': 'error',
'svelte/no-dupe-style-properties': 'error',
'svelte/no-dynamic-slot-name': 'error',
'svelte/no-inner-declarations': 'error',
'svelte/no-not-function-handler': 'error',
'svelte/no-object-in-text-mustaches': 'error',
'svelte/no-shorthand-style-property-overrides': 'error',
'svelte/no-unknown-style-directive-property': 'error',
'svelte/no-unused-svelte-ignore': 'error',
'svelte/system': 'error',
'svelte/valid-compile': 'error'
}
};

67
node_modules/eslint-plugin-svelte/lib/index.d.ts generated vendored Normal file
View File

@ -0,0 +1,67 @@
import type { RuleModule } from './types';
import * as processor from './processor';
declare const _default: {
meta: typeof processor.meta;
configs: {
base: {
plugins: string[];
overrides: {
files: string[];
parser: string;
rules: {
'no-inner-declarations': string;
'no-self-assign': string;
'svelte/comment-directive': string;
'svelte/system': string;
};
}[];
};
recommended: {
extends: string[];
rules: {
'svelte/comment-directive': string;
'svelte/no-at-debug-tags': string;
'svelte/no-at-html-tags': string;
'svelte/no-dupe-else-if-blocks': string;
'svelte/no-dupe-style-properties': string;
'svelte/no-dynamic-slot-name': string;
'svelte/no-inner-declarations': string;
'svelte/no-not-function-handler': string;
'svelte/no-object-in-text-mustaches': string;
'svelte/no-shorthand-style-property-overrides': string;
'svelte/no-unknown-style-directive-property': string;
'svelte/no-unused-svelte-ignore': string;
'svelte/system': string;
'svelte/valid-compile': string;
};
};
prettier: {
extends: string[];
rules: {
'svelte/first-attribute-linebreak': string;
'svelte/html-closing-bracket-spacing': string;
'svelte/html-quotes': string;
'svelte/html-self-closing': string;
'svelte/indent': string;
'svelte/max-attributes-per-line': string;
'svelte/mustache-spacing': string;
'svelte/no-spaces-around-equal-signs-in-attribute': string;
'svelte/no-trailing-spaces': string;
'svelte/shorthand-attribute': string;
'svelte/shorthand-directive': string;
};
};
all: {
extends: string[];
rules: any;
};
};
rules: {
[key: string]: RuleModule;
};
processors: {
'.svelte': typeof processor;
svelte: typeof processor;
};
};
export = _default;

53
node_modules/eslint-plugin-svelte/lib/index.js generated vendored Normal file
View File

@ -0,0 +1,53 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
const rules_1 = require("./utils/rules");
const base_1 = __importDefault(require("./configs/base"));
const recommended_1 = __importDefault(require("./configs/recommended"));
const prettier_1 = __importDefault(require("./configs/prettier"));
const all_1 = __importDefault(require("./configs/all"));
const processor = __importStar(require("./processor"));
const meta = __importStar(require("./meta"));
const configs = {
base: base_1.default,
recommended: recommended_1.default,
prettier: prettier_1.default,
all: all_1.default
};
const rules = rules_1.rules.reduce((obj, r) => {
obj[r.meta.docs.ruleName] = r;
return obj;
}, {});
module.exports = {
meta,
configs,
rules,
processors: {
'.svelte': processor,
svelte: processor
}
};

2
node_modules/eslint-plugin-svelte/lib/meta.d.ts generated vendored Normal file
View File

@ -0,0 +1,2 @@
export declare const name: "eslint-plugin-svelte";
export declare const version: "2.35.0";

5
node_modules/eslint-plugin-svelte/lib/meta.js generated vendored Normal file
View File

@ -0,0 +1,5 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.version = exports.name = void 0;
exports.name = 'eslint-plugin-svelte';
exports.version = '2.35.0';

View File

@ -0,0 +1,5 @@
import type { Linter } from 'eslint';
export * as meta from '../meta';
export declare function preprocess(code: string, filename: string): string[];
export declare function postprocess([messages]: Linter.LintMessage[][], filename: string): Linter.LintMessage[];
export declare const supportsAutofix = true;

View File

@ -0,0 +1,54 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.supportsAutofix = exports.postprocess = exports.preprocess = exports.meta = void 0;
const shared_1 = require("../shared");
exports.meta = __importStar(require("../meta"));
function preprocess(code, filename) {
if (filename) {
(0, shared_1.beginShared)(filename);
}
return [code];
}
exports.preprocess = preprocess;
function postprocess([messages], filename) {
const shared = (0, shared_1.terminateShared)(filename);
if (shared) {
return filter(messages, shared);
}
return messages;
}
exports.postprocess = postprocess;
exports.supportsAutofix = true;
function filter(messages, shared) {
if (shared.commentDirectives.length === 0) {
return messages;
}
let filteredMessages = messages;
for (const cd of shared.commentDirectives) {
filteredMessages = cd.filterMessages(filteredMessages);
}
return filteredMessages;
}

View File

@ -0,0 +1,2 @@
declare const _default: import("../../types").RuleModule;
export default _default;

View File

@ -0,0 +1,424 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../../utils");
const ts_utils_1 = require("../../utils/ts-utils");
const compat_1 = require("../../utils/compat");
function unionTypeParts(type) {
return [...iterate(type)];
function* iterate(t) {
if (t.isUnion()) {
for (const type of t.types) {
yield* iterate(type);
}
}
else {
yield t;
}
}
}
function isPossiblyFalsy(type, tsTools) {
return (unionTypeParts(type)
.filter((t) => !(0, ts_utils_1.isTruthyLiteral)(t, tsTools))
.some((type) => (0, ts_utils_1.isPossiblyFalsyType)(type, tsTools.ts)));
}
function isPossiblyTruthy(type, tsTools) {
return unionTypeParts(type).some((type) => !(0, ts_utils_1.isFalsyType)(type, tsTools));
}
function isPossiblyNullish(type, tsTools) {
return (0, ts_utils_1.isNullableType)(type, tsTools.ts);
}
function isAlwaysNullish(type, tsTools) {
return (0, ts_utils_1.isNullishType)(type, tsTools.ts);
}
function isLiteral(type, tsTools) {
return ((0, ts_utils_1.isBooleanLiteralType)(type, tsTools.ts) || (0, ts_utils_1.isNullishType)(type, tsTools.ts) || type.isLiteral());
}
exports.default = (0, utils_1.createRule)('@typescript-eslint/no-unnecessary-condition', {
meta: {
docs: {
description: 'disallow conditionals where the type is always truthy or always falsy',
category: 'Extension Rules',
recommended: false,
extensionRule: {
plugin: '@typescript-eslint/eslint-plugin',
url: 'https://typescript-eslint.io/rules/no-unnecessary-condition/'
}
},
schema: [
{
type: 'object',
properties: {
allowConstantLoopConditions: {
description: 'Whether to ignore constant loop conditions, such as `while (true)`.',
type: 'boolean'
},
allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing: {
description: 'Whether to not error when running with a tsconfig that has strictNullChecks turned.',
type: 'boolean'
}
},
additionalProperties: false
}
],
fixable: 'code',
messages: {
alwaysTruthy: 'Unnecessary conditional, value is always truthy.',
alwaysFalsy: 'Unnecessary conditional, value is always falsy.',
alwaysTruthyFunc: 'This callback should return a conditional, but return is always truthy.',
alwaysFalsyFunc: 'This callback should return a conditional, but return is always falsy.',
neverNullish: 'Unnecessary conditional, expected left-hand side of `??` operator to be possibly null or undefined.',
alwaysNullish: 'Unnecessary conditional, left-hand side of `??` operator is always `null` or `undefined`.',
literalBooleanExpression: 'Unnecessary conditional, both sides of the expression are literal values.',
noOverlapBooleanExpression: 'Unnecessary conditional, the types have no overlap.',
never: 'Unnecessary conditional, value is `never`.',
neverOptionalChain: 'Unnecessary optional chain on a non-nullish value.',
noStrictNullCheck: 'This rule requires the `strictNullChecks` compiler option to be turned on to function correctly.'
},
type: 'suggestion',
deprecated: true,
replacedBy: {
note: 'This rule is no longer needed when using svelte-eslint-parser>=v0.19.0.'
}
},
create(context) {
const { allowConstantLoopConditions = false, allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing = false } = (context.options[0] || {});
const tools = (0, ts_utils_1.getTypeScriptTools)(context);
if (!tools) {
return {};
}
const { service, ts } = tools;
const checker = service.program.getTypeChecker();
const sourceCode = (0, compat_1.getSourceCode)(context);
const compilerOptions = service.program.getCompilerOptions();
const isStrictNullChecks = compilerOptions.strict
? compilerOptions.strictNullChecks !== false
: compilerOptions.strictNullChecks;
if (!isStrictNullChecks && allowRuleToRunWithoutStrictNullChecksIKnowWhatIAmDoing !== true) {
context.report({
loc: {
start: { line: 0, column: 0 },
end: { line: 0, column: 0 }
},
messageId: 'noStrictNullCheck'
});
}
const mutableVarReferenceIds = [];
const scriptElements = [];
let inSvelteReactiveStatement = false;
for (const scope of [
sourceCode.scopeManager.globalScope,
sourceCode.scopeManager.globalScope?.childScopes.find((scope) => scope.type === 'module')
]) {
if (!scope)
continue;
for (const variable of scope.variables) {
if (variable.defs.some((def) => def.type === 'Variable' && (def.parent.kind === 'var' || def.parent.kind === 'let'))) {
for (const reference of variable.references) {
mutableVarReferenceIds.push(reference.identifier);
}
}
}
}
for (const body of sourceCode.ast.body) {
if (body.type === 'SvelteScriptElement') {
scriptElements.push(body);
}
}
function hasSvelteReactiveVar(node) {
const inReactiveScope = inSvelteReactiveStatement ||
(scriptElements.length &&
scriptElements.every((elem) => node.range[1] <= elem.range[0] || elem.range[1] <= node.range[0]));
if (!inReactiveScope) {
return false;
}
return mutableVarReferenceIds.some((id) => node.range[0] <= id.range[0] && id.range[1] <= node.range[1]);
}
function getNodeType(node) {
const tsNode = service.esTreeNodeToTSNodeMap.get(node);
return tsNode && (0, ts_utils_1.getConstrainedTypeAtLocation)(checker, tsNode);
}
function nodeIsArrayType(node) {
const nodeType = getNodeType(node);
if (!nodeType) {
return false;
}
return checker.isArrayType(nodeType);
}
function nodeIsTupleType(node) {
const nodeType = getNodeType(node);
return Boolean(nodeType && (0, ts_utils_1.isTupleType)(nodeType, ts));
}
function isArrayIndexExpression(node) {
return (node.type === 'MemberExpression' &&
node.computed &&
(nodeIsArrayType(node.object) ||
(nodeIsTupleType(node.object) &&
node.property.type !== 'Literal')));
}
function checkNode(node, isUnaryNotArgument = false) {
if (hasSvelteReactiveVar(node)) {
return;
}
if (node.type === 'UnaryExpression' && node.operator === '!') {
checkNode(node.argument, true);
return;
}
if (isArrayIndexExpression(node)) {
return;
}
if (node.type === 'LogicalExpression' && node.operator !== '??') {
checkNode(node.right);
return;
}
const type = getNodeType(node);
if (!type ||
unionTypeParts(type).some((part) => (0, ts_utils_1.isAnyType)(part, ts) || (0, ts_utils_1.isUnknownType)(part, ts) || part.isTypeParameter())) {
return;
}
let messageId = null;
if (unionTypeParts(type).some((part) => (0, ts_utils_1.isNeverType)(part, ts))) {
messageId = 'never';
}
else if (!isPossiblyTruthy(type, tools)) {
messageId = !isUnaryNotArgument ? 'alwaysFalsy' : 'alwaysTruthy';
}
else if (!isPossiblyFalsy(type, tools)) {
messageId = !isUnaryNotArgument ? 'alwaysTruthy' : 'alwaysFalsy';
}
if (messageId) {
context.report({ node, messageId });
}
}
function checkNodeForNullish(node) {
if (hasSvelteReactiveVar(node)) {
return;
}
const type = getNodeType(node);
if (!type || (0, ts_utils_1.isAnyType)(type, ts) || (0, ts_utils_1.isUnknownType)(type, ts)) {
return;
}
let messageId = null;
if (unionTypeParts(type).some((part) => (0, ts_utils_1.isNeverType)(part, ts))) {
messageId = 'never';
}
else if (!isPossiblyNullish(type, tools)) {
if (!isArrayIndexExpression(node) &&
!(node.type === 'ChainExpression' &&
node.expression.type !== 'TSNonNullExpression' &&
optionChainContainsOptionArrayIndex(node.expression))) {
messageId = 'neverNullish';
}
}
else if (isAlwaysNullish(type, tools)) {
messageId = 'alwaysNullish';
}
if (messageId) {
context.report({ node, messageId });
}
}
const BOOL_OPERATORS = new Set(['<', '>', '<=', '>=', '==', '===', '!=', '!==']);
function checkIfBinaryExpressionIsNecessaryConditional(node) {
if (hasSvelteReactiveVar(node)) {
return;
}
if (!BOOL_OPERATORS.has(node.operator)) {
return;
}
const leftType = getNodeType(node.left);
const rightType = getNodeType(node.right);
if (!leftType || !rightType) {
return;
}
if (isLiteral(leftType, tools) && isLiteral(rightType, tools)) {
context.report({ node, messageId: 'literalBooleanExpression' });
return;
}
if (isStrictNullChecks) {
const UNDEFINED = ts.TypeFlags.Undefined;
const NULL = ts.TypeFlags.Null;
const isComparable = (type, f) => {
let flag = f;
flag |= ts.TypeFlags.Any | ts.TypeFlags.Unknown | ts.TypeFlags.TypeParameter;
if (node.operator === '==' || node.operator === '!=') {
flag |= NULL | UNDEFINED;
}
return unionTypeParts(type).some((t) => (t.flags & flag) !== 0);
};
if ((leftType.flags === UNDEFINED && !isComparable(rightType, UNDEFINED)) ||
(rightType.flags === UNDEFINED && !isComparable(leftType, UNDEFINED)) ||
(leftType.flags === NULL && !isComparable(rightType, NULL)) ||
(rightType.flags === NULL && !isComparable(leftType, NULL))) {
context.report({ node, messageId: 'noOverlapBooleanExpression' });
}
}
}
function checkLogicalExpressionForUnnecessaryConditionals(node) {
if (node.operator === '??') {
checkNodeForNullish(node.left);
return;
}
checkNode(node.left);
}
function checkIfLoopIsNecessaryConditional(node) {
if (node.test === null) {
return;
}
if (allowConstantLoopConditions) {
const nodeType = getNodeType(node.test);
if (nodeType &&
(0, ts_utils_1.isBooleanLiteralType)(nodeType, ts) &&
checker.typeToString(nodeType) === 'true')
return;
}
checkNode(node.test);
}
const ARRAY_PREDICATE_FUNCTIONS = new Set(['filter', 'find', 'some', 'every']);
function isArrayPredicateFunction(node) {
const { callee } = node;
return (callee.type === 'MemberExpression' &&
callee.property.type === 'Identifier' &&
ARRAY_PREDICATE_FUNCTIONS.has(callee.property.name) &&
(nodeIsArrayType(callee.object) || nodeIsTupleType(callee.object)));
}
function checkCallExpression(node) {
if (isArrayPredicateFunction(node) && node.arguments.length) {
const callback = node.arguments[0];
if ((callback.type === 'ArrowFunctionExpression' || callback.type === 'FunctionExpression') &&
callback.body) {
if (callback.body.type !== 'BlockStatement') {
checkNode(callback.body);
return;
}
const callbackBody = callback.body.body;
if (callbackBody.length === 1 &&
callbackBody[0].type === 'ReturnStatement' &&
callbackBody[0].argument) {
checkNode(callbackBody[0].argument);
return;
}
}
const nodeType = getNodeType(callback);
if (!nodeType) {
return;
}
const returnTypes = (0, ts_utils_1.getCallSignaturesOfType)(nodeType).map((sig) => sig.getReturnType());
if (returnTypes.length === 0) {
return;
}
if (returnTypes.some((t) => (0, ts_utils_1.isAnyType)(t, ts) || (0, ts_utils_1.isUnknownType)(t, ts))) {
return;
}
if (!returnTypes.some((t) => isPossiblyFalsy(t, tools))) {
context.report({
node: callback,
messageId: 'alwaysTruthyFunc'
});
return;
}
if (!returnTypes.some((t) => isPossiblyTruthy(t, tools))) {
context.report({
node: callback,
messageId: 'alwaysFalsyFunc'
});
}
}
}
function optionChainContainsOptionArrayIndex(node) {
const lhsNode = node.type === 'CallExpression' ? node.callee : node.object;
if (node.optional && isArrayIndexExpression(lhsNode)) {
return true;
}
if (lhsNode.type === 'MemberExpression' || lhsNode.type === 'CallExpression') {
return optionChainContainsOptionArrayIndex(lhsNode);
}
return false;
}
function isNullablePropertyType(objType, propertyType) {
if (propertyType.isUnion()) {
return propertyType.types.some((type) => isNullablePropertyType(objType, type));
}
if (propertyType.isNumberLiteral() || propertyType.isStringLiteral()) {
const propType = (0, ts_utils_1.getTypeOfPropertyOfType)(objType, propertyType.value.toString(), checker);
if (propType) {
return (0, ts_utils_1.isNullableType)(propType, ts);
}
}
const typeName = (0, ts_utils_1.getTypeName)(propertyType, tools);
return Boolean((typeName === 'string' && checker.getIndexInfoOfType(objType, ts.IndexKind.String)) ||
(typeName === 'number' && checker.getIndexInfoOfType(objType, ts.IndexKind.Number)));
}
function isNullableOriginFromPrev(node) {
const prevType = getNodeType(node.object);
const property = node.property;
if (prevType && prevType.isUnion() && property.type === 'Identifier') {
const isOwnNullable = prevType.types.some((type) => {
if (node.computed) {
const propertyType = getNodeType(node.property);
return Boolean(propertyType && isNullablePropertyType(type, propertyType));
}
const propType = (0, ts_utils_1.getTypeOfPropertyOfType)(type, property.name, checker);
return propType && (0, ts_utils_1.isNullableType)(propType, ts);
});
return !isOwnNullable && (0, ts_utils_1.isNullableType)(prevType, ts);
}
return false;
}
function isOptionableExpression(node) {
const type = getNodeType(node);
if (!type) {
return false;
}
const isOwnNullable = node.type === 'MemberExpression' ? !isNullableOriginFromPrev(node) : true;
return ((0, ts_utils_1.isAnyType)(type, ts) ||
(0, ts_utils_1.isUnknownType)(type, ts) ||
((0, ts_utils_1.isNullableType)(type, ts) && isOwnNullable));
}
function checkOptionalChain(node, beforeOperator, fix) {
if (!node.optional) {
return;
}
if (optionChainContainsOptionArrayIndex(node)) {
return;
}
const nodeToCheck = node.type === 'CallExpression' ? node.callee : node.object;
if (hasSvelteReactiveVar(nodeToCheck)) {
return;
}
if (isOptionableExpression(nodeToCheck)) {
return;
}
const questionDotOperator = sourceCode.getTokenAfter(beforeOperator, {
includeComments: false,
filter: (token) => token.type === 'Punctuator' && token.value === '?.'
});
context.report({
node,
loc: questionDotOperator.loc,
messageId: 'neverOptionalChain',
fix(fixer) {
return fixer.replaceText(questionDotOperator, fix);
}
});
}
function checkOptionalMemberExpression(node) {
checkOptionalChain(node, node.object, node.computed ? '' : '.');
}
function checkOptionalCallExpression(node) {
checkOptionalChain(node, node.callee, '');
}
return {
SvelteReactiveStatement: () => (inSvelteReactiveStatement = true),
'SvelteReactiveStatement:exit': () => (inSvelteReactiveStatement = false),
BinaryExpression: checkIfBinaryExpressionIsNecessaryConditional,
CallExpression: checkCallExpression,
ConditionalExpression: (node) => checkNode(node.test),
DoWhileStatement: checkIfLoopIsNecessaryConditional,
ForStatement: checkIfLoopIsNecessaryConditional,
IfStatement: (node) => checkNode(node.test),
LogicalExpression: checkLogicalExpressionForUnnecessaryConditionals,
WhileStatement: checkIfLoopIsNecessaryConditional,
'MemberExpression[optional = true]': checkOptionalMemberExpression,
'CallExpression[optional = true]': checkOptionalCallExpression
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,123 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('block-lang', {
meta: {
docs: {
description: 'disallows the use of languages other than those specified in the configuration for the lang attribute of `<script>` and `<style>` blocks.',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
enforceScriptPresent: {
type: 'boolean'
},
enforceStylePresent: {
type: 'boolean'
},
script: {
oneOf: [
{
type: ['string', 'null']
},
{
type: 'array',
items: {
type: ['string', 'null']
},
minItems: 1
}
]
},
style: {
oneOf: [
{
type: ['string', 'null']
},
{
type: 'array',
items: {
type: ['string', 'null']
},
minItems: 1
}
]
}
},
additionalProperties: false
}
],
messages: {},
type: 'suggestion'
},
create(context) {
if (!(0, compat_1.getSourceCode)(context).parserServices.isSvelte) {
return {};
}
const enforceScriptPresent = context.options[0]?.enforceScriptPresent ?? false;
const enforceStylePresent = context.options[0]?.enforceStylePresent ?? false;
const scriptOption = context.options[0]?.script ?? null;
const allowedScriptLangs = Array.isArray(scriptOption)
? scriptOption
: [scriptOption];
const scriptNodes = [];
const styleOption = context.options[0]?.style ?? null;
const allowedStyleLangs = Array.isArray(styleOption)
? styleOption
: [styleOption];
const styleNodes = [];
return {
SvelteScriptElement(node) {
scriptNodes.push(node);
},
SvelteStyleElement(node) {
styleNodes.push(node);
},
'Program:exit'() {
if (scriptNodes.length === 0 && enforceScriptPresent) {
context.report({
loc: { line: 1, column: 1 },
message: `The <script> block should be present and its lang attribute should be ${prettyPrintLangs(allowedScriptLangs)}.`
});
}
for (const scriptNode of scriptNodes) {
if (!allowedScriptLangs.includes((0, ast_utils_1.getLangValue)(scriptNode)?.toLowerCase() ?? null)) {
context.report({
node: scriptNode,
message: `The lang attribute of the <script> block should be ${prettyPrintLangs(allowedScriptLangs)}.`
});
}
}
if (styleNodes.length === 0 && enforceStylePresent) {
context.report({
loc: { line: 1, column: 1 },
message: `The <style> block should be present and its lang attribute should be ${prettyPrintLangs(allowedStyleLangs)}.`
});
}
for (const styleNode of styleNodes) {
if (!allowedStyleLangs.includes((0, ast_utils_1.getLangValue)(styleNode)?.toLowerCase() ?? null)) {
context.report({
node: styleNode,
message: `The lang attribute of the <style> block should be ${prettyPrintLangs(allowedStyleLangs)}.`
});
}
}
}
};
}
});
function prettyPrintLangs(langs) {
const hasNull = langs.includes(null);
const nonNullLangs = langs.filter((lang) => lang !== null).map((lang) => `"${lang}"`);
if (nonNullLangs.length === 0) {
return 'omitted';
}
const hasNullText = hasNull ? 'either omitted or ' : '';
const nonNullText = nonNullLangs.length === 1 ? nonNullLangs[0] : `one of ${nonNullLangs.join(', ')}`;
return hasNullText + nonNullText;
}

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,100 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
exports.default = (0, utils_1.createRule)('button-has-type', {
meta: {
docs: {
description: 'disallow usage of button without an explicit type attribute',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
button: {
type: 'boolean'
},
submit: {
type: 'boolean'
},
reset: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
missingTypeAttribute: 'Missing an explicit type attribute for button.',
invalidTypeAttribute: '{{value}} is an invalid value for button type attribute.',
forbiddenTypeAttribute: '{{value}} is a forbidden value for button type attribute.',
emptyTypeAttribute: 'A value must be set for button type attribute.'
},
type: 'suggestion'
},
create(context) {
const configuration = {
button: true,
submit: true,
reset: true,
...(context.options[0] ?? {})
};
function isButtonType(type) {
return type === 'button' || type === 'submit' || type === 'reset';
}
function report(node, messageId, data = {}) {
context.report({
node,
messageId,
data
});
}
function validateAttribute(attribute) {
if (attribute.value.length === 0) {
report(attribute, 'emptyTypeAttribute');
return;
}
const strValue = (0, ast_utils_1.getStaticAttributeValue)(attribute);
if (strValue == null) {
return;
}
if (!isButtonType(strValue)) {
report(attribute, 'invalidTypeAttribute', { value: strValue });
}
else if (!configuration[strValue]) {
report(attribute, 'forbiddenTypeAttribute', { value: strValue });
}
}
function validateDirective(directive) {
if (!directive.expression) {
report(directive, 'emptyTypeAttribute');
}
}
return {
"SvelteElement[name.name='button'] > SvelteStartTag"(node) {
const typeAttr = (0, ast_utils_1.findAttribute)(node, 'type');
if (typeAttr) {
validateAttribute(typeAttr);
return;
}
const typeDir = (0, ast_utils_1.findBindDirective)(node, 'type');
if (typeDir) {
validateDirective(typeDir);
return;
}
const typeShortAttr = (0, ast_utils_1.findShorthandAttribute)(node, 'type');
if (typeShortAttr) {
return;
}
for (const attr of node.attributes) {
if (attr.type === 'SvelteSpreadAttribute') {
return;
}
}
report(node, 'missingTypeAttribute');
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,182 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const shared_1 = require("../shared");
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
const COMMENT_DIRECTIVE_B = /^\s*(eslint-(?:en|dis)able)(?:\s+|$)/;
const COMMENT_DIRECTIVE_L = /^\s*(eslint-disable(?:-next)?-line)(?:\s+|$)/;
const ALL_RULES = () => true;
function stripDirectiveComment(value) {
return value.split(/\s-{2,}\s/u)[0];
}
exports.default = (0, utils_1.createRule)('comment-directive', {
meta: {
docs: {
description: 'support comment-directives in HTML template',
category: 'System',
recommended: 'base'
},
schema: [
{
type: 'object',
properties: {
reportUnusedDisableDirectives: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
unused: 'Unused {{kind}} directive (no problems were reported).',
unusedRule: "Unused {{kind}} directive (no problems were reported from '{{rule}}').",
unusedEnable: 'Unused {{kind}} directive (reporting is not suppressed).',
unusedEnableRule: "Unused {{kind}} directive (reporting from '{{rule}}' is not suppressed)."
},
type: 'problem'
},
create(context) {
const shared = (0, shared_1.getShared)((0, compat_1.getFilename)(context));
if (!shared)
return {};
const options = context.options[0] || {};
const reportUnusedDisableDirectives = Boolean(options.reportUnusedDisableDirectives);
const directives = shared.newCommentDirectives({
ruleId: 'svelte/comment-directive',
reportUnusedDisableDirectives
});
const sourceCode = (0, compat_1.getSourceCode)(context);
function parse(pattern, comment) {
const text = stripDirectiveComment(comment.value);
const match = pattern.exec(text);
if (match == null) {
return null;
}
const type = match[1];
const rules = [];
const rulesRe = /([^\s,]+)[\s,]*/g;
let startIndex = match[0].length;
rulesRe.lastIndex = startIndex;
let res;
while ((res = rulesRe.exec(text))) {
const ruleId = res[1].trim();
const commentStart = comment.range[0] + 4;
const start = sourceCode.getLocFromIndex(commentStart + startIndex);
const end = sourceCode.getLocFromIndex(commentStart + startIndex + ruleId.length);
rules.push({
ruleId,
loc: {
start,
end
}
});
startIndex = rulesRe.lastIndex;
}
return { type, rules };
}
function processBlock(directives, comment) {
const parsed = parse(COMMENT_DIRECTIVE_B, comment);
if (parsed != null) {
if (parsed.type === 'eslint-disable') {
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.disableBlock(comment.loc.end, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unused',
data: { kind: parsed.type }
});
}
directives.disableBlock(comment.loc.end, ALL_RULES, {
loc: comment.loc.start
});
}
}
else {
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedEnableRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.enableBlock(comment.loc.start, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unusedEnable',
data: { kind: parsed.type }
});
}
directives.enableBlock(comment.loc.start, ALL_RULES, {
loc: comment.loc.start
});
}
}
}
}
function processLine(directives, comment) {
const parsed = parse(COMMENT_DIRECTIVE_L, comment);
if (parsed != null && comment.loc.start.line === comment.loc.end.line) {
const line = comment.loc.start.line + (parsed.type === 'eslint-disable-line' ? 0 : 1);
if (parsed.rules.length) {
for (const rule of parsed.rules) {
if (reportUnusedDisableDirectives) {
context.report({
loc: rule.loc,
messageId: 'unusedRule',
data: { rule: rule.ruleId, kind: parsed.type }
});
}
directives.disableLine(line, rule.ruleId, {
loc: rule.loc.start
});
}
}
else {
if (reportUnusedDisableDirectives) {
context.report({
loc: comment.loc,
messageId: 'unused',
data: { kind: parsed.type }
});
}
directives.disableLine(line, ALL_RULES, {
loc: comment.loc.start
});
}
}
}
return {
SvelteHTMLComment(node) {
processBlock(directives, node);
processLine(directives, node);
},
SvelteScriptElement(node) {
directives.enableBlock(node.startTag.loc.end, ALL_RULES, {
loc: node.loc.start
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,80 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const svelte_store_1 = require("./reference-helpers/svelte-store");
exports.default = (0, utils_1.createRule)('derived-has-same-inputs-outputs', {
meta: {
docs: {
description: 'derived store should use same variable names between values and callback',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
schema: [],
messages: {
unexpected: "The argument name should be '{{name}}'."
},
type: 'suggestion'
},
create(context) {
function isIdentifierOrArrayExpression(node) {
return ['Identifier', 'ArrayExpression'].includes(node.type);
}
function isFunctionExpression(node) {
return ['ArrowFunctionExpression', 'FunctionExpression'].includes(node.type);
}
function checkIdentifier(context, args, fn) {
const fnParam = fn.params[0];
if (fnParam.type !== 'Identifier')
return;
const expectedName = `$${args.name}`;
if (expectedName !== fnParam.name) {
context.report({
node: fn,
loc: fnParam.loc,
messageId: 'unexpected',
data: { name: expectedName }
});
}
}
function checkArrayExpression(context, args, fn) {
const fnParam = fn.params[0];
if (fnParam.type !== 'ArrayPattern')
return;
const argNames = args.elements.map((element) => {
return element && element.type === 'Identifier' ? element.name : null;
});
fnParam.elements.forEach((element, index) => {
const argName = argNames[index];
if (element && element.type === 'Identifier' && argName) {
const expectedName = `$${argName}`;
if (expectedName !== element.name) {
context.report({
node: fn,
loc: element.loc,
messageId: 'unexpected',
data: { name: expectedName }
});
}
}
});
}
return {
Program() {
for (const { node } of (0, svelte_store_1.extractStoreReferences)(context, ['derived'])) {
const [args, fn] = node.arguments;
if (!args || !isIdentifierOrArrayExpression(args))
continue;
if (!fn || !isFunctionExpression(fn))
continue;
if (!fn.params || fn.params.length === 0)
continue;
if (args.type === 'Identifier')
checkIdentifier(context, args, fn);
else
checkArrayExpression(context, args, fn);
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,56 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const SLOTS_TYPE_NAME = '$$Slots';
exports.default = (0, utils_1.createRule)('experimental-require-slot-types', {
meta: {
docs: {
description: 'require slot type declaration using the `$$Slots` interface',
category: 'Experimental',
recommended: false
},
schema: [],
messages: {
missingSlotsInterface: `The component must define the $$Slots interface.`
},
type: 'suggestion'
},
create(context) {
let isTs = false;
let hasSlot = false;
let hasDeclaredSlots = false;
return {
SvelteScriptElement(node) {
const lang = (0, ast_utils_1.getLangValue)(node)?.toLowerCase();
isTs = lang === 'ts' || lang === 'typescript';
},
SvelteElement(node) {
if (node.name.type === 'SvelteName' && node.name.name === 'slot') {
hasSlot = true;
}
},
TSInterfaceDeclaration(node) {
if (node.id.name === SLOTS_TYPE_NAME) {
hasDeclaredSlots = true;
}
},
TSTypeAliasDeclaration(node) {
if (node.id.name === SLOTS_TYPE_NAME) {
hasDeclaredSlots = true;
}
},
'Program:exit'() {
if (isTs && hasSlot && !hasDeclaredSlots) {
context.report({
loc: {
line: 1,
column: 1
},
messageId: 'missingSlotsInterface'
});
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const EVENTS_TYPE_NAME = '$$Events';
exports.default = (0, utils_1.createRule)('experimental-require-strict-events', {
meta: {
docs: {
description: 'require the strictEvents attribute on `<script>` tags',
category: 'Experimental',
recommended: false
},
schema: [],
messages: {
missingStrictEvents: `The component must have the strictEvents attribute on its <script> tag or it must define the $$Events interface.`
},
type: 'suggestion'
},
create(context) {
let isTs = false;
let hasAttribute = false;
let hasDeclaredEvents = false;
let scriptNode;
return {
SvelteScriptElement(node) {
const lang = (0, ast_utils_1.getLangValue)(node)?.toLowerCase();
isTs = lang === 'ts' || lang === 'typescript';
hasAttribute = (0, ast_utils_1.findAttribute)(node, 'strictEvents') !== null;
scriptNode = node;
},
TSInterfaceDeclaration(node) {
if (node.id.name === EVENTS_TYPE_NAME) {
hasDeclaredEvents = true;
}
},
TSTypeAliasDeclaration(node) {
if (node.id.name === EVENTS_TYPE_NAME) {
hasDeclaredEvents = true;
}
},
'Program:exit'() {
if (isTs && !hasAttribute && !hasDeclaredEvents) {
context.report({
node: scriptNode,
messageId: 'missingStrictEvents'
});
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,67 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('first-attribute-linebreak', {
meta: {
docs: {
description: 'enforce the location of first attribute',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
multiline: { enum: ['below', 'beside'] },
singleline: { enum: ['below', 'beside'] }
},
additionalProperties: false
}
],
messages: {
expected: 'Expected a linebreak before this attribute.',
unexpected: 'Expected no linebreak before this attribute.'
},
type: 'layout'
},
create(context) {
const multiline = context.options[0]?.multiline || 'below';
const singleline = context.options[0]?.singleline || 'beside';
const sourceCode = (0, compat_1.getSourceCode)(context);
function report(firstAttribute, location) {
context.report({
node: firstAttribute,
messageId: location === 'beside' ? 'unexpected' : 'expected',
fix(fixer) {
const prevToken = sourceCode.getTokenBefore(firstAttribute, {
includeComments: true
});
return fixer.replaceTextRange([prevToken.range[1], firstAttribute.range[0]], location === 'beside' ? ' ' : '\n');
}
});
}
return {
SvelteStartTag(node) {
const firstAttribute = node.attributes[0];
if (!firstAttribute)
return;
const lastAttribute = node.attributes[node.attributes.length - 1];
const location = firstAttribute.loc.start.line === lastAttribute.loc.end.line ? singleline : multiline;
if (location === 'beside') {
if (node.parent.name.loc.end.line === firstAttribute.loc.start.line) {
return;
}
}
else {
if (node.parent.name.loc.end.line < firstAttribute.loc.start.line) {
return;
}
}
report(firstAttribute, location);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,92 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('html-closing-bracket-spacing', {
meta: {
docs: {
description: "require or disallow a space before tag's closing brackets",
category: 'Stylistic Issues',
conflictWithPrettier: true,
recommended: false
},
schema: [
{
type: 'object',
properties: {
startTag: {
enum: ['always', 'never', 'ignore']
},
endTag: {
enum: ['always', 'never', 'ignore']
},
selfClosingTag: {
enum: ['always', 'never', 'ignore']
}
},
additionalProperties: false
}
],
messages: {
expectedSpace: "Expected space before '>', but not found.",
unexpectedSpace: "Expected no space before '>', but found."
},
fixable: 'whitespace',
type: 'layout'
},
create(ctx) {
const options = {
startTag: 'never',
endTag: 'never',
selfClosingTag: 'always',
...ctx.options[0]
};
const src = ctx.getSourceCode();
function containsNewline(string) {
return string.includes('\n');
}
function report(node, shouldHave) {
const tagSrc = src.getText(node);
const match = /(\s*)\/?>$/.exec(tagSrc);
const end = node.range[1];
const start = node.range[1] - match[0].length;
const loc = {
start: src.getLocFromIndex(start),
end: src.getLocFromIndex(end)
};
ctx.report({
loc,
messageId: shouldHave ? 'expectedSpace' : 'unexpectedSpace',
*fix(fixer) {
if (shouldHave) {
yield fixer.insertTextBeforeRange([start, end], ' ');
}
else {
const spaces = match[1];
yield fixer.removeRange([start, start + spaces.length]);
}
}
});
}
return {
'SvelteStartTag, SvelteEndTag'(node) {
const tagType = node.type === 'SvelteEndTag'
? 'endTag'
: node.selfClosing
? 'selfClosingTag'
: 'startTag';
if (options[tagType] === 'ignore')
return;
const tagSrc = src.getText(node);
const match = /(\s*)\/?>$/.exec(tagSrc);
if (containsNewline(match[1]))
return;
if (options[tagType] === 'always' && !match[1]) {
report(node, true);
}
else if (options[tagType] === 'never' && match[1]) {
report(node, false);
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,158 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const ast_utils_2 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const QUOTE_CHARS = {
double: '"',
single: "'"
};
const QUOTE_NAMES = {
double: 'double quotes',
single: 'single quotes',
unquoted: 'unquoted'
};
exports.default = (0, utils_1.createRule)('html-quotes', {
meta: {
docs: {
description: 'enforce quotes style of HTML attributes',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
prefer: { enum: ['double', 'single'] },
dynamic: {
type: 'object',
properties: {
quoted: { type: 'boolean' },
avoidInvalidUnquotedInHTML: { type: 'boolean' }
},
additionalProperties: false
}
},
additionalProperties: false
}
],
messages: {
expectedEnclosed: 'Expected to be enclosed by quotes.',
expectedEnclosedBy: 'Expected to be enclosed by {{kind}}.',
unexpectedEnclosed: 'Unexpected to be enclosed by any quotes.'
},
type: 'layout'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const preferQuote = context.options[0]?.prefer ?? 'double';
const dynamicQuote = context.options[0]?.dynamic?.quoted ? preferQuote : 'unquoted';
const avoidInvalidUnquotedInHTML = Boolean(context.options[0]?.dynamic?.avoidInvalidUnquotedInHTML);
function canBeUnquotedInHTML(text) {
return !/[\s"'<=>`]/u.test(text);
}
function verifyQuote(prefer, quoteAndRange) {
if (!quoteAndRange) {
return;
}
if (quoteAndRange.quote === prefer) {
return;
}
let messageId;
let expectedQuote = prefer;
if (quoteAndRange.quote !== 'unquoted') {
if (expectedQuote === 'unquoted') {
messageId = 'unexpectedEnclosed';
}
else {
const contentText = sourceCode.text.slice(quoteAndRange.range[0] + 1, quoteAndRange.range[1] - 1);
const needEscape = contentText.includes(QUOTE_CHARS[expectedQuote]);
if (needEscape) {
return;
}
messageId = 'expectedEnclosedBy';
}
}
else {
const contentText = sourceCode.text.slice(...quoteAndRange.range);
const needEscapeDoubleQuote = contentText.includes('"');
const needEscapeSingleQuote = contentText.includes("'");
if (needEscapeDoubleQuote && needEscapeSingleQuote) {
return;
}
if (needEscapeDoubleQuote && expectedQuote === 'double') {
expectedQuote = 'single';
messageId = 'expectedEnclosed';
}
else if (needEscapeSingleQuote && expectedQuote === 'single') {
expectedQuote = 'double';
messageId = 'expectedEnclosed';
}
else {
messageId = 'expectedEnclosedBy';
}
}
context.report({
loc: {
start: sourceCode.getLocFromIndex(quoteAndRange.range[0]),
end: sourceCode.getLocFromIndex(quoteAndRange.range[1])
},
messageId,
data: { kind: QUOTE_NAMES[expectedQuote] },
*fix(fixer) {
if (expectedQuote !== 'unquoted') {
yield fixer.insertTextBeforeRange([quoteAndRange.range[0], quoteAndRange.range[0]], QUOTE_CHARS[expectedQuote]);
}
if (quoteAndRange.quote !== 'unquoted') {
yield fixer.removeRange([quoteAndRange.range[0], quoteAndRange.range[0] + 1]);
yield fixer.removeRange([quoteAndRange.range[1] - 1, quoteAndRange.range[1]]);
}
if (expectedQuote !== 'unquoted') {
yield fixer.insertTextAfterRange([quoteAndRange.range[1], quoteAndRange.range[1]], QUOTE_CHARS[expectedQuote]);
}
}
});
}
function verifyForValues(attr) {
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
verifyQuote(preferQuote, quoteAndRange);
}
function verifyForDynamicMustacheTag(attr, valueNode) {
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
const text = sourceCode.text.slice(...valueNode.range);
verifyQuote(avoidInvalidUnquotedInHTML && !canBeUnquotedInHTML(text) ? preferQuote : dynamicQuote, quoteAndRange);
}
function verifyForDirective(attr) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(attr, sourceCode);
if (!mustacheTokens) {
return;
}
const quoteAndRange = (0, ast_utils_2.getAttributeValueQuoteAndRange)(attr, sourceCode);
const text = sourceCode.text.slice(mustacheTokens.openToken.range[0], mustacheTokens.closeToken.range[1]);
verifyQuote(avoidInvalidUnquotedInHTML && !canBeUnquotedInHTML(text) ? preferQuote : dynamicQuote, quoteAndRange);
}
return {
'SvelteAttribute, SvelteStyleDirective'(node) {
if (node.value.length === 1 && node.value[0].type === 'SvelteMustacheTag') {
verifyForDynamicMustacheTag(node, node.value[0]);
}
else if (node.value.length >= 1) {
verifyForValues(node);
}
},
'SvelteDirective, SvelteSpecialDirective'(node) {
if (node.expression == null) {
return;
}
if (node.key.range[0] <= node.expression.range[0] &&
node.expression.range[1] <= node.key.range[1]) {
return;
}
verifyForDirective(node);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,154 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const TYPE_MESSAGES = {
normal: 'HTML elements',
void: 'HTML void elements',
component: 'Svelte custom components',
svelte: 'Svelte special elements'
};
exports.default = (0, utils_1.createRule)('html-self-closing', {
meta: {
docs: {
description: 'enforce self-closing style',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
type: 'layout',
fixable: 'code',
messages: {
requireClosing: 'Require self-closing on {{type}}.',
disallowClosing: 'Disallow self-closing on {{type}}.'
},
schema: [
{
anyOf: [
{
properties: {
void: {
enum: ['never', 'always', 'ignore']
},
normal: {
enum: ['never', 'always', 'ignore']
},
component: {
enum: ['never', 'always', 'ignore']
},
svelte: {
enum: ['never', 'always', 'ignore']
}
},
additionalProperties: false
},
{
enum: ['all', 'html', 'none']
}
]
}
]
},
create(context) {
let options = {
void: 'always',
normal: 'always',
component: 'always',
svelte: 'always'
};
const option = context.options?.[0];
switch (option) {
case 'none':
options = {
void: 'never',
normal: 'never',
component: 'never',
svelte: 'never'
};
break;
case 'html':
options = {
void: 'always',
normal: 'never',
component: 'never',
svelte: 'always'
};
break;
default:
if (typeof option !== 'object' || option === null)
break;
options = {
...options,
...option
};
break;
}
function getElementType(node) {
if (node.kind === 'component')
return 'component';
if (node.kind === 'special')
return 'svelte';
if ((0, ast_utils_1.isVoidHtmlElement)(node))
return 'void';
return 'normal';
}
function isElementEmpty(node) {
if (node.children.length <= 0)
return true;
for (const child of node.children) {
if (child.type !== 'SvelteText')
return false;
if (!/^\s*$/.test(child.value))
return false;
}
return true;
}
function report(node, shouldBeClosed) {
const elementType = getElementType(node);
context.report({
node,
loc: {
start: (0, compat_1.getSourceCode)(context).getLocFromIndex(node.startTag.range[1] - (node.startTag.selfClosing ? 2 : 1)),
end: node.loc.end
},
messageId: shouldBeClosed ? 'requireClosing' : 'disallowClosing',
data: {
type: TYPE_MESSAGES[elementType]
},
*fix(fixer) {
if (shouldBeClosed) {
for (const child of node.children) {
yield fixer.removeRange(child.range);
}
yield fixer.insertTextBeforeRange([node.startTag.range[1] - 1, node.startTag.range[1]], '/');
if (node.endTag)
yield fixer.removeRange(node.endTag.range);
}
else {
yield fixer.removeRange([node.startTag.range[1] - 2, node.startTag.range[1] - 1]);
if (!(0, ast_utils_1.isVoidHtmlElement)(node))
yield fixer.insertTextAfter(node, `</${(0, ast_utils_1.getNodeName)(node)}>`);
}
}
});
}
return {
SvelteElement(node) {
if (!isElementEmpty(node))
return;
const elementType = getElementType(node);
const elementTypeOptions = options[elementType];
if (elementTypeOptions === 'ignore')
return;
const shouldBeClosed = elementTypeOptions === 'always';
if (shouldBeClosed && !node.startTag.selfClosing) {
report(node, true);
}
else if (!shouldBeClosed && node.startTag.selfClosing) {
report(node, false);
}
}
};
}
});

View File

@ -0,0 +1,6 @@
import type { AST } from 'svelte-eslint-parser';
import type { TSESTree } from '@typescript-eslint/types';
type AnyToken = AST.Token | AST.Comment;
export declare function isWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
export declare function isNotWhitespace(token: AnyToken | TSESTree.Comment | null | undefined): boolean;
export {};

View File

@ -0,0 +1,15 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isNotWhitespace = exports.isWhitespace = void 0;
function isWhitespace(token) {
return (token != null &&
((token.type === 'HTMLText' && !token.value.trim()) ||
(token.type === 'JSXText' && !token.value.trim())));
}
exports.isWhitespace = isWhitespace;
function isNotWhitespace(token) {
return (token != null &&
(token.type !== 'HTMLText' || Boolean(token.value.trim())) &&
(token.type !== 'JSXText' || Boolean(token.value.trim())));
}
exports.isNotWhitespace = isNotWhitespace;

View File

@ -0,0 +1,28 @@
import type { ASTNode, SourceCode } from '../../types';
import type { AST } from 'svelte-eslint-parser';
import type { OffsetContext } from './offset-context';
export type AnyToken = AST.Token | AST.Comment;
export type MaybeNode = {
type: string;
range: [number, number];
loc: AST.SourceLocation;
};
export type IndentOptions = {
indentChar: ' ' | '\t';
indentScript: boolean;
indentSize: number;
switchCase: number;
alignAttributesVertically: boolean;
ignoredNodes: string[];
};
export type IndentContext = {
sourceCode: SourceCode;
options: IndentOptions;
offsets: OffsetContext;
};
export declare function getFirstAndLastTokens(sourceCode: SourceCode, node: ASTNode | AnyToken | MaybeNode, borderOffset?: number): {
firstToken: AST.Token;
lastToken: AST.Token;
};
export declare function isBeginningOfLine(sourceCode: SourceCode, node: ASTNode | AnyToken | MaybeNode): boolean;
export declare function isBeginningOfElement(node: AST.SvelteText): boolean;

View File

@ -0,0 +1,55 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isBeginningOfElement = exports.isBeginningOfLine = exports.getFirstAndLastTokens = void 0;
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const ast_1 = require("./ast");
function getFirstAndLastTokens(sourceCode, node, borderOffset = 0) {
let firstToken = sourceCode.getFirstToken(node);
let lastToken = sourceCode.getLastToken(node);
let left, right;
while ((left = sourceCode.getTokenBefore(firstToken)) != null &&
(right = sourceCode.getTokenAfter(lastToken)) != null &&
(0, eslint_utils_1.isOpeningParenToken)(left) &&
(0, eslint_utils_1.isClosingParenToken)(right) &&
borderOffset <= left.range[0]) {
firstToken = left;
lastToken = right;
}
while ((0, ast_1.isWhitespace)(firstToken) && firstToken.range[0] < lastToken.range[0]) {
firstToken = sourceCode.getTokenAfter(firstToken);
}
while ((0, ast_1.isWhitespace)(lastToken) && firstToken.range[0] < lastToken.range[0]) {
lastToken = sourceCode.getTokenBefore(lastToken);
}
return { firstToken, lastToken };
}
exports.getFirstAndLastTokens = getFirstAndLastTokens;
function isBeginningOfLine(sourceCode, node) {
const prevToken = sourceCode.getTokenBefore(node, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
return !prevToken || prevToken.loc.end.line < node.loc.start.line;
}
exports.isBeginningOfLine = isBeginningOfLine;
function isBeginningOfElement(node) {
if (node.parent.type === 'SvelteElement' ||
node.parent.type === 'SvelteAwaitCatchBlock' ||
node.parent.type === 'SvelteAwaitPendingBlock' ||
node.parent.type === 'SvelteAwaitThenBlock' ||
node.parent.type === 'SvelteEachBlock' ||
node.parent.type === 'SvelteElseBlock' ||
node.parent.type === 'SvelteIfBlock' ||
node.parent.type === 'SvelteKeyBlock' ||
node.parent.type === 'SvelteStyleElement') {
return node.parent.children[0] === node;
}
if (node.parent.type === 'Program') {
return node.parent.body[0] === node;
}
return assertNever(node.parent);
}
exports.isBeginningOfElement = isBeginningOfElement;
function assertNever(value) {
throw new Error(`This part of the code should never be reached but ${value} made it through.`);
}

View File

@ -0,0 +1,5 @@
import type { IndentContext } from './commons';
import type { ESNodeListener } from '../../types-for-node';
type NodeListener = ESNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,731 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const commons_1 = require("./commons");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const ast_utils_1 = require("../../utils/ast-utils");
function defineVisitor(context) {
const { sourceCode, offsets, options } = context;
function getRootLeft(node) {
let target = node;
let parent = (0, ast_utils_1.getParent)(target);
while (parent &&
(parent.type === 'AssignmentExpression' ||
parent.type === 'AssignmentPattern' ||
parent.type === 'BinaryExpression' ||
parent.type === 'LogicalExpression')) {
const prevToken = sourceCode.getTokenBefore(target);
if (prevToken && (0, eslint_utils_1.isOpeningParenToken)(prevToken)) {
break;
}
target = parent;
parent = (0, ast_utils_1.getParent)(target);
}
return target.left;
}
const visitor = {
Program(node) {
for (const body of node.body) {
if (body.type === 'SvelteText' && !body.value.trim()) {
continue;
}
offsets.setStartOffsetToken(sourceCode.getFirstToken(body), 0);
}
},
ArrayExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getTokenAfter(node.elements[node.elements.length - 1] || firstToken, { filter: eslint_utils_1.isClosingBracketToken, includeComments: false });
offsets.setOffsetElementList(node.elements, firstToken, rightToken, 1);
},
ArrayPattern(node) {
visitor.ArrayExpression(node);
},
ArrowFunctionExpression(node) {
const [firstToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const leftToken = node.async ? secondToken : firstToken;
const arrowToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isArrowToken,
includeComments: false
});
if (node.async) {
offsets.setOffsetToken(secondToken, 1, firstToken);
}
if ((0, eslint_utils_1.isOpeningParenToken)(leftToken)) {
const rightToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftToken, rightToken, 1);
}
offsets.setOffsetToken(arrowToken, 1, firstToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
},
AssignmentExpression(node) {
const leftNode = getRootLeft(node);
const opToken = sourceCode.getTokenAfter(node.left, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.right).firstToken;
offsets.setOffsetToken([opToken, rightToken], 1, (0, commons_1.getFirstAndLastTokens)(sourceCode, leftNode).firstToken);
},
AssignmentPattern(node) {
visitor.AssignmentExpression(node);
},
BinaryExpression(node) {
visitor.AssignmentExpression(node);
},
LogicalExpression(node) {
visitor.AssignmentExpression(node);
},
AwaitExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
RestElement(node) {
visitor.AwaitExpression(node);
},
SpreadElement(node) {
visitor.AwaitExpression(node);
},
UnaryExpression(node) {
visitor.AwaitExpression(node);
},
BlockStatement(node) {
offsets.setOffsetElementList(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
ClassBody(node) {
visitor.BlockStatement(node);
},
BreakStatement(node) {
if (node.label) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
}
},
ContinueStatement(node) {
visitor.BreakStatement(node);
},
CallExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(node.typeParameters || node.callee, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
const rightParenToken = sourceCode.getLastToken(node);
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
for (const optionalToken of sourceCode.getTokensBetween(sourceCode.getLastToken(node.typeParameters || node.callee), leftParenToken, { filter: isOptionalToken, includeComments: false })) {
offsets.setOffsetToken(optionalToken, 1, firstToken);
}
offsets.setOffsetToken(leftParenToken, 1, firstToken);
offsets.setOffsetElementList(node.arguments, leftParenToken, rightParenToken, 1);
},
CatchClause(node) {
const catchToken = sourceCode.getFirstToken(node);
if (node.param != null) {
const leftParenToken = sourceCode.getTokenBefore(node.param);
const rightParenToken = sourceCode.getTokenAfter(node.param);
offsets.setOffsetToken(leftParenToken, 1, catchToken);
offsets.setOffsetElementList([node.param], leftParenToken, rightParenToken, 1);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, catchToken);
},
ClassDeclaration(node) {
const classToken = sourceCode.getFirstToken(node);
if (node.id != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.id), 1, classToken);
}
if (node.superClass != null) {
const extendsToken = sourceCode.getTokenBefore(node.superClass);
const superClassToken = sourceCode.getTokenAfter(extendsToken);
offsets.setOffsetToken(extendsToken, 1, classToken);
offsets.setOffsetToken(superClassToken, 1, extendsToken);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, classToken);
},
ClassExpression(node) {
visitor.ClassDeclaration(node);
},
ConditionalExpression(node) {
const questionToken = sourceCode.getTokenAfter(node.test, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const consequentToken = sourceCode.getTokenAfter(questionToken);
const colonToken = sourceCode.getTokenAfter(node.consequent, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const alternateToken = sourceCode.getTokenAfter(colonToken);
let baseNode = node;
let parent = (0, ast_utils_1.getParent)(baseNode);
while (parent && parent.type === 'ConditionalExpression' && parent.alternate === baseNode) {
baseNode = parent;
parent = (0, ast_utils_1.getParent)(baseNode);
}
const baseToken = sourceCode.getFirstToken(baseNode);
offsets.setOffsetToken([questionToken, colonToken], 1, baseToken);
offsets.setOffsetToken(consequentToken, 1, questionToken);
offsets.setOffsetToken(alternateToken, 1, colonToken);
},
DoWhileStatement(node) {
const doToken = sourceCode.getFirstToken(node);
const whileToken = sourceCode.getTokenAfter(node.body, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const leftParenToken = sourceCode.getTokenAfter(whileToken);
const rightParenToken = sourceCode.getTokenAfter(node.test);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, doToken);
offsets.setOffsetToken(whileToken, 0, doToken);
offsets.setOffsetToken(leftParenToken, 1, whileToken);
offsets.setOffsetElementList([node.test], leftParenToken, rightParenToken, 1);
},
ExportAllDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
const tokens = sourceCode.getTokensBetween(exportToken, node.source);
const fromIndex = tokens.findIndex((t) => t.value === 'from');
const fromToken = tokens[fromIndex];
const beforeTokens = tokens.slice(0, fromIndex);
const afterTokens = [...tokens.slice(fromIndex + 1), sourceCode.getFirstToken(node.source)];
if (!node.exported) {
offsets.setOffsetToken(beforeTokens, 1, exportToken);
}
else {
const asIndex = beforeTokens.findIndex((t) => t.value === 'as');
offsets.setOffsetToken(beforeTokens.slice(0, asIndex), 1, exportToken);
offsets.setOffsetToken(beforeTokens.slice(asIndex), 1, beforeTokens[asIndex - 1]);
}
offsets.setOffsetToken(fromToken, 0, exportToken);
offsets.setOffsetToken(afterTokens, 1, fromToken);
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, exportToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
},
ExportDefaultDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
const declarationToken = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.declaration).firstToken;
const defaultTokens = sourceCode.getTokensBetween(exportToken, declarationToken);
offsets.setOffsetToken([...defaultTokens, declarationToken], 1, exportToken);
},
ExportNamedDeclaration(node) {
const exportToken = sourceCode.getFirstToken(node);
if (node.declaration) {
const declarationToken = sourceCode.getFirstToken(node.declaration);
offsets.setOffsetToken(declarationToken, 1, exportToken);
}
else {
const firstSpecifier = node.specifiers[0];
if (!firstSpecifier || firstSpecifier.type === 'ExportSpecifier') {
const leftBraceTokens = firstSpecifier
? sourceCode.getTokensBetween(exportToken, firstSpecifier)
: [sourceCode.getTokenAfter(exportToken)];
const rightBraceToken = node.source
? sourceCode.getTokenBefore(node.source, {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
})
: sourceCode.getLastToken(node, {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
});
offsets.setOffsetToken(leftBraceTokens, 0, exportToken);
offsets.setOffsetElementList(node.specifiers, leftBraceTokens[leftBraceTokens.length - 1], rightBraceToken, 1);
if (node.source) {
const [fromToken, ...tokens] = sourceCode.getTokensBetween(rightBraceToken, node.source);
offsets.setOffsetToken(fromToken, 0, exportToken);
offsets.setOffsetToken([...tokens, sourceCode.getFirstToken(node.source)], 1, fromToken);
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, exportToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
}
}
else {
}
}
},
ExportSpecifier(node) {
const tokens = sourceCode.getTokens(node);
let firstToken = tokens.shift();
if (firstToken.value === 'type') {
const typeToken = firstToken;
firstToken = tokens.shift();
offsets.setOffsetToken(firstToken, 0, typeToken);
}
offsets.setOffsetToken(tokens, 1, firstToken);
},
ForInStatement(node) {
const forToken = sourceCode.getFirstToken(node);
const awaitToken = (node.type === 'ForOfStatement' && node.await && sourceCode.getTokenAfter(forToken)) ||
null;
const leftParenToken = sourceCode.getTokenAfter(awaitToken || forToken);
const leftToken = sourceCode.getFirstToken(node.left);
const inOrOfToken = sourceCode.getTokenAfter(node.left, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = sourceCode.getTokenAfter(inOrOfToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isNotOpeningParenToken,
includeComments: false
});
if (awaitToken != null) {
offsets.setOffsetToken(awaitToken, 0, forToken);
}
offsets.setOffsetToken(leftParenToken, 1, forToken);
offsets.setOffsetToken(leftToken, 1, leftParenToken);
offsets.setOffsetToken([inOrOfToken, rightToken], 1, leftToken);
offsets.setOffsetToken(rightParenToken, 0, leftParenToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, forToken);
},
ForOfStatement(node) {
visitor.ForInStatement(node);
},
ForStatement(node) {
const forToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(forToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isNotOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, forToken);
offsets.setOffsetElementList([node.init, node.test, node.update], leftParenToken, rightParenToken, 1);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, forToken);
},
FunctionDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenBefore(node.params[0] ||
node.returnType ||
sourceCode.getTokenBefore(node.body), {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
let bodyBaseToken = null;
if (firstToken.type === 'Punctuator') {
bodyBaseToken = sourceCode.getFirstToken((0, ast_utils_1.getParent)(node));
}
else {
let tokenOffset = 0;
for (const token of sourceCode.getTokensBetween(firstToken, leftParenToken)) {
if (token.value === '<') {
break;
}
if (token.value === '*' || (node.id && token.range[0] === node.id.range[0])) {
tokenOffset = 1;
}
offsets.setOffsetToken(token, tokenOffset, firstToken);
}
bodyBaseToken = firstToken;
}
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetToken(leftParenToken, 1, bodyBaseToken);
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, bodyBaseToken);
},
FunctionExpression(node) {
visitor.FunctionDeclaration(node);
},
IfStatement(node) {
const [ifToken, ifLeftParenToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const ifRightParenToken = sourceCode.getTokenBefore(node.consequent, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(ifLeftParenToken, 1, ifToken);
offsets.setOffsetToken(ifRightParenToken, 0, ifLeftParenToken);
const consequentFirstToken = sourceCode.getFirstToken(node.consequent);
offsets.setOffsetToken(consequentFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(consequentFirstToken) ? 0 : 1, ifToken);
if (node.alternate != null) {
const elseToken = sourceCode.getTokenAfter(node.consequent, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(elseToken, 0, ifToken);
const alternateFirstToken = sourceCode.getFirstToken(node.alternate);
offsets.setOffsetToken(alternateFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(alternateFirstToken) ? 0 : 1, elseToken);
}
},
ImportDeclaration(node) {
const importToken = sourceCode.getFirstToken(node);
const tokens = sourceCode.getTokensBetween(importToken, node.source);
const fromIndex = tokens.map((t) => t.value).lastIndexOf('from');
const { fromToken, beforeTokens, afterTokens } = fromIndex >= 0
? {
fromToken: tokens[fromIndex],
beforeTokens: tokens.slice(0, fromIndex),
afterTokens: [...tokens.slice(fromIndex + 1), sourceCode.getFirstToken(node.source)]
}
: {
fromToken: null,
beforeTokens: [...tokens, sourceCode.getFirstToken(node.source)],
afterTokens: []
};
const namedSpecifiers = [];
for (const specifier of node.specifiers) {
if (specifier.type === 'ImportSpecifier') {
namedSpecifiers.push(specifier);
}
else {
const removeTokens = sourceCode.getTokens(specifier);
removeTokens.shift();
for (const token of removeTokens) {
const i = beforeTokens.indexOf(token);
if (i >= 0) {
beforeTokens.splice(i, 1);
}
}
}
}
if (namedSpecifiers.length) {
const leftBrace = sourceCode.getTokenBefore(namedSpecifiers[0]);
const rightBrace = sourceCode.getTokenAfter(namedSpecifiers[namedSpecifiers.length - 1], {
filter: eslint_utils_1.isClosingBraceToken,
includeComments: false
});
offsets.setOffsetElementList(namedSpecifiers, leftBrace, rightBrace, 1);
for (const token of [...sourceCode.getTokensBetween(leftBrace, rightBrace), rightBrace]) {
const i = beforeTokens.indexOf(token);
if (i >= 0) {
beforeTokens.splice(i, 1);
}
}
}
if (beforeTokens.every((t) => (0, eslint_utils_1.isOpeningBraceToken)(t) || (0, eslint_utils_1.isClosingBraceToken)(t))) {
offsets.setOffsetToken(beforeTokens, 0, importToken);
}
else {
offsets.setOffsetToken(beforeTokens, 1, importToken);
}
if (fromToken) {
offsets.setOffsetToken(fromToken, 0, importToken);
offsets.setOffsetToken(afterTokens, 1, fromToken);
}
const lastToken = sourceCode.getLastToken(node, {
filter: eslint_utils_1.isNotSemicolonToken,
includeComments: false
});
const assertionTokens = sourceCode.getTokensBetween(node.source, lastToken);
if (assertionTokens.length) {
const assertToken = assertionTokens.shift();
offsets.setOffsetToken(assertToken, 0, importToken);
const assertionOpen = assertionTokens.shift();
if (assertionOpen) {
offsets.setOffsetToken(assertionOpen, 1, assertToken);
offsets.setOffsetElementList(assertionTokens, assertionOpen, lastToken, 1);
}
}
},
ImportExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getLastToken(node);
const leftToken = sourceCode.getTokenAfter(firstToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftToken, 1, firstToken);
offsets.setOffsetElementList([node.source], leftToken, rightToken, 1);
},
ImportNamespaceSpecifier(node) {
const tokens = sourceCode.getTokens(node);
const firstToken = tokens.shift();
offsets.setOffsetToken(tokens, 1, firstToken);
},
ImportSpecifier(node) {
visitor.ExportSpecifier(node);
},
LabeledStatement(node) {
const labelToken = sourceCode.getFirstToken(node);
const colonToken = sourceCode.getTokenAfter(labelToken);
const bodyToken = sourceCode.getTokenAfter(colonToken);
offsets.setOffsetToken([colonToken, bodyToken], 1, labelToken);
},
SvelteReactiveStatement(node) {
visitor.LabeledStatement(node);
},
MemberExpression(node) {
const objectToken = sourceCode.getFirstToken(node);
if (node.type === 'MemberExpression' && node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(node.property, {
filter: eslint_utils_1.isOpeningBracketToken,
includeComments: false
});
const rightBracketToken = sourceCode.getTokenAfter(node.property, {
filter: eslint_utils_1.isClosingBracketToken,
includeComments: false
});
for (const optionalToken of sourceCode.getTokensBetween(sourceCode.getLastToken(node.object), leftBracketToken, { filter: isOptionalToken, includeComments: false })) {
offsets.setOffsetToken(optionalToken, 1, objectToken);
}
offsets.setOffsetToken(leftBracketToken, 1, objectToken);
offsets.setOffsetElementList([node.property], leftBracketToken, rightBracketToken, 1);
}
else {
const dotToken = sourceCode.getTokenBefore(node.property);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, objectToken);
}
},
MetaProperty(node) {
visitor.MemberExpression(node);
},
MethodDefinition(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.key);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([node.key], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (node.value) {
const initToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
Property(node) {
visitor.MethodDefinition(node);
},
NewExpression(node) {
const newToken = sourceCode.getFirstToken(node);
const calleeTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.callee);
offsets.setOffsetToken(calleeTokens.firstToken, 1, newToken);
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, calleeTokens.firstToken);
}
const leftParenBefore = node.typeParameters || calleeTokens.lastToken;
if (node.arguments.length || leftParenBefore.range[1] < node.range[1]) {
const rightParenToken = sourceCode.getLastToken(node);
const leftParenToken = sourceCode.getTokenAfter(leftParenBefore);
offsets.setOffsetToken(leftParenToken, 1, calleeTokens.firstToken);
offsets.setOffsetElementList(node.arguments, leftParenToken, rightParenToken, 1);
}
},
ObjectExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const rightToken = sourceCode.getTokenAfter(node.properties[node.properties.length - 1] || firstToken, { filter: eslint_utils_1.isClosingBraceToken, includeComments: false });
offsets.setOffsetElementList(node.properties, firstToken, rightToken, 1);
},
ObjectPattern(node) {
visitor.ObjectExpression(node);
},
PropertyDefinition(node) {
visitor.MethodDefinition(node);
},
ReturnStatement(node) {
if (node.argument) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
}
},
ThrowStatement(node) {
visitor.ReturnStatement(node);
},
SequenceExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetElementList(node.expressions, firstToken, null, 0);
},
SwitchCase(node) {
const caseToken = sourceCode.getFirstToken(node);
if (node.test != null) {
const testTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.test);
const colonToken = sourceCode.getTokenAfter(testTokens.lastToken);
offsets.setOffsetToken([testTokens.firstToken, colonToken], 1, caseToken);
}
else {
const colonToken = sourceCode.getTokenAfter(caseToken);
offsets.setOffsetToken(colonToken, 1, caseToken);
}
if (node.consequent.length === 1 && node.consequent[0].type === 'BlockStatement') {
offsets.setOffsetToken(sourceCode.getFirstToken(node.consequent[0]), 0, caseToken);
}
else {
for (const statement of node.consequent) {
offsets.setOffsetToken((0, commons_1.getFirstAndLastTokens)(sourceCode, statement).firstToken, 1, caseToken);
}
}
},
SwitchStatement(node) {
const switchToken = sourceCode.getFirstToken(node);
const { firstToken: leftParenToken, lastToken: rightParenToken } = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.discriminant);
const leftBraceToken = sourceCode.getTokenAfter(rightParenToken);
const rightBraceToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftParenToken, 1, switchToken);
offsets.setOffsetElementList([node.discriminant], leftParenToken, rightParenToken, 1);
offsets.setOffsetToken(leftBraceToken, 0, switchToken);
offsets.setOffsetElementList(node.cases, leftBraceToken, rightBraceToken, options.switchCase);
},
TaggedTemplateExpression(node) {
const tagTokens = (0, commons_1.getFirstAndLastTokens)(sourceCode, node.tag);
offsets.setOffsetToken(sourceCode.getFirstToken(node.quasi), 1, tagTokens.firstToken);
},
TemplateLiteral(node) {
const firstToken = sourceCode.getFirstToken(node);
const quasiTokens = node.quasis.slice(1).map((n) => sourceCode.getFirstToken(n));
const expressionToken = node.quasis.slice(0, -1).map((n) => sourceCode.getTokenAfter(n));
offsets.setOffsetToken(quasiTokens, 0, firstToken);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
TryStatement(node) {
const tryToken = sourceCode.getFirstToken(node);
const tryBlockToken = sourceCode.getFirstToken(node.block);
offsets.setOffsetToken(tryBlockToken, 0, tryToken);
if (node.handler != null) {
const catchToken = sourceCode.getFirstToken(node.handler);
offsets.setOffsetToken(catchToken, 0, tryToken);
}
if (node.finalizer != null) {
const finallyToken = sourceCode.getTokenBefore(node.finalizer);
const finallyBlockToken = sourceCode.getFirstToken(node.finalizer);
offsets.setOffsetToken([finallyToken, finallyBlockToken], 0, tryToken);
}
},
UpdateExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
VariableDeclaration(node) {
offsets.setOffsetElementList(node.declarations, sourceCode.getFirstToken(node), null, 1);
},
VariableDeclarator(node) {
if (node.init != null) {
const idToken = sourceCode.getFirstToken(node);
const eqToken = sourceCode.getTokenAfter(node.id);
const initToken = sourceCode.getTokenAfter(eqToken);
offsets.setOffsetToken([eqToken, initToken], 1, idToken);
}
},
WhileStatement(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(firstToken);
const rightParenToken = sourceCode.getTokenBefore(node.body, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, firstToken);
offsets.setOffsetToken(rightParenToken, 0, leftParenToken);
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
},
WithStatement(node) {
visitor.WhileStatement(node);
},
YieldExpression(node) {
if (node.argument != null) {
const [yieldToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(secondToken, 1, yieldToken);
if (node.delegate) {
offsets.setOffsetToken(sourceCode.getTokenAfter(secondToken), 1, yieldToken);
}
}
},
DebuggerStatement() {
},
Identifier() {
},
ImportDefaultSpecifier() {
},
Literal() {
},
PrivateIdentifier() {
},
Super() {
},
TemplateElement() {
},
ThisExpression() {
},
ExpressionStatement() {
},
ChainExpression() {
},
EmptyStatement() {
}
};
const commonVisitor = {
':statement, PropertyDefinition'(node) {
const firstToken = sourceCode.getFirstToken(node);
const lastToken = sourceCode.getLastToken(node);
if ((0, eslint_utils_1.isSemicolonToken)(lastToken) && firstToken !== lastToken) {
const next = sourceCode.getTokenAfter(lastToken);
if (!next || lastToken.loc.start.line < next.loc.start.line) {
offsets.setOffsetToken(lastToken, 0, firstToken);
}
}
},
':expression'(node) {
let leftToken = sourceCode.getTokenBefore(node);
let rightToken = sourceCode.getTokenAfter(node);
let firstToken = sourceCode.getFirstToken(node);
while (leftToken &&
(0, eslint_utils_1.isOpeningParenToken)(leftToken) &&
rightToken &&
(0, eslint_utils_1.isClosingParenToken)(rightToken)) {
offsets.setOffsetToken(firstToken, 1, leftToken);
offsets.setOffsetToken(rightToken, 0, leftToken);
firstToken = leftToken;
leftToken = sourceCode.getTokenBefore(leftToken);
rightToken = sourceCode.getTokenAfter(rightToken);
}
}
};
const v = visitor;
return {
...v,
...commonVisitor
};
}
exports.defineVisitor = defineVisitor;
function isOptionalToken(token) {
return token.type === 'Punctuator' && token.value === '?.';
}

View File

@ -0,0 +1,3 @@
import type { RuleContext, RuleListener } from '../../types';
import type { IndentOptions } from './commons';
export declare function defineVisitor(context: RuleContext, defaultOptions: Partial<IndentOptions>): RuleListener;

View File

@ -0,0 +1,235 @@
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k);
__setModuleDefault(result, mod);
return result;
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const SV = __importStar(require("./svelte"));
const ES = __importStar(require("./es"));
const TS = __importStar(require("./ts"));
const ast_1 = require("./ast");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const offset_context_1 = require("./offset-context");
const compat_1 = require("../../utils/compat");
function parseOptions(options, defaultOptions) {
const ret = {
indentChar: ' ',
indentScript: true,
indentSize: 2,
switchCase: 1,
alignAttributesVertically: false,
ignoredNodes: [],
...defaultOptions
};
if (Number.isSafeInteger(options.indent)) {
ret.indentSize = Number(options.indent);
}
else if (options.indent === 'tab') {
ret.indentChar = '\t';
ret.indentSize = 1;
}
if (typeof options.indentScript === 'boolean') {
ret.indentScript = options.indentScript;
}
if (options.switchCase != null && Number.isSafeInteger(options.switchCase)) {
ret.switchCase = options.switchCase;
}
if (options.ignoredNodes != null) {
ret.ignoredNodes = options.ignoredNodes;
}
if (options.alignAttributesVertically && ret.indentChar === ' ') {
ret.alignAttributesVertically = true;
}
else if (ret.indentChar !== ' ') {
ret.alignAttributesVertically = false;
}
return ret;
}
function defineVisitor(context, defaultOptions) {
if (!(0, compat_1.getFilename)(context).endsWith('.svelte'))
return {};
const options = parseOptions(context.options[0] || {}, defaultOptions);
const sourceCode = (0, compat_1.getSourceCode)(context);
const offsets = new offset_context_1.OffsetContext({ sourceCode, options });
function getIndentText({ line, column }) {
return sourceCode.lines[line - 1].slice(0, column);
}
function validateToken(token, expectedIndent) {
const line = token.loc.start.line;
const indentText = getIndentText(token.loc.start);
if (indentText.trim() !== '') {
return;
}
const actualIndent = token.loc.start.column;
const mismatchCharIndexes = [];
for (let i = 0; i < indentText.length; ++i) {
if (indentText[i] !== options.indentChar) {
mismatchCharIndexes.push(i);
}
}
if (actualIndent !== expectedIndent) {
const loc = {
start: { line, column: 0 },
end: { line, column: actualIndent }
};
context.report({
loc,
messageId: 'unexpectedIndentation',
data: {
expectedIndent: String(expectedIndent),
actualIndent: String(actualIndent),
expectedUnit: options.indentChar === '\t' ? 'tab' : 'space',
actualUnit: mismatchCharIndexes.length
? 'whitespace'
: options.indentChar === '\t'
? 'tab'
: 'space',
expectedIndentPlural: expectedIndent === 1 ? '' : 's',
actualIndentPlural: actualIndent === 1 ? '' : 's'
},
fix(fixer) {
return fixer.replaceTextRange([sourceCode.getIndexFromLoc(loc.start), sourceCode.getIndexFromLoc(loc.end)], options.indentChar.repeat(expectedIndent));
}
});
return;
}
for (const i of mismatchCharIndexes) {
const loc = {
start: { line, column: i },
end: { line, column: i + 1 }
};
context.report({
loc,
messageId: 'unexpectedChar',
data: {
expected: JSON.stringify(options.indentChar),
actual: JSON.stringify(indentText[i])
},
fix(fixer) {
return fixer.replaceTextRange([sourceCode.getIndexFromLoc(loc.start), sourceCode.getIndexFromLoc(loc.end)], options.indentChar);
}
});
}
}
function processLine(tokens, prevComments, prevToken, calculator) {
const firstToken = tokens[0];
const actualIndent = firstToken.loc.start.column;
const expectedIndent = calculator.getExpectedIndentFromTokens(tokens);
if (expectedIndent == null) {
calculator.saveExpectedIndent(tokens, actualIndent);
return;
}
calculator.saveExpectedIndent(tokens, Math.min(...tokens
.map((t) => calculator.getExpectedIndentFromToken(t))
.filter((i) => i != null)));
let prev = prevToken;
if (prevComments.length) {
if (prev && prev.loc.end.line < prevComments[0].loc.start.line) {
validateToken(prevComments[0], expectedIndent);
}
prev = prevComments[prevComments.length - 1];
}
if (prev && prev.loc.end.line < tokens[0].loc.start.line) {
validateToken(tokens[0], expectedIndent);
}
}
const indentContext = {
sourceCode,
options,
offsets
};
const nodesVisitor = {
...ES.defineVisitor(indentContext),
...SV.defineVisitor(indentContext),
...TS.defineVisitor(indentContext)
};
const knownNodes = new Set(Object.keys(nodesVisitor));
function compositingIgnoresVisitor(visitor) {
for (const ignoreSelector of options.ignoredNodes) {
const key = `${ignoreSelector}:exit`;
if (visitor[key]) {
const handler = visitor[key];
visitor[key] = function (node, ...args) {
const ret = handler.call(this, node, ...args);
offsets.ignore(node);
return ret;
};
}
else {
visitor[key] = (node) => offsets.ignore(node);
}
}
return visitor;
}
return compositingIgnoresVisitor({
...nodesVisitor,
'*:exit'(node) {
if (!knownNodes.has(node.type)) {
offsets.ignore(node);
}
},
'Program:exit'(node) {
const calculator = offsets.getOffsetCalculator();
let prevToken = null;
for (const { prevComments, tokens } of iterateLineTokens()) {
processLine(tokens, prevComments, prevToken, calculator);
prevToken = tokens[tokens.length - 1];
}
function* iterateLineTokens() {
let line = 0;
let prevComments = [];
let bufferTokens = [];
for (const token of sourceCode.getTokens(node, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) {
const thisLine = token.loc.start.line;
if (line === thisLine || bufferTokens.length === 0) {
bufferTokens.push(token);
}
else {
if ((0, eslint_utils_1.isCommentToken)(bufferTokens[0]) && bufferTokens.every(eslint_utils_1.isCommentToken)) {
prevComments.push(bufferTokens[0]);
}
else {
yield {
prevComments,
tokens: bufferTokens
};
prevComments = [];
}
bufferTokens = [token];
}
line = thisLine;
}
if (bufferTokens.length && !bufferTokens.every(eslint_utils_1.isCommentToken)) {
yield {
prevComments,
tokens: bufferTokens
};
}
}
}
});
}
exports.defineVisitor = defineVisitor;

View File

@ -0,0 +1,57 @@
import type { ASTNode, SourceCode } from '../../types';
import type { AnyToken, IndentOptions, MaybeNode } from './commons';
declare const enum OffsetDataType {
normal = 0,
align = 1,
start = 2
}
type OffsetData = {
type: OffsetDataType.normal;
base: number;
offset: number;
expectedIndent?: number;
} | {
type: OffsetDataType.align;
base: number;
alignIndent: number;
expectedIndent?: number;
} | {
type: OffsetDataType.start;
offset: number;
expectedIndent?: number;
};
export declare class OffsetContext {
private readonly sourceCode;
private readonly options;
private readonly offsets;
private readonly ignoreRanges;
constructor(arg: {
sourceCode: SourceCode;
options: IndentOptions;
});
setOffsetIndex(index: number, offset: number, base: number): void;
private setAlignIndent;
setOffsetToken(token: AnyToken | null | undefined | (AnyToken | null | undefined)[], offset: number, baseToken: AnyToken): void;
copyOffset(index: number, srcIndex: number): void;
setStartOffsetIndex(index: number, offset: number): void;
setStartOffsetToken(token: AnyToken | null | undefined | (AnyToken | null | undefined)[], offset: number): void;
setOffsetElementList(nodes: (ASTNode | AnyToken | MaybeNode | null | undefined)[], baseNodeOrToken: ASTNode | AnyToken | MaybeNode, lastNodeOrToken: ASTNode | AnyToken | MaybeNode | null, offset: number, align?: boolean): void;
private _setOffsetElementList;
ignore(node: ASTNode): void;
getOffsetCalculator(): OffsetCalculator;
}
export declare class OffsetCalculator {
private readonly options;
private readonly offsets;
private readonly ignoreRanges;
constructor(arg: {
offsets: Map<number, OffsetData>;
options: IndentOptions;
ignoreRanges: [number, number][];
});
private getExpectedIndentFromIndex;
getExpectedIndentFromToken(token: AnyToken): number | null;
getExpectedIndentFromTokens(tokens: AnyToken[]): null | number;
saveExpectedIndent(tokens: AnyToken[], expectedIndent: number): void;
}
export {};

View File

@ -0,0 +1,193 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.OffsetCalculator = exports.OffsetContext = void 0;
const ast_1 = require("./ast");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
class OffsetContext {
constructor(arg) {
this.offsets = new Map();
this.ignoreRanges = new Map();
this.sourceCode = arg.sourceCode;
this.options = arg.options;
}
setOffsetIndex(index, offset, base) {
if (index === base) {
return;
}
this.offsets.set(index, {
type: 0,
base,
offset
});
}
setAlignIndent(index, alignIndent, base) {
if (index === base) {
return;
}
this.offsets.set(index, {
type: 1,
base,
alignIndent
});
}
setOffsetToken(token, offset, baseToken) {
if (!token) {
return;
}
if (Array.isArray(token)) {
for (const t of token) {
this.setOffsetToken(t, offset, baseToken);
}
return;
}
this.setOffsetIndex(token.range[0], offset, baseToken.range[0]);
}
copyOffset(index, srcIndex) {
const offsetData = this.offsets.get(srcIndex);
if (!offsetData) {
return;
}
if (offsetData.type === 2) {
this.setStartOffsetIndex(index, offsetData.offset);
}
else if (offsetData.type === 1) {
this.setAlignIndent(index, offsetData.alignIndent, offsetData.base);
}
else {
this.setOffsetIndex(index, offsetData.offset, offsetData.base);
}
}
setStartOffsetIndex(index, offset) {
this.offsets.set(index, {
type: 2,
offset
});
}
setStartOffsetToken(token, offset) {
if (!token) {
return;
}
if (Array.isArray(token)) {
for (const t of token) {
this.setStartOffsetToken(t, offset);
}
return;
}
this.setStartOffsetIndex(token.range[0], offset);
}
setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, offset, align) {
let setIndent = (token, baseToken) => this.setOffsetToken(token, offset, baseToken);
if (align) {
for (const n of nodes) {
if (n) {
if (!(0, commons_1.isBeginningOfLine)(this.sourceCode, n)) {
const startLoc = n.loc.start;
const alignIndent = startLoc.column - /^\s*/u.exec(this.sourceCode.lines[startLoc.line - 1])[0].length;
setIndent = (token, baseToken) => this.setAlignIndent(token.range[0], alignIndent, baseToken.range[0]);
}
break;
}
}
}
this._setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, setIndent);
}
_setOffsetElementList(nodes, baseNodeOrToken, lastNodeOrToken, setIndent) {
const baseToken = this.sourceCode.getFirstToken(baseNodeOrToken);
let prevToken = this.sourceCode.getLastToken(baseNodeOrToken);
for (const node of nodes) {
if (node == null) {
continue;
}
const elementTokens = (0, commons_2.getFirstAndLastTokens)(this.sourceCode, node, prevToken.range[1]);
let t = prevToken;
while ((t = this.sourceCode.getTokenAfter(t, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) != null &&
t.range[1] <= elementTokens.firstToken.range[0]) {
setIndent(t, baseToken);
}
setIndent(elementTokens.firstToken, baseToken);
prevToken = elementTokens.lastToken;
}
if (lastNodeOrToken) {
const lastToken = this.sourceCode.getFirstToken(lastNodeOrToken);
let t = prevToken;
while ((t = this.sourceCode.getTokenAfter(t, {
includeComments: true,
filter: ast_1.isNotWhitespace
})) != null &&
t.range[1] <= lastToken.range[0]) {
setIndent(t, baseToken);
}
this.setOffsetToken(lastToken, 0, baseToken);
}
}
ignore(node) {
const range = node.range;
const n = this.ignoreRanges.get(range[0]) ?? 0;
this.ignoreRanges.set(range[0], Math.max(n, range[1]));
}
getOffsetCalculator() {
return new OffsetCalculator({
offsets: this.offsets,
options: this.options,
ignoreRanges: [...this.ignoreRanges]
});
}
}
exports.OffsetContext = OffsetContext;
class OffsetCalculator {
constructor(arg) {
this.offsets = arg.offsets;
this.options = arg.options;
this.ignoreRanges = arg.ignoreRanges;
}
getExpectedIndentFromIndex(index) {
const offsetInfo = this.offsets.get(index);
if (offsetInfo == null) {
return null;
}
if (offsetInfo.expectedIndent != null) {
return offsetInfo.expectedIndent;
}
if (offsetInfo.type === 2) {
return offsetInfo.offset * this.options.indentSize;
}
const baseIndent = this.getExpectedIndentFromIndex(offsetInfo.base);
if (baseIndent == null) {
return null;
}
if (offsetInfo.type === 1) {
return baseIndent + offsetInfo.alignIndent;
}
return baseIndent + offsetInfo.offset * this.options.indentSize;
}
getExpectedIndentFromToken(token) {
return this.getExpectedIndentFromIndex(token.range[0]);
}
getExpectedIndentFromTokens(tokens) {
for (const token of tokens) {
const index = token.range[0];
if (this.ignoreRanges.some(([f, t]) => f <= index && index < t)) {
return null;
}
const expectedIndent = this.getExpectedIndentFromIndex(index);
if (expectedIndent != null) {
return expectedIndent;
}
}
return null;
}
saveExpectedIndent(tokens, expectedIndent) {
for (const token of tokens) {
const offsetInfo = this.offsets.get(token.range[0]);
if (offsetInfo == null) {
continue;
}
offsetInfo.expectedIndent = offsetInfo.expectedIndent ?? expectedIndent;
}
}
}
exports.OffsetCalculator = OffsetCalculator;

View File

@ -0,0 +1,5 @@
import type { SvelteNodeListener } from '../../types-for-node';
import type { IndentContext } from './commons';
type NodeListener = SvelteNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,378 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const ast_1 = require("./ast");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
const commons_3 = require("./commons");
const PREFORMATTED_ELEMENT_NAMES = ['pre', 'textarea', 'template'];
function defineVisitor(context) {
const { sourceCode, offsets, options } = context;
const visitor = {
SvelteScriptElement(node) {
offsets.setOffsetElementList(node.body, node.startTag, node.endTag, options.indentScript ? 1 : 0);
},
SvelteStyleElement(node) {
node.children.forEach((n) => offsets.ignore(n));
},
SvelteElement(node) {
if (node.name.type === 'Identifier' || node.name.type === 'SvelteName') {
if (PREFORMATTED_ELEMENT_NAMES.includes(node.name.name)) {
const startTagToken = sourceCode.getFirstToken(node);
const endTagToken = node.endTag && sourceCode.getFirstToken(node.endTag);
offsets.setOffsetToken(endTagToken, 0, startTagToken);
node.children.forEach((n) => offsets.ignore(n));
return;
}
if (node.name.name === 'style') {
node.children.forEach((n) => offsets.ignore(n));
return;
}
}
if (node.endTag) {
offsets.setOffsetElementList(node.children.filter(isNotEmptyTextNode), node.startTag, node.endTag, 1);
}
},
SvelteStartTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList(node.attributes, openToken, closeToken, 1, options.alignAttributesVertically);
if (node.selfClosing) {
const slash = sourceCode.getTokenBefore(closeToken);
if (slash.value === '/') {
offsets.setOffsetToken(slash, 0, openToken);
}
}
},
SvelteEndTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([], openToken, closeToken, 1);
},
SvelteAttribute(node) {
const keyToken = sourceCode.getFirstToken(node);
const eqToken = sourceCode.getTokenAfter(node.key);
if (eqToken != null && eqToken.range[1] <= node.range[1]) {
offsets.setOffsetToken(eqToken, 1, keyToken);
const valueStartToken = sourceCode.getTokenAfter(eqToken);
if (valueStartToken != null && valueStartToken.range[1] <= node.range[1]) {
offsets.setOffsetToken(valueStartToken, 1, keyToken);
const values = node.type === 'SvelteAttribute' || node.type === 'SvelteStyleDirective'
? node.value
: [];
let processedValues = false;
if (valueStartToken.type === 'Punctuator') {
const quoted = ['"', "'"].includes(valueStartToken.value);
const mustache = !quoted && valueStartToken.value === '{';
if (quoted || mustache) {
const last = sourceCode.getLastToken(node);
if (last.type === 'Punctuator' &&
((quoted && last.value === valueStartToken.value) ||
(mustache && last.value === '}'))) {
offsets.setOffsetToken(last, 0, valueStartToken);
offsets.setOffsetElementList(values, valueStartToken, last, 1);
processedValues = true;
}
}
}
if (!processedValues) {
for (const val of values) {
const token = sourceCode.getFirstToken(val);
offsets.setOffsetToken(token, 0, valueStartToken);
}
}
}
}
},
SvelteDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteStyleDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteSpecialDirective(node) {
visitor.SvelteAttribute(node);
},
SvelteShorthandAttribute(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([], openToken, closeToken, 1);
},
SvelteSpreadAttribute(node) {
visitor.SvelteShorthandAttribute(node);
},
SvelteDirectiveKey(_node) {
},
SvelteSpecialDirectiveKey(_node) {
},
SvelteText(node) {
const tokens = sourceCode.getTokens(node, {
filter: ast_1.isNotWhitespace,
includeComments: false
});
const first = tokens.shift();
if (!first) {
return;
}
offsets.setOffsetToken(tokens, (0, commons_2.isBeginningOfLine)(sourceCode, first) ? 0 : (0, commons_1.isBeginningOfElement)(node) ? 1 : 0, first);
},
SvelteLiteral(node) {
const tokens = sourceCode.getTokens(node, {
filter: ast_1.isNotWhitespace,
includeComments: false
});
const first = tokens.shift();
if (!first) {
return;
}
offsets.setOffsetToken(tokens, (0, commons_2.isBeginningOfLine)(sourceCode, first) ? 0 : 1, first);
},
SvelteMustacheTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList([node.expression], openToken, closeToken, 1);
},
SvelteDebugTag(node) {
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetElementList(node.identifiers, openToken, closeToken, 1);
},
SvelteConstTag(node) {
const openToken = sourceCode.getFirstToken(node);
const constToken = sourceCode.getTokenAfter(openToken);
const declarationToken = sourceCode.getFirstToken(node.declaration);
const closeToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(constToken, 1, openToken);
offsets.setOffsetToken(declarationToken, 1, openToken);
offsets.setOffsetToken(closeToken, 0, openToken);
},
SvelteIfBlock(node) {
const [openToken, ...ifTokens] = sourceCode.getFirstTokens(node, {
count: node.elseif ? 3 : 2,
includeComments: false
});
offsets.setOffsetToken(ifTokens, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, ifTokens[0]);
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
if (node.else) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.else), 0, openToken);
if (node.else.elseif) {
return;
}
}
const [openCloseTagToken, endIfToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endIfToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteElseBlock(node) {
if (node.elseif) {
return;
}
const [openToken, elseToken, closeToken] = sourceCode.getFirstTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(elseToken, 1, openToken);
offsets.setOffsetToken(closeToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteEachBlock(node) {
const [openToken, eachToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(eachToken, 1, openToken);
offsets.setOffsetElementList([node.expression, node.context, node.index], eachToken, null, 1);
if (node.key) {
const key = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.key);
offsets.setOffsetToken(key.firstToken, 1, eachToken);
const closeOpenTagToken = sourceCode.getTokenAfter(key.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
const closeOpenTagToken = sourceCode.getTokenAfter(node.index || node.context);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
if (node.else) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.else), 0, openToken);
}
const [openCloseTagToken, endEachToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endEachToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteAwaitBlock(node) {
const [openToken, awaitToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(awaitToken, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, awaitToken);
if (node.pending) {
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
offsets.setOffsetToken(sourceCode.getFirstToken(node.pending, {
includeComments: false,
filter: ast_1.isNotWhitespace
}), 1, openToken);
}
if (node.then) {
if (node.kind === 'await-then') {
const thenToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(thenToken, 1, openToken);
if (node.then.value) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.then.value), 1, thenToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.then.value || thenToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
offsets.setOffsetToken(sourceCode.getFirstToken(node.then), 0, openToken);
}
}
if (node.catch) {
if (node.kind === 'await-catch') {
const catchToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(catchToken, 1, openToken);
if (node.catch.error) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.catch.error), 1, catchToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.catch.error || catchToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
else {
offsets.setOffsetToken(sourceCode.getFirstToken(node.catch), 0, openToken);
}
}
const [openCloseTagToken, endAwaitToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endAwaitToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteAwaitPendingBlock(node) {
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteAwaitThenBlock(node) {
if (!node.awaitThen) {
const [openToken, thenToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(thenToken, 1, openToken);
if (node.value) {
const valueToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken(valueToken, 1, thenToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.value || thenToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteAwaitCatchBlock(node) {
if (!node.awaitCatch) {
const [openToken, catchToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(catchToken, 1, openToken);
if (node.error) {
const errorToken = sourceCode.getFirstToken(node.error);
offsets.setOffsetToken(errorToken, 1, catchToken);
}
const closeOpenTagToken = sourceCode.getTokenAfter(node.error || catchToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
}
const openToken = sourceCode.getFirstToken(node);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
},
SvelteKeyBlock(node) {
const [openToken, keyToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(keyToken, 1, openToken);
const exp = (0, commons_3.getFirstAndLastTokens)(sourceCode, node.expression);
offsets.setOffsetToken(exp.firstToken, 1, keyToken);
const closeOpenTagToken = sourceCode.getTokenAfter(exp.lastToken);
offsets.setOffsetToken(closeOpenTagToken, 0, openToken);
for (const child of node.children) {
const token = sourceCode.getFirstToken(child, {
includeComments: false,
filter: ast_1.isNotWhitespace
});
offsets.setOffsetToken(token, 1, openToken);
}
const [openCloseTagToken, endAwaitToken, closeCloseTagToken] = sourceCode.getLastTokens(node, {
count: 3,
includeComments: false
});
offsets.setOffsetToken(openCloseTagToken, 0, openToken);
offsets.setOffsetToken(endAwaitToken, 1, openCloseTagToken);
offsets.setOffsetToken(closeCloseTagToken, 0, openCloseTagToken);
},
SvelteHTMLComment(_node) {
},
SvelteName(_node) {
},
SvelteMemberExpressionName(_node) {
}
};
return visitor;
}
exports.defineVisitor = defineVisitor;
function isNotEmptyTextNode(node) {
return !(node.type === 'SvelteText' && node.value.trim() === '');
}

View File

@ -0,0 +1,5 @@
import type { IndentContext } from './commons';
import type { TSNodeListener } from '../../types-for-node';
type NodeListener = TSNodeListener;
export declare function defineVisitor(context: IndentContext): NodeListener;
export {};

View File

@ -0,0 +1,743 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.defineVisitor = void 0;
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const commons_1 = require("./commons");
const commons_2 = require("./commons");
function defineVisitor(context) {
const { offsets, sourceCode } = context;
const visitor = {
TSTypeAnnotation(node) {
const [colonOrArrowToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
const baseToken = sourceCode.getFirstToken(node.parent);
offsets.setOffsetToken([colonOrArrowToken, secondToken], 1, baseToken);
const before = sourceCode.getTokenBefore(colonOrArrowToken);
if (before && before.value === '?') {
offsets.setOffsetToken(before, 1, baseToken);
}
},
TSAsExpression(node) {
const expressionTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression);
const asOrSatisfiesToken = sourceCode.getTokenAfter(expressionTokens.lastToken);
offsets.setOffsetToken([asOrSatisfiesToken, (0, commons_2.getFirstAndLastTokens)(sourceCode, node.typeAnnotation).firstToken], 1, expressionTokens.firstToken);
},
TSSatisfiesExpression(node) {
visitor.TSAsExpression(node);
},
TSTypeReference(node) {
if (node.typeParameters) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
},
TSInstantiationExpression(node) {
visitor.TSTypeReference(node);
},
TSTypeParameterInstantiation(node) {
offsets.setOffsetElementList(node.params, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSTypeParameterDeclaration(node) {
visitor.TSTypeParameterInstantiation(node);
},
TSTypeAliasDeclaration(node) {
const typeToken = sourceCode.getFirstToken(node);
const idToken = sourceCode.getFirstToken(node.id);
offsets.setOffsetToken(idToken, 1, typeToken);
let eqToken;
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, idToken);
eqToken = sourceCode.getTokenAfter(node.typeParameters);
}
else {
eqToken = sourceCode.getTokenAfter(node.id);
}
const initToken = sourceCode.getTokenAfter(eqToken);
offsets.setOffsetToken([eqToken, initToken], 1, idToken);
},
TSFunctionType(node) {
const firstToken = sourceCode.getFirstToken(node);
let currToken = firstToken;
if (node.type === 'TSConstructorType') {
currToken = sourceCode.getTokenAfter(currToken);
offsets.setOffsetToken(currToken, 1, firstToken);
}
if (node.typeParameters) {
currToken = sourceCode.getTokenAfter(node.typeParameters);
offsets.setOffsetToken(currToken, 1, firstToken);
}
const leftParenToken = currToken;
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
const arrowToken = sourceCode.getTokenAfter(rightParenToken);
offsets.setOffsetToken(arrowToken, 1, leftParenToken);
},
TSConstructorType(node) {
visitor.TSFunctionType(node);
},
TSTypeLiteral(node) {
offsets.setOffsetElementList(node.members, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSPropertySignature(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
let keyLast;
if (node.computed) {
const closeBracket = sourceCode.getTokenAfter(keyTokens.lastToken);
offsets.setOffsetElementList([node.key], firstToken, closeBracket, 1);
keyLast = closeBracket;
}
else {
keyLast = keyTokens.lastToken;
}
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, firstToken);
}
else if (node.optional) {
const qToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(qToken, 1, firstToken);
}
},
TSIndexSignature(node) {
const leftBracketToken = sourceCode.getFirstToken(node);
const rightBracketToken = sourceCode.getTokenAfter(node.parameters[node.parameters.length - 1] || leftBracketToken, { filter: eslint_utils_1.isClosingBracketToken, includeComments: false });
offsets.setOffsetElementList(node.parameters, leftBracketToken, rightBracketToken, 1);
const keyLast = rightBracketToken;
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, leftBracketToken);
}
},
TSArrayType(node) {
const firstToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getLastTokens(node, { count: 2, includeComments: false }), 0, firstToken);
},
TSTupleType(node) {
offsets.setOffsetElementList(node.elementTypes, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSQualifiedName(node) {
const objectToken = sourceCode.getFirstToken(node);
const dotToken = sourceCode.getTokenBefore(node.right);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, objectToken);
},
TSIndexedAccessType(node) {
const objectToken = sourceCode.getFirstToken(node);
const leftBracketToken = sourceCode.getTokenBefore(node.indexType, {
filter: eslint_utils_1.isOpeningBracketToken,
includeComments: false
});
const rightBracketToken = sourceCode.getTokenAfter(node.indexType, {
filter: eslint_utils_1.isClosingBracketToken,
includeComments: false
});
offsets.setOffsetToken(leftBracketToken, 1, objectToken);
offsets.setOffsetElementList([node.indexType], leftBracketToken, rightBracketToken, 1);
},
TSUnionType(node) {
const firstToken = sourceCode.getFirstToken(node);
const types = [...node.types];
if ((0, commons_2.getFirstAndLastTokens)(sourceCode, types[0]).firstToken === firstToken) {
types.shift();
}
offsets.setOffsetElementList(types, firstToken, null, (0, commons_1.isBeginningOfLine)(sourceCode, firstToken) ? 0 : 1);
},
TSIntersectionType(node) {
visitor.TSUnionType(node);
},
TSMappedType(node) {
const leftBraceToken = sourceCode.getFirstToken(node);
const leftBracketToken = sourceCode.getTokenBefore(node.typeParameter);
const rightBracketToken = sourceCode.getTokenAfter(node.nameType || node.typeParameter);
offsets.setOffsetToken([...sourceCode.getTokensBetween(leftBraceToken, leftBracketToken), leftBracketToken], 1, leftBraceToken);
offsets.setOffsetElementList([node.typeParameter, node.nameType], leftBracketToken, rightBracketToken, 1);
const rightBraceToken = sourceCode.getLastToken(node);
if (node.typeAnnotation) {
const typeAnnotationToken = sourceCode.getFirstToken(node.typeAnnotation);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(rightBracketToken, typeAnnotationToken),
typeAnnotationToken
], 1, leftBraceToken);
}
else {
offsets.setOffsetToken([...sourceCode.getTokensBetween(rightBracketToken, rightBraceToken)], 1, leftBraceToken);
}
offsets.setOffsetToken(rightBraceToken, 0, leftBraceToken);
},
TSTypeParameter(node) {
const [firstToken, ...afterTokens] = sourceCode.getTokens(node);
for (const child of [node.constraint, node.default]) {
if (!child) {
continue;
}
const [, ...removeTokens] = sourceCode.getTokens(child);
for (const token of removeTokens) {
const i = afterTokens.indexOf(token);
if (i >= 0) {
afterTokens.splice(i, 1);
}
}
}
const secondToken = afterTokens.shift();
if (!secondToken) {
return;
}
offsets.setOffsetToken(secondToken, 1, firstToken);
if (secondToken.value === 'extends') {
let prevToken = null;
let token = afterTokens.shift();
while (token) {
if (token.value === '=') {
break;
}
offsets.setOffsetToken(token, 1, secondToken);
prevToken = token;
token = afterTokens.shift();
}
while (token) {
offsets.setOffsetToken(token, 1, prevToken || secondToken);
token = afterTokens.shift();
}
}
else {
offsets.setOffsetToken(afterTokens, 1, firstToken);
}
},
TSConditionalType(node) {
const checkTypeToken = sourceCode.getFirstToken(node);
const extendsToken = sourceCode.getTokenAfter(node.checkType);
const extendsTypeToken = sourceCode.getFirstToken(node.extendsType);
offsets.setOffsetToken(extendsToken, 1, checkTypeToken);
offsets.setOffsetToken(extendsTypeToken, 1, extendsToken);
const questionToken = sourceCode.getTokenAfter(node.extendsType, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const consequentToken = sourceCode.getTokenAfter(questionToken);
const colonToken = sourceCode.getTokenAfter(node.trueType, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const alternateToken = sourceCode.getTokenAfter(colonToken);
let baseNode = node;
let parent = baseNode.parent;
while (parent && parent.type === 'TSConditionalType' && parent.falseType === baseNode) {
baseNode = parent;
parent = baseNode.parent;
}
const baseToken = sourceCode.getFirstToken(baseNode);
offsets.setOffsetToken([questionToken, colonToken], 1, baseToken);
offsets.setOffsetToken(consequentToken, 1, questionToken);
offsets.setOffsetToken(alternateToken, 1, colonToken);
},
TSInterfaceDeclaration(node) {
const interfaceToken = sourceCode.getFirstToken(node);
offsets.setOffsetToken(sourceCode.getFirstToken(node.id), 1, interfaceToken);
if (node.typeParameters != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node.id));
}
if (node.extends != null && node.extends.length) {
const extendsToken = sourceCode.getTokenBefore(node.extends[0]);
offsets.setOffsetToken(extendsToken, 1, interfaceToken);
offsets.setOffsetElementList(node.extends, extendsToken, null, 1);
}
const bodyToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyToken, 0, interfaceToken);
},
TSInterfaceBody(node) {
offsets.setOffsetElementList(node.body, sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
TSClassImplements(node) {
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node));
}
},
TSInterfaceHeritage(node) {
visitor.TSClassImplements(node);
},
TSEnumDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
const prefixTokens = sourceCode.getTokensBetween(firstToken, idTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(idTokens.firstToken, 1, firstToken);
const leftBraceToken = sourceCode.getTokenAfter(idTokens.lastToken);
const rightBraceToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftBraceToken, 0, firstToken);
offsets.setOffsetElementList(node.members, leftBraceToken, rightBraceToken, 1);
},
TSModuleDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
const prefixTokens = sourceCode.getTokensBetween(firstToken, idTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(idTokens.firstToken, 1, firstToken);
if (node.body) {
const bodyFirstToken = sourceCode.getFirstToken(node.body);
offsets.setOffsetToken(bodyFirstToken, (0, eslint_utils_1.isOpeningBraceToken)(bodyFirstToken) ? 0 : 1, firstToken);
}
},
TSModuleBlock(node) {
visitor.TSInterfaceBody(node);
},
TSMethodSignature(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
let keyLast;
if (node.computed) {
const closeBracket = sourceCode.getTokenAfter(keyTokens.lastToken);
offsets.setOffsetElementList([node.key], firstToken, closeBracket, 1);
keyLast = closeBracket;
}
else {
keyLast = keyTokens.lastToken;
}
const leftParenToken = sourceCode.getTokenAfter(keyLast, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, leftParenToken), leftParenToken], 1, firstToken);
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
if (node.returnType) {
const typeAnnotationToken = sourceCode.getFirstToken(node.returnType);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyLast, typeAnnotationToken), typeAnnotationToken], 1, firstToken);
}
},
TSCallSignatureDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
let currToken = firstToken;
if (node.type === 'TSConstructSignatureDeclaration') {
currToken = sourceCode.getTokenAfter(currToken);
offsets.setOffsetToken(currToken, 1, firstToken);
}
if (node.typeParameters) {
currToken = sourceCode.getTokenAfter(node.typeParameters);
offsets.setOffsetToken(currToken, 1, firstToken);
}
const leftParenToken = currToken;
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
if (node.returnType) {
const typeAnnotationToken = sourceCode.getFirstToken(node.returnType);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(rightParenToken, typeAnnotationToken),
typeAnnotationToken
], 1, firstToken);
}
},
TSConstructSignatureDeclaration(node) {
visitor.TSCallSignatureDeclaration(node);
},
TSEmptyBodyFunctionExpression(node) {
const firstToken = sourceCode.getFirstToken(node);
let leftParenToken, bodyBaseToken;
if (firstToken.type === 'Punctuator') {
leftParenToken = firstToken;
bodyBaseToken = sourceCode.getFirstToken(node.parent);
}
else {
let nextToken = sourceCode.getTokenAfter(firstToken);
let nextTokenOffset = 0;
while (nextToken && !(0, eslint_utils_1.isOpeningParenToken)(nextToken) && nextToken.value !== '<') {
if (nextToken.value === '*' || (node.id && nextToken.range[0] === node.id.range[0])) {
nextTokenOffset = 1;
}
offsets.setOffsetToken(nextToken, nextTokenOffset, firstToken);
nextToken = sourceCode.getTokenAfter(nextToken);
}
leftParenToken = nextToken;
bodyBaseToken = firstToken;
}
if (!(0, eslint_utils_1.isOpeningParenToken)(leftParenToken) && node.typeParameters) {
leftParenToken = sourceCode.getTokenAfter(node.typeParameters);
}
const rightParenToken = sourceCode.getTokenAfter(node.params[node.params.length - 1] || leftParenToken, { filter: eslint_utils_1.isClosingParenToken, includeComments: false });
offsets.setOffsetToken(leftParenToken, 1, bodyBaseToken);
offsets.setOffsetElementList(node.params, leftParenToken, rightParenToken, 1);
},
TSDeclareFunction(node) {
visitor.TSEmptyBodyFunctionExpression(node);
},
TSTypeOperator(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
TSTypeQuery(node) {
visitor.TSTypeOperator(node);
},
TSInferType(node) {
visitor.TSTypeOperator(node);
},
TSTypePredicate(node) {
const firstToken = sourceCode.getFirstToken(node);
const opToken = sourceCode.getTokenAfter(node.parameterName, {
filter: eslint_utils_1.isNotClosingParenToken,
includeComments: false
});
const rightToken = node.typeAnnotation && (0, commons_2.getFirstAndLastTokens)(sourceCode, node.typeAnnotation).firstToken;
offsets.setOffsetToken([opToken, rightToken], 1, (0, commons_2.getFirstAndLastTokens)(sourceCode, firstToken).firstToken);
},
TSAbstractMethodDefinition(node) {
const { keyNode, valueNode } = node.type === 'TSEnumMember'
? { keyNode: node.id, valueNode: node.initializer }
: { keyNode: node.key, valueNode: node.value };
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, keyNode);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([keyNode], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (valueNode != null) {
const initToken = sourceCode.getFirstToken(valueNode);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
TSAbstractPropertyDefinition(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSEnumMember(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSAbstractAccessorProperty(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSOptionalType(node) {
offsets.setOffsetToken(sourceCode.getLastToken(node), 1, sourceCode.getFirstToken(node));
},
TSNonNullExpression(node) {
visitor.TSOptionalType(node);
},
TSJSDocNonNullableType(node) {
visitor.TSOptionalType(node);
},
TSTypeAssertion(node) {
const firstToken = sourceCode.getFirstToken(node);
const expressionToken = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression).firstToken;
offsets.setOffsetElementList([node.typeAnnotation], firstToken, sourceCode.getTokenBefore(expressionToken), 1);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
TSImportType(node) {
const firstToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(firstToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
offsets.setOffsetToken(leftParenToken, 1, firstToken);
const argument = node.argument ||
node.parameter;
const rightParenToken = sourceCode.getTokenAfter(argument, {
filter: eslint_utils_1.isClosingParenToken,
includeComments: false
});
offsets.setOffsetElementList([argument], leftParenToken, rightParenToken, 1);
if (node.qualifier) {
const dotToken = sourceCode.getTokenBefore(node.qualifier);
const propertyToken = sourceCode.getTokenAfter(dotToken);
offsets.setOffsetToken([dotToken, propertyToken], 1, firstToken);
}
if (node.typeParameters) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, firstToken);
}
},
TSParameterProperty(node) {
const firstToken = sourceCode.getFirstToken(node);
const parameterToken = sourceCode.getFirstToken(node.parameter);
offsets.setOffsetToken([...sourceCode.getTokensBetween(firstToken, parameterToken), parameterToken], 1, firstToken);
},
TSImportEqualsDeclaration(node) {
const importToken = sourceCode.getFirstToken(node);
const idTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.id);
offsets.setOffsetToken(idTokens.firstToken, 1, importToken);
const opToken = sourceCode.getTokenAfter(idTokens.lastToken);
offsets.setOffsetToken([opToken, sourceCode.getFirstToken(node.moduleReference)], 1, idTokens.lastToken);
},
TSExternalModuleReference(node) {
const requireToken = sourceCode.getFirstToken(node);
const leftParenToken = sourceCode.getTokenAfter(requireToken, {
filter: eslint_utils_1.isOpeningParenToken,
includeComments: false
});
const rightParenToken = sourceCode.getLastToken(node);
offsets.setOffsetToken(leftParenToken, 1, requireToken);
offsets.setOffsetElementList([node.expression], leftParenToken, rightParenToken, 1);
},
TSExportAssignment(node) {
const exportNode = sourceCode.getFirstToken(node);
const exprTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.expression);
const opToken = sourceCode.getTokenBefore(exprTokens.firstToken);
offsets.setOffsetToken([opToken, exprTokens.firstToken], 1, exportNode);
},
TSNamedTupleMember(node) {
const labelToken = sourceCode.getFirstToken(node);
const elementTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.elementType);
offsets.setOffsetToken([
...sourceCode.getTokensBetween(labelToken, elementTokens.firstToken),
elementTokens.firstToken
], 1, labelToken);
},
TSRestType(node) {
const firstToken = sourceCode.getFirstToken(node);
const nextToken = sourceCode.getTokenAfter(firstToken);
offsets.setOffsetToken(nextToken, 1, firstToken);
},
TSNamespaceExportDeclaration(node) {
const firstToken = sourceCode.getFirstToken(node);
const idToken = sourceCode.getFirstToken(node.id);
offsets.setOffsetToken([...sourceCode.getTokensBetween(firstToken, idToken), idToken], 1, firstToken);
},
TSTemplateLiteralType(node) {
const firstToken = sourceCode.getFirstToken(node);
const quasiTokens = node.quasis.slice(1).map((n) => sourceCode.getFirstToken(n));
const expressionToken = node.quasis.slice(0, -1).map((n) => sourceCode.getTokenAfter(n));
offsets.setOffsetToken(quasiTokens, 0, firstToken);
offsets.setOffsetToken(expressionToken, 1, firstToken);
},
Decorator(node) {
const [atToken, secondToken] = sourceCode.getFirstTokens(node, {
count: 2,
includeComments: false
});
offsets.setOffsetToken(secondToken, 0, atToken);
const parent = node.parent;
const { decorators } = parent;
if (!decorators || decorators.length === 0) {
return;
}
if (decorators[0] === node) {
if (parent.range[0] === node.range[0]) {
const startParentToken = sourceCode.getTokenAfter(decorators[decorators?.length - 1]);
offsets.setOffsetToken(startParentToken, 0, atToken);
}
else {
const startParentToken = sourceCode.getFirstToken(parent.parent &&
(parent.parent.type === 'ExportDefaultDeclaration' ||
parent.parent.type === 'ExportNamedDeclaration') &&
node.range[0] < parent.parent.range[0]
? parent.parent
: parent);
offsets.copyOffset(atToken.range[0], startParentToken.range[0]);
}
}
else {
offsets.setOffsetToken(atToken, 0, sourceCode.getFirstToken(decorators[0]));
}
},
AccessorProperty(node) {
const keyNode = node.key;
const valueNode = node.value;
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, keyNode);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
if (node.computed) {
prefixTokens.pop();
}
offsets.setOffsetToken(prefixTokens, 0, firstToken);
let lastKeyToken;
if (node.computed) {
const leftBracketToken = sourceCode.getTokenBefore(keyTokens.firstToken);
const rightBracketToken = (lastKeyToken = sourceCode.getTokenAfter(keyTokens.lastToken));
offsets.setOffsetToken(leftBracketToken, 0, firstToken);
offsets.setOffsetElementList([keyNode], leftBracketToken, rightBracketToken, 1);
}
else {
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
lastKeyToken = keyTokens.lastToken;
}
if (valueNode != null) {
const initToken = sourceCode.getFirstToken(valueNode);
offsets.setOffsetToken([...sourceCode.getTokensBetween(lastKeyToken, initToken), initToken], 1, lastKeyToken);
}
},
StaticBlock(node) {
const firstToken = sourceCode.getFirstToken(node);
let next = sourceCode.getTokenAfter(firstToken);
while (next && (0, eslint_utils_1.isNotOpeningBraceToken)(next)) {
offsets.setOffsetToken(next, 0, firstToken);
next = sourceCode.getTokenAfter(next);
}
offsets.setOffsetToken(next, 0, firstToken);
offsets.setOffsetElementList(node.body, next, sourceCode.getLastToken(node), 1);
},
ImportAttribute(node) {
const firstToken = sourceCode.getFirstToken(node);
const keyTokens = (0, commons_2.getFirstAndLastTokens)(sourceCode, node.key);
const prefixTokens = sourceCode.getTokensBetween(firstToken, keyTokens.firstToken);
offsets.setOffsetToken(prefixTokens, 0, firstToken);
offsets.setOffsetToken(keyTokens.firstToken, 0, firstToken);
const initToken = sourceCode.getFirstToken(node.value);
offsets.setOffsetToken([...sourceCode.getTokensBetween(keyTokens.lastToken, initToken), initToken], 1, keyTokens.lastToken);
},
TSAnyKeyword() {
},
TSBigIntKeyword() {
},
TSBooleanKeyword() {
},
TSNeverKeyword() {
},
TSNullKeyword() {
},
TSNumberKeyword() {
},
TSObjectKeyword() {
},
TSStringKeyword() {
},
TSSymbolKeyword() {
},
TSUndefinedKeyword() {
},
TSUnknownKeyword() {
},
TSVoidKeyword() {
},
TSAbstractKeyword() {
},
TSAsyncKeyword() {
},
TSPrivateKeyword() {
},
TSProtectedKeyword() {
},
TSPublicKeyword() {
},
TSReadonlyKeyword() {
},
TSStaticKeyword() {
},
TSDeclareKeyword() {
},
TSExportKeyword() {
},
TSIntrinsicKeyword() {
},
TSThisType() {
},
TSLiteralType() {
}
};
const commonsVisitor = {
['TSTypeAliasDeclaration, TSCallSignatureDeclaration, TSConstructSignatureDeclaration, TSImportEqualsDeclaration,' +
'TSAbstractMethodDefinition, TSAbstractPropertyDefinition, AccessorProperty, TSAbstractAccessorProperty, TSEnumMember,' +
'TSPropertySignature, TSIndexSignature, TSMethodSignature,' +
'TSAbstractClassProperty, ClassProperty'](node) {
const firstToken = sourceCode.getFirstToken(node);
const lastToken = sourceCode.getLastToken(node);
if ((0, eslint_utils_1.isSemicolonToken)(lastToken) && firstToken !== lastToken) {
const next = sourceCode.getTokenAfter(lastToken);
if (!next || lastToken.loc.start.line < next.loc.start.line) {
offsets.setOffsetToken(lastToken, 0, firstToken);
}
}
},
'*[type=/^TS/]'(node) {
if (node.type !== 'TSAnyKeyword' &&
node.type !== 'TSArrayType' &&
node.type !== 'TSBigIntKeyword' &&
node.type !== 'TSBooleanKeyword' &&
node.type !== 'TSConditionalType' &&
node.type !== 'TSConstructorType' &&
node.type !== 'TSFunctionType' &&
node.type !== 'TSImportType' &&
node.type !== 'TSIndexedAccessType' &&
node.type !== 'TSInferType' &&
node.type !== 'TSIntersectionType' &&
node.type !== 'TSIntrinsicKeyword' &&
node.type !== 'TSLiteralType' &&
node.type !== 'TSMappedType' &&
node.type !== 'TSNamedTupleMember' &&
node.type !== 'TSNeverKeyword' &&
node.type !== 'TSNullKeyword' &&
node.type !== 'TSNumberKeyword' &&
node.type !== 'TSObjectKeyword' &&
node.type !== 'TSOptionalType' &&
node.type !== 'TSRestType' &&
node.type !== 'TSStringKeyword' &&
node.type !== 'TSSymbolKeyword' &&
node.type !== 'TSTemplateLiteralType' &&
node.type !== 'TSThisType' &&
node.type !== 'TSTupleType' &&
node.type !== 'TSTypeLiteral' &&
node.type !== 'TSTypeOperator' &&
node.type !== 'TSTypePredicate' &&
node.type !== 'TSTypeQuery' &&
node.type !== 'TSTypeReference' &&
node.type !== 'TSUndefinedKeyword' &&
node.type !== 'TSUnionType' &&
node.type !== 'TSUnknownKeyword' &&
node.type !== 'TSVoidKeyword') {
return;
}
const typeNode = node;
if (typeNode.parent.type === 'TSParenthesizedType') {
return;
}
let leftToken = sourceCode.getTokenBefore(typeNode);
let rightToken = sourceCode.getTokenAfter(typeNode);
let firstToken = sourceCode.getFirstToken(typeNode);
while (leftToken &&
(0, eslint_utils_1.isOpeningParenToken)(leftToken) &&
rightToken &&
(0, eslint_utils_1.isClosingParenToken)(rightToken)) {
offsets.setOffsetToken(firstToken, 1, leftToken);
offsets.setOffsetToken(rightToken, 0, leftToken);
firstToken = leftToken;
leftToken = sourceCode.getTokenBefore(leftToken);
rightToken = sourceCode.getTokenAfter(rightToken);
}
}
};
const extendsESVisitor = {
['ClassDeclaration[implements], ClassDeclaration[typeParameters], ClassDeclaration[superTypeParameters],' +
'ClassExpression[implements], ClassExpression[typeParameters], ClassExpression[superTypeParameters]'](node) {
if (node.typeParameters != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.typeParameters), 1, sourceCode.getFirstToken(node.id || node));
}
if (node.superTypeParameters != null && node.superClass != null) {
offsets.setOffsetToken(sourceCode.getFirstToken(node.superTypeParameters), 1, sourceCode.getFirstToken(node.superClass));
}
if (node.implements != null && node.implements.length) {
const classToken = sourceCode.getFirstToken(node);
const implementsToken = sourceCode.getTokenBefore(node.implements[0]);
offsets.setOffsetToken(implementsToken, 1, classToken);
offsets.setOffsetElementList(node.implements, implementsToken, null, 1);
}
}
};
const deprecatedVisitor = {
TSParenthesizedType(node) {
offsets.setOffsetElementList([node.typeAnnotation], sourceCode.getFirstToken(node), sourceCode.getLastToken(node), 1);
},
ClassProperty(node) {
visitor.TSAbstractMethodDefinition(node);
},
TSAbstractClassProperty(node) {
visitor.TSAbstractMethodDefinition(node);
}
};
const v = visitor;
return {
...v,
...commonsVisitor,
...extendsESVisitor,
...deprecatedVisitor
};
}
exports.defineVisitor = defineVisitor;

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

49
node_modules/eslint-plugin-svelte/lib/rules/indent.js generated vendored Normal file
View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const indent_helpers_1 = require("./indent-helpers");
exports.default = (0, utils_1.createRule)('indent', {
meta: {
docs: {
description: 'enforce consistent indentation',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
indent: {
anyOf: [{ type: 'integer', minimum: 1 }, { enum: ['tab'] }]
},
indentScript: { type: 'boolean' },
switchCase: { type: 'integer', minimum: 0 },
alignAttributesVertically: { type: 'boolean' },
ignoredNodes: {
type: 'array',
items: {
allOf: [
{ type: 'string' },
{ not: { type: 'string', pattern: ':exit$' } },
{ not: { type: 'string', pattern: '^\\s*$' } }
]
},
uniqueItems: true,
additionalItems: false
}
},
additionalProperties: false
}
],
messages: {
unexpectedChar: 'Expected {{expected}} character, but found {{actual}} character.',
unexpectedIndentation: 'Expected indentation of {{expectedIndent}} {{expectedUnit}}{{expectedIndentPlural}} but found {{actualIndent}} {{actualUnit}}{{actualIndentPlural}}.'
},
type: 'layout'
},
create(context) {
return (0, indent_helpers_1.defineVisitor)(context, {});
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,266 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const svelte_eslint_parser_1 = require("svelte-eslint-parser");
const compat_1 = require("../utils/compat");
function extractTickReferences(context) {
const referenceTracker = new eslint_utils_1.ReferenceTracker((0, compat_1.getSourceCode)(context).scopeManager.globalScope);
const a = referenceTracker.iterateEsmReferences({
svelte: {
[eslint_utils_1.ReferenceTracker.ESM]: true,
tick: {
[eslint_utils_1.ReferenceTracker.CALL]: true
}
}
});
return Array.from(a).map(({ node, path }) => {
return {
node: node,
name: path[path.length - 1]
};
});
}
function extractTaskReferences(context) {
const referenceTracker = new eslint_utils_1.ReferenceTracker((0, compat_1.getSourceCode)(context).scopeManager.globalScope);
const a = referenceTracker.iterateGlobalReferences({
setTimeout: { [eslint_utils_1.ReferenceTracker.CALL]: true },
setInterval: { [eslint_utils_1.ReferenceTracker.CALL]: true },
queueMicrotask: { [eslint_utils_1.ReferenceTracker.CALL]: true }
});
return Array.from(a).map(({ node, path }) => {
return {
node: node,
name: path[path.length - 1]
};
});
}
function isChildNode(maybeAncestorNode, node) {
let parent = node.parent;
while (parent) {
if (parent === maybeAncestorNode)
return true;
parent = parent.parent;
}
return false;
}
function isFunctionCall(node) {
if (node.type !== 'Identifier')
return false;
const { parent } = node;
if (parent?.type !== 'CallExpression')
return false;
return parent.callee.type === 'Identifier' && parent.callee.name === node.name;
}
function isReactiveVariableNode(reactiveVariableReferences, node) {
if (node.type !== 'Identifier')
return false;
return reactiveVariableReferences.includes(node);
}
function isNodeForAssign(node) {
const { parent } = node;
if (parent?.type === 'AssignmentExpression') {
return parent.left.type === 'Identifier' && parent.left.name === node.name;
}
return (parent?.type === 'MemberExpression' &&
parent.parent?.type === 'AssignmentExpression' &&
parent.parent.left.type === 'MemberExpression' &&
parent.parent.left.object.type === 'Identifier' &&
parent.parent.left.object.name === node.name);
}
function isPromiseThenOrCatchBody(node) {
if (!getDeclarationBody(node))
return false;
const { parent } = node;
if (parent?.type !== 'CallExpression' || parent?.callee?.type !== 'MemberExpression') {
return false;
}
const { property } = parent.callee;
if (property?.type !== 'Identifier')
return false;
return ['then', 'catch'].includes(property.name);
}
function getReactiveVariableReferences(context) {
const scopeManager = (0, compat_1.getSourceCode)(context).scopeManager;
const toplevelScope = scopeManager.globalScope?.childScopes.find((scope) => scope.type === 'module') ||
scopeManager.globalScope;
if (!toplevelScope) {
return [];
}
const reactiveVariableNodes = [];
for (const variable of toplevelScope.variables) {
for (const reference of variable.references) {
if (reference.identifier.type === 'Identifier' && !isFunctionCall(reference.identifier)) {
reactiveVariableNodes.push(reference.identifier);
}
}
}
return reactiveVariableNodes;
}
function getTrackedVariableNodes(reactiveVariableReferences, ast) {
const reactiveVariableNodes = new Set();
for (const identifier of reactiveVariableReferences) {
if (ast.range[0] <= identifier.range[0] &&
identifier.range[1] <= ast.range[1]) {
reactiveVariableNodes.add(identifier);
}
}
return reactiveVariableNodes;
}
function getDeclarationBody(node, functionName) {
if (node.type === 'VariableDeclarator' &&
node.id.type === 'Identifier' &&
(!functionName || node.id.name === functionName)) {
if (node.init?.type === 'ArrowFunctionExpression' || node.init?.type === 'FunctionExpression') {
return node.init.body;
}
}
else if (node.type === 'FunctionDeclaration' &&
node.id?.type === 'Identifier' &&
(!functionName || node.id?.name === functionName)) {
return node.body;
}
else if (!functionName && node.type === 'ArrowFunctionExpression') {
return node.body;
}
return null;
}
function getFunctionDeclarationNode(context, functionCall) {
const variable = (0, ast_utils_1.findVariable)(context, functionCall);
if (!variable) {
return null;
}
for (const def of variable.defs) {
if (def.type === 'FunctionName') {
if (def.node.type === 'FunctionDeclaration') {
return def.node.body;
}
}
if (def.type === 'Variable') {
if (def.node.init &&
(def.node.init.type === 'FunctionExpression' ||
def.node.init.type === 'ArrowFunctionExpression')) {
return def.node.init.body;
}
}
}
return null;
}
function isInsideOfFunction(node) {
let parent = node;
while (parent) {
parent = parent.parent;
if (!parent)
break;
if (parent.type === 'FunctionDeclaration' && parent.async)
return true;
if (parent.type === 'VariableDeclarator' &&
(parent.init?.type === 'FunctionExpression' ||
parent.init?.type === 'ArrowFunctionExpression') &&
parent.init?.async) {
return true;
}
}
return false;
}
function doLint(context, ast, callFuncIdentifiers, tickCallExpressions, taskReferences, reactiveVariableNames, reactiveVariableReferences, pIsSameTask) {
const processed = new Set();
verifyInternal(ast, callFuncIdentifiers, pIsSameTask);
function verifyInternal(ast, callFuncIdentifiers, pIsSameTask) {
if (processed.has(ast)) {
return;
}
processed.add(ast);
let isSameMicroTask = pIsSameTask;
const differentMicroTaskEnterNodes = [];
(0, svelte_eslint_parser_1.traverseNodes)(ast, {
enterNode(node) {
if (isPromiseThenOrCatchBody(node)) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
for (const { node: callExpression } of [...tickCallExpressions, ...taskReferences]) {
if (isChildNode(callExpression, node)) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
}
if (node.parent?.type === 'AssignmentExpression' &&
node.parent?.right.type === 'AwaitExpression' &&
node.parent?.left === node) {
differentMicroTaskEnterNodes.push(node);
isSameMicroTask = false;
}
if (node.type === 'Identifier' && isFunctionCall(node)) {
const functionDeclarationNode = getFunctionDeclarationNode(context, node);
if (functionDeclarationNode) {
verifyInternal(functionDeclarationNode, [...callFuncIdentifiers, node], isSameMicroTask);
}
}
if (!isSameMicroTask) {
if (isReactiveVariableNode(reactiveVariableReferences, node) &&
reactiveVariableNames.includes(node.name) &&
isNodeForAssign(node)) {
context.report({
node,
loc: node.loc,
messageId: 'unexpected'
});
callFuncIdentifiers.forEach((callFuncIdentifier) => {
context.report({
node: callFuncIdentifier,
loc: callFuncIdentifier.loc,
messageId: 'unexpectedCall',
data: {
variableName: node.name
}
});
});
}
}
},
leaveNode(node) {
if (node.type === 'AwaitExpression') {
if (ast.parent?.type === 'SvelteReactiveStatement') {
if (!isInsideOfFunction(node)) {
isSameMicroTask = false;
}
}
else {
isSameMicroTask = false;
}
}
if (differentMicroTaskEnterNodes.includes(node)) {
isSameMicroTask = true;
}
}
});
}
}
exports.default = (0, utils_1.createRule)('infinite-reactive-loop', {
meta: {
docs: {
description: "Svelte runtime prevents calling the same reactive statement twice in a microtask. But between different microtask, it doesn't prevent.",
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
unexpected: 'Possibly it may occur an infinite reactive loop.',
unexpectedCall: 'Possibly it may occur an infinite reactive loop because this function may update `{{variableName}}`.'
},
type: 'suggestion'
},
create(context) {
return {
['SvelteReactiveStatement']: (ast) => {
const tickCallExpressions = extractTickReferences(context);
const taskReferences = extractTaskReferences(context);
const reactiveVariableReferences = getReactiveVariableReferences(context);
const trackedVariableNodes = getTrackedVariableNodes(reactiveVariableReferences, ast);
doLint(context, ast.body, [], tickCallExpressions, taskReferences, Array.from(trackedVariableNodes).map((node) => node.name), reactiveVariableReferences, true);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
function isSingleLine(node) {
return node.loc.start.line === node.loc.end.line;
}
function groupAttributesByLine(attributes) {
const group = [];
for (const attr of attributes) {
if (group[0]?.[0]?.loc.end.line === attr.loc.start.line) {
group[0].push(attr);
}
else {
group.unshift([attr]);
}
}
return group.reverse();
}
exports.default = (0, utils_1.createRule)('max-attributes-per-line', {
meta: {
docs: {
description: 'enforce the maximum number of attributes per line',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'whitespace',
schema: [
{
type: 'object',
properties: {
multiline: {
type: 'number',
minimum: 1
},
singleline: {
type: 'number',
minimum: 1
}
},
additionalProperties: false
}
],
messages: {
requireNewline: "'{{name}}' should be on a new line."
},
type: 'layout'
},
create(context) {
const multilineMaximum = context.options[0]?.multiline ?? 1;
const singlelineMaximum = context.options[0]?.singleline ?? 1;
const sourceCode = (0, compat_1.getSourceCode)(context);
function report(attribute) {
if (!attribute) {
return;
}
let name;
if (attribute.type === 'SvelteAttribute' ||
attribute.type === 'SvelteShorthandAttribute' ||
attribute.type === 'SvelteDirective' ||
attribute.type === 'SvelteStyleDirective' ||
attribute.type === 'SvelteSpecialDirective') {
name = sourceCode.text.slice(...attribute.key.range);
}
else {
name = sourceCode.text.slice(...attribute.range);
}
context.report({
node: attribute,
loc: attribute.loc,
messageId: 'requireNewline',
data: { name },
fix(fixer) {
const prevToken = sourceCode.getTokenBefore(attribute, {
includeComments: true
});
const range = [prevToken.range[1], attribute.range[0]];
return fixer.replaceTextRange(range, '\n');
}
});
}
return {
SvelteStartTag(node) {
const numberOfAttributes = node.attributes.length;
if (!numberOfAttributes)
return;
if (isSingleLine(node)) {
if (numberOfAttributes > singlelineMaximum) {
report(node.attributes[singlelineMaximum]);
}
}
else {
for (const attrs of groupAttributesByLine(node.attributes)) {
report(attrs[multilineMaximum]);
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,256 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
const VALUE_SCHEMA = { enum: ['never', 'always'] };
function parseOptions(options) {
return {
textExpressions: options?.textExpressions || 'never',
attributesAndProps: options?.attributesAndProps || 'never',
directiveExpressions: options?.directiveExpressions || 'never',
tags: {
openingBrace: options?.tags?.openingBrace || 'never',
closingBrace: options?.tags?.closingBrace || 'never'
}
};
}
exports.default = (0, utils_1.createRule)('mustache-spacing', {
meta: {
docs: {
description: 'enforce unified spacing in mustache',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: true
},
fixable: 'code',
schema: [
{
type: 'object',
properties: {
textExpressions: VALUE_SCHEMA,
attributesAndProps: VALUE_SCHEMA,
directiveExpressions: VALUE_SCHEMA,
tags: {
type: 'object',
properties: {
openingBrace: VALUE_SCHEMA,
closingBrace: {
enum: ['never', 'always', 'always-after-expression']
}
},
additionalProperties: false
}
},
additionalProperties: false
}
],
messages: {
expectedOpening: "Expected 1 space after '{', but not found.",
expectedClosing: "Expected 1 space before '}', but not found.",
unexpectedOpening: "Expected no space after '{', but found.",
unexpectedClosing: "Expected no space before '}', but found."
},
type: 'layout'
},
create(context) {
const options = parseOptions(context.options[0]);
const sourceCode = (0, compat_1.getSourceCode)(context);
function verifyBraces(openingBrace, closingBrace, openingOption, closingOption, hasExpression) {
const firstToken = sourceCode.getTokenAfter(openingBrace, {
includeComments: true
});
if (openingOption === 'always') {
if (openingBrace.range[1] === firstToken.range[0]) {
context.report({
node: openingBrace,
messageId: 'expectedOpening',
fix: (fixer) => fixer.insertTextAfter(openingBrace, ' ')
});
}
}
else {
if (openingBrace.range[1] !== firstToken.range[0]) {
context.report({
loc: {
start: openingBrace.loc.start,
end: firstToken.loc.start
},
messageId: 'unexpectedOpening',
fix: (fixer) => fixer.removeRange([openingBrace.range[1], firstToken.range[0]])
});
}
}
if (!closingBrace) {
return;
}
const lastToken = sourceCode.getTokenBefore(closingBrace, {
includeComments: true
});
if (closingOption === 'always' ||
(closingOption === 'always-after-expression' && hasExpression)) {
if (closingBrace.range[0] === lastToken.range[1]) {
context.report({
node: closingBrace,
messageId: 'expectedClosing',
fix: (fixer) => fixer.insertTextBefore(closingBrace, ' ')
});
}
}
else {
if (closingBrace.range[0] !== lastToken.range[1]) {
context.report({
loc: {
start: lastToken.loc.end,
end: closingBrace.loc.end
},
messageId: 'unexpectedClosing',
fix: (fixer) => fixer.removeRange([lastToken.range[1], closingBrace.range[0]])
});
}
}
}
function verifyExpression(node, option) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
if (!mustacheTokens) {
return;
}
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, option, option);
}
return {
SvelteMustacheTag(node) {
if (node.kind === 'raw') {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
return;
}
let option;
if (node.parent.type === 'SvelteAttribute') {
option = options.attributesAndProps;
}
else if (node.parent.type === 'SvelteStyleDirective') {
option = options.directiveExpressions;
}
else {
option = options.textExpressions;
}
verifyExpression(node, option);
},
SvelteShorthandAttribute(node) {
verifyExpression(node, options.attributesAndProps);
},
SvelteSpreadAttribute(node) {
verifyExpression(node, options.attributesAndProps);
},
SvelteDirective(node) {
verifyExpression(node, options.directiveExpressions);
},
SvelteSpecialDirective(node) {
verifyExpression(node, options.directiveExpressions);
},
SvelteDebugTag(node) {
const mustacheTokens = (0, ast_utils_1.getMustacheTokens)(node, sourceCode);
verifyBraces(mustacheTokens.openToken, mustacheTokens.closeToken, options.tags.openingBrace, options.tags.closingBrace, true);
},
SvelteIfBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
if (node.elseif) {
return;
}
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteElseBlock(node) {
if (node.elseif) {
return;
}
const openToken = sourceCode.getFirstToken(node);
const closeToken = sourceCode.getTokenAfter(openToken, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openToken, closeToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteEachBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.key || node.index || node.context, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteKeyBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteAwaitBlock(node) {
const closeBlockClosingToken = sourceCode.getLastToken(node);
const closeBlockOpeningToken = sourceCode.getTokenBefore(closeBlockClosingToken, {
includeComments: false,
filter: eslint_utils_1.isOpeningBraceToken
});
verifyBraces(closeBlockOpeningToken, closeBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, false);
},
SvelteAwaitPendingBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockClosingToken = sourceCode.getTokenAfter(node.parent.expression, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
});
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, true);
},
SvelteAwaitThenBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockLast = node.value || (node.awaitThen ? node.parent.expression : null);
const openBlockClosingToken = openBlockLast
? sourceCode.getTokenAfter(openBlockLast, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
})
: null;
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, Boolean(openBlockClosingToken &&
openBlockLast &&
openBlockClosingToken === sourceCode.getTokenAfter(openBlockLast)));
},
SvelteAwaitCatchBlock(node) {
const openBlockOpeningToken = sourceCode.getFirstToken(node);
const openBlockLast = node.error || (node.awaitCatch ? node.parent.expression : null);
const openBlockClosingToken = openBlockLast
? sourceCode.getTokenAfter(openBlockLast, {
includeComments: false,
filter: eslint_utils_1.isClosingBraceToken
})
: null;
verifyBraces(openBlockOpeningToken, openBlockClosingToken, options.tags.openingBrace, options.tags.closingBrace, Boolean(openBlockClosingToken &&
openBlockLast &&
openBlockClosingToken === sourceCode.getTokenAfter(openBlockLast)));
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,28 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-at-debug-tags', {
meta: {
docs: {
description: 'disallow the use of `{@debug}`',
category: 'Best Practices',
recommended: true,
default: 'warn'
},
schema: [],
messages: {
unexpected: 'Unexpected `{@debug}`.'
},
type: 'problem'
},
create(context) {
return {
SvelteDebugTag(node) {
context.report({
node,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,27 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-at-html-tags', {
meta: {
docs: {
description: 'disallow use of `{@html}` to prevent XSS attack',
category: 'Security Vulnerability',
recommended: true
},
schema: [],
messages: {
unexpected: '`{@html}` can lead to XSS attack.'
},
type: 'suggestion'
},
create(context) {
return {
'SvelteMustacheTag[kind=raw]'(node) {
context.report({
node,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,110 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const DOM_MANIPULATING_METHODS = new Set([
'appendChild',
'insertBefore',
'normalize',
'removeChild',
'replaceChild',
'after',
'append',
'before',
'insertAdjacentElement',
'insertAdjacentHTML',
'insertAdjacentText',
'prepend',
'remove',
'replaceChildren',
'replaceWith'
]);
const DOM_MANIPULATING_PROPERTIES = new Set([
'textContent',
'innerHTML',
'outerHTML',
'innerText',
'outerText'
]);
exports.default = (0, utils_1.createRule)('no-dom-manipulating', {
meta: {
docs: {
description: 'disallow DOM manipulating',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
disallowManipulateDOM: "Don't manipulate the DOM directly. The Svelte runtime can get confused if there is a difference between the actual DOM and the DOM expected by the Svelte runtime."
},
type: 'problem'
},
create(context) {
const domVariables = new Set();
function verifyIdentifier(node) {
const member = node.parent;
if (member?.type !== 'MemberExpression' || member.object !== node) {
return;
}
const name = (0, eslint_utils_1.getPropertyName)(member);
if (!name) {
return;
}
let target = member;
let parent = target.parent;
while (parent?.type === 'ChainExpression') {
target = parent;
parent = parent.parent;
}
if (!parent) {
return;
}
if (parent.type === 'CallExpression') {
if (parent.callee !== target || !DOM_MANIPULATING_METHODS.has(name)) {
return;
}
}
else if (parent.type === 'AssignmentExpression') {
if (parent.left !== target || !DOM_MANIPULATING_PROPERTIES.has(name)) {
return;
}
}
else {
return;
}
context.report({
node: member,
messageId: 'disallowManipulateDOM'
});
}
return {
"SvelteDirective[kind='Binding']"(node) {
if (node.key.name.name !== 'this' ||
!node.expression ||
node.expression.type !== 'Identifier') {
return;
}
const element = node.parent.parent;
if (element.type !== 'SvelteElement' || !isHTMLElement(element)) {
return;
}
const variable = (0, ast_utils_1.findVariable)(context, node.expression);
if (!variable || (variable.scope.type !== 'module' && variable.scope.type !== 'global')) {
return;
}
domVariables.add(variable);
},
'Program:exit'() {
for (const variable of domVariables) {
for (const reference of variable.references) {
verifyIdentifier(reference.identifier);
}
}
}
};
function isHTMLElement(node) {
return (node.kind === 'html' || (node.kind === 'special' && (0, ast_utils_1.getNodeName)(node) === 'svelte:element'));
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,101 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
function splitByLogicalOperator(operator, node) {
if (node.type === 'LogicalExpression' && node.operator === operator) {
return [
...splitByLogicalOperator(operator, node.left),
...splitByLogicalOperator(operator, node.right)
];
}
return [node];
}
function splitByOr(node) {
return splitByLogicalOperator('||', node);
}
function splitByAnd(node) {
return splitByLogicalOperator('&&', node);
}
function buildOrOperands(node) {
const orOperands = splitByOr(node);
return {
node,
operands: orOperands.map((orOperand) => {
const andOperands = splitByAnd(orOperand);
return {
node: orOperand,
operands: andOperands
};
})
};
}
exports.default = (0, utils_1.createRule)('no-dupe-else-if-blocks', {
meta: {
docs: {
description: 'disallow duplicate conditions in `{#if}` / `{:else if}` chains',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'This branch can never execute. Its condition is a duplicate or covered by previous conditions in the `{#if}` / `{:else if}` chain.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
function equal(a, b) {
if (a.type !== b.type) {
return false;
}
if (a.type === 'LogicalExpression' &&
b.type === 'LogicalExpression' &&
(a.operator === '||' || a.operator === '&&') &&
a.operator === b.operator) {
return ((equal(a.left, b.left) && equal(a.right, b.right)) ||
(equal(a.left, b.right) && equal(a.right, b.left)));
}
return (0, ast_utils_1.equalTokens)(a, b, sourceCode);
}
function isSubset(operandsA, operandsB) {
return operandsA.operands.every((operandA) => operandsB.operands.some((operandB) => equal(operandA, operandB)));
}
function* iterateIfElseIf(node) {
let target = node;
while (target.parent.type === 'SvelteElseBlock' &&
target.parent.children.includes(target) &&
target.parent.parent.type === 'SvelteIfBlock') {
yield target.parent.parent;
target = target.parent.parent;
}
}
return {
SvelteIfBlock(node) {
const test = node.expression;
const conditionsToCheck = test.type === 'LogicalExpression' && test.operator === '&&'
? [...splitByAnd(test), test]
: [test];
const listToCheck = conditionsToCheck.map(buildOrOperands);
for (const currentIdBlock of iterateIfElseIf(node)) {
if (currentIdBlock.expression) {
const currentOrOperands = buildOrOperands(currentIdBlock.expression);
for (const condition of listToCheck) {
const operands = (condition.operands = condition.operands.filter((orOperand) => {
return !currentOrOperands.operands.some((currentOrOperand) => isSubset(currentOrOperand, orOperand));
}));
if (!operands.length) {
context.report({
node: condition.node,
messageId: 'unexpected'
});
return;
}
}
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,73 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dupe-on-directives', {
meta: {
docs: {
description: 'disallow duplicate `on:` directives',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
duplication: 'This `on:{{type}}` directive is the same and duplicate directives in L{{lineNo}}.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const directiveDataMap = new Map();
return {
SvelteDirective(node) {
if (node.kind !== 'EventHandler')
return;
const directiveDataList = directiveDataMap.get(node.key.name.name);
if (!directiveDataList) {
directiveDataMap.set(node.key.name.name, [
{
expression: node.expression,
nodes: [node]
}
]);
return;
}
const directiveData = directiveDataList.find((data) => {
if (!data.expression || !node.expression) {
return data.expression === node.expression;
}
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
});
if (!directiveData) {
directiveDataList.push({
expression: node.expression,
nodes: [node]
});
return;
}
directiveData.nodes.push(node);
},
'SvelteStartTag:exit'() {
for (const [type, directiveDataList] of directiveDataMap) {
for (const { nodes } of directiveDataList) {
if (nodes.length < 2) {
continue;
}
for (const node of nodes) {
context.report({
node,
messageId: 'duplication',
data: {
type,
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line)
}
});
}
}
}
directiveDataMap.clear();
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const css_utils_1 = require("../utils/css-utils");
exports.default = (0, utils_1.createRule)('no-dupe-style-properties', {
meta: {
docs: {
description: 'disallow duplicate style properties',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: "Duplicate property '{{name}}'."
},
type: 'problem'
},
create(context) {
return {
SvelteStartTag(node) {
const reported = new Set();
const beforeDeclarations = new Map();
for (const { decls } of iterateStyleDeclSetFromAttrs(node.attributes)) {
for (const decl of decls) {
const already = beforeDeclarations.get(decl.prop);
if (already) {
for (const report of [already, decl].filter((n) => !reported.has(n))) {
context.report({
node,
loc: report.loc,
messageId: 'unexpected',
data: { name: report.prop }
});
reported.add(report);
}
}
}
for (const decl of decls) {
beforeDeclarations.set(decl.prop, decl);
}
}
}
};
function* iterateStyleDeclSetFromAttrs(attrs) {
for (const attr of attrs) {
if (attr.type === 'SvelteStyleDirective') {
yield {
decls: [{ prop: attr.key.name.name, loc: attr.key.name.loc }]
};
}
else if (attr.type === 'SvelteAttribute') {
if (attr.key.name !== 'style') {
continue;
}
const root = (0, css_utils_1.parseStyleAttributeValue)(attr, context);
if (!root) {
continue;
}
yield* iterateStyleDeclSetFromStyleRoot(root);
}
}
}
function* iterateStyleDeclSetFromStyleRoot(root) {
for (const child of root.nodes) {
if (child.type === 'decl') {
yield {
decls: [
{
prop: child.prop.name,
get loc() {
return child.prop.loc;
}
}
]
};
}
else if (child.type === 'inline') {
const decls = [];
for (const root of child.getAllInlineStyles().values()) {
for (const set of iterateStyleDeclSetFromStyleRoot(root)) {
decls.push(...set.decls);
}
}
yield { decls };
}
}
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,74 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dupe-use-directives', {
meta: {
docs: {
description: 'disallow duplicate `use:` directives',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
duplication: 'This `{{keyText}}` directive is the same and duplicate directives in L{{lineNo}}.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
const directiveDataMap = new Map();
return {
SvelteDirective(node) {
if (node.kind !== 'Action')
return;
const keyText = (0, ast_utils_1.getAttributeKeyText)(node, context);
const directiveDataList = directiveDataMap.get(keyText);
if (!directiveDataList) {
directiveDataMap.set(keyText, [
{
expression: node.expression,
nodes: [node]
}
]);
return;
}
const directiveData = directiveDataList.find((data) => {
if (!data.expression || !node.expression) {
return data.expression === node.expression;
}
return (0, ast_utils_1.equalTokens)(data.expression, node.expression, sourceCode);
});
if (!directiveData) {
directiveDataList.push({
expression: node.expression,
nodes: [node]
});
return;
}
directiveData.nodes.push(node);
},
'SvelteStartTag:exit'() {
for (const [keyText, directiveDataList] of directiveDataMap) {
for (const { nodes } of directiveDataList) {
if (nodes.length < 2) {
continue;
}
for (const node of nodes) {
context.report({
node,
messageId: 'duplication',
data: {
keyText,
lineNo: String((nodes[0] !== node ? nodes[0] : nodes[1]).loc.start.line)
}
});
}
}
}
directiveDataMap.clear();
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,77 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-dynamic-slot-name', {
meta: {
docs: {
description: 'disallow dynamic slot name',
category: 'Possible Errors',
recommended: true
},
fixable: 'code',
schema: [],
messages: {
unexpected: '`<slot>` name cannot be dynamic.',
requireValue: '`<slot>` name requires a value.'
},
type: 'problem'
},
create(context) {
const sourceCode = (0, compat_1.getSourceCode)(context);
return {
"SvelteElement[name.name='slot'] > SvelteStartTag.startTag > SvelteAttribute[key.name='name']"(node) {
if (node.value.length === 0) {
context.report({
node,
messageId: 'requireValue'
});
return;
}
for (const vNode of node.value) {
if (vNode.type === 'SvelteMustacheTag') {
context.report({
node: vNode,
messageId: 'unexpected',
fix(fixer) {
const text = getStaticText(vNode.expression);
if (text == null) {
return null;
}
if (node.value.length === 1) {
const range = (0, ast_utils_1.getAttributeValueQuoteAndRange)(node, sourceCode).range;
return fixer.replaceTextRange(range, `"${text}"`);
}
const range = vNode.range;
return fixer.replaceTextRange(range, text);
}
});
}
}
}
};
function getStaticText(node) {
const expr = findRootExpression(node);
return (0, ast_utils_1.getStringIfConstant)(expr);
}
function findRootExpression(node, already = new Set()) {
if (node.type !== 'Identifier' || already.has(node)) {
return node;
}
already.add(node);
const variable = (0, ast_utils_1.findVariable)(context, node);
if (!variable || variable.defs.length !== 1) {
return node;
}
const def = variable.defs[0];
if (def.type === 'Variable') {
if (def.parent.kind === 'const' && def.node.init) {
const init = def.node.init;
return findRootExpression(init, already);
}
}
return node;
}
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,41 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const svelte_kit_1 = require("../utils/svelte-kit");
exports.default = (0, utils_1.createRule)('no-export-load-in-svelte-module-in-kit-pages', {
meta: {
docs: {
description: 'disallow exporting load functions in `*.svelte` module in SvelteKit page components.',
category: 'Possible Errors',
recommended: false
},
schema: [],
messages: {
unexpected: 'disallow exporting load functions in `*.svelte` module in SvelteKit page components.'
},
type: 'problem'
},
create(context) {
if (!(0, svelte_kit_1.isKitPageComponent)(context)) {
return {};
}
let isModule = false;
return {
[`Program > SvelteScriptElement > SvelteStartTag > SvelteAttribute[key.name="context"] > SvelteLiteral[value="module"]`]: () => {
isModule = true;
},
'Program > SvelteScriptElement:exit': () => {
isModule = false;
},
[`:matches(ExportNamedDeclaration > FunctionDeclaration, ExportNamedDeclaration > VariableDeclaration > VariableDeclarator) > Identifier.id[name="load"]`]: (node) => {
if (!isModule)
return {};
return context.report({
node,
loc: node.loc,
messageId: 'unexpected'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,48 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-extra-reactive-curlies', {
meta: {
docs: {
description: 'disallow wrapping single reactive statements in curly braces',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
hasSuggestions: true,
schema: [],
messages: {
extraCurlies: `Do not wrap reactive statements in curly braces unless necessary.`,
removeExtraCurlies: `Remove the unnecessary curly braces.`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > BlockStatement[body.length=1]`]: (node) => {
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node,
loc: node.loc,
messageId: 'extraCurlies',
suggest: [
{
messageId: 'removeExtraCurlies',
fix(fixer) {
const tokens = source.getTokens(node, { includeComments: true });
return [
fixer.removeRange([tokens[0].range[0], tokens[1].range[0]]),
fixer.removeRange([
tokens[tokens.length - 2].range[1],
tokens[tokens.length - 1].range[1]
])
];
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,29 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-ignored-unsubscribe', {
meta: {
docs: {
description: 'disallow ignoring the unsubscribe method returned by the `subscribe()` on Svelte stores.',
category: 'Best Practices',
recommended: false
},
fixable: undefined,
hasSuggestions: false,
messages: {
forbidden: 'Ignoring returned value of the subscribe method is forbidden.'
},
schema: [],
type: 'problem'
},
create: (context) => {
return {
"ExpressionStatement > CallExpression > MemberExpression.callee[property.name='subscribe']": (node) => {
context.report({
messageId: 'forbidden',
node: node.property
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,160 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-immutable-reactive-statements', {
meta: {
docs: {
description: "disallow reactive statements that don't reference reactive values.",
category: 'Best Practices',
recommended: false
},
schema: [],
messages: {
immutable: 'This statement is not reactive because all variables referenced in the reactive statement are immutable.'
},
type: 'suggestion'
},
create(context) {
const scopeManager = (0, compat_1.getSourceCode)(context).scopeManager;
const globalScope = scopeManager.globalScope;
const toplevelScope = globalScope?.childScopes.find((scope) => scope.type === 'module') || globalScope;
if (!globalScope || !toplevelScope) {
return {};
}
const cacheMutableVariable = new WeakMap();
function isMutableVariableReference(reference) {
if (reference.identifier.name.startsWith('$')) {
return true;
}
if (!reference.resolved) {
return true;
}
return isMutableVariable(reference.resolved);
}
function isMutableVariable(variable) {
const cache = cacheMutableVariable.get(variable);
if (cache != null) {
return cache;
}
if (variable.defs.length === 0) {
return true;
}
const isMutableDefine = variable.defs.some((def) => {
if (def.type === 'ImportBinding') {
return false;
}
if (def.node.type === 'AssignmentExpression') {
return true;
}
if (def.type === 'Variable') {
const parent = def.parent;
if (parent.kind === 'const') {
if (def.node.init &&
(def.node.init.type === 'FunctionExpression' ||
def.node.init.type === 'ArrowFunctionExpression' ||
def.node.init.type === 'Literal')) {
return false;
}
}
else {
const pp = parent.parent;
if (pp && pp.type === 'ExportNamedDeclaration' && pp.declaration === parent) {
return true;
}
}
return hasWrite(variable);
}
return false;
});
cacheMutableVariable.set(variable, isMutableDefine);
return isMutableDefine;
}
function hasWrite(variable) {
const defIds = variable.defs.map((def) => def.name);
for (const reference of variable.references) {
if (reference.isWrite() &&
!defIds.some((defId) => defId.range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= defId.range[1])) {
return true;
}
if (hasWriteMember(reference.identifier)) {
return true;
}
}
return false;
}
function hasWriteMember(expr) {
if (expr.type === 'JSXIdentifier')
return false;
const parent = expr.parent;
if (parent.type === 'AssignmentExpression') {
return parent.left === expr;
}
if (parent.type === 'UpdateExpression') {
return parent.argument === expr;
}
if (parent.type === 'UnaryExpression') {
return parent.operator === 'delete' && parent.argument === expr;
}
if (parent.type === 'MemberExpression') {
return parent.object === expr && hasWriteMember(parent);
}
if (parent.type === 'SvelteDirective') {
return parent.kind === 'Binding' && parent.expression === expr;
}
if (parent.type === 'SvelteEachBlock') {
return parent.expression === expr && hasWriteReference(parent.context);
}
return false;
}
function hasWriteReference(pattern) {
for (const id of (0, ast_utils_1.iterateIdentifiers)(pattern)) {
const variable = (0, ast_utils_1.findVariable)(context, id);
if (variable && hasWrite(variable))
return true;
}
return false;
}
function* iterateRangeReferences(scope, range) {
for (const variable of scope.variables) {
for (const reference of variable.references) {
if (range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= range[1]) {
yield reference;
}
}
}
}
return {
SvelteReactiveStatement(node) {
for (const reference of iterateRangeReferences(toplevelScope, node.range)) {
if (reference.isWriteOnly()) {
continue;
}
if (isMutableVariableReference(reference)) {
return;
}
}
for (const through of toplevelScope.through.filter((reference) => node.range[0] <= reference.identifier.range[0] &&
reference.identifier.range[1] <= node.range[1])) {
if (through.identifier.name.startsWith('$$')) {
return;
}
if (through.resolved == null) {
return;
}
}
context.report({
node: node.body.type === 'ExpressionStatement' &&
node.body.expression.type === 'AssignmentExpression' &&
node.body.expression.operator === '='
? node.body.expression.right
: node.body,
messageId: 'immutable'
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,52 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-inline-styles', {
meta: {
docs: {
description: 'disallow attributes and directives that produce inline styles',
category: 'Best Practices',
recommended: false
},
schema: [
{
type: 'object',
properties: {
allowTransitions: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
hasStyleAttribute: 'Found disallowed style attribute.',
hasStyleDirective: 'Found disallowed style directive.',
hasTransition: 'Found disallowed transition.'
},
type: 'suggestion'
},
create(context) {
const allowTransitions = context.options[0]?.allowTransitions ?? false;
return {
SvelteElement(node) {
if (node.kind !== 'html') {
return;
}
for (const attribute of node.startTag.attributes) {
if (attribute.type === 'SvelteStyleDirective') {
context.report({ loc: attribute.loc, messageId: 'hasStyleDirective' });
}
if (attribute.type === 'SvelteAttribute' && attribute.key.name === 'style') {
context.report({ loc: attribute.loc, messageId: 'hasStyleAttribute' });
}
if (!allowTransitions &&
attribute.type === 'SvelteDirective' &&
attribute.kind === 'Transition') {
context.report({ loc: attribute.loc, messageId: 'hasTransition' });
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,35 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const eslint_core_1 = require("../utils/eslint-core");
const coreRule = (0, eslint_core_1.getCoreRule)('no-inner-declarations');
exports.default = (0, utils_1.createRule)('no-inner-declarations', {
meta: {
docs: {
description: 'disallow variable or `function` declarations in nested blocks',
category: 'Extension Rules',
recommended: true,
extensionRule: 'no-inner-declarations'
},
fixable: coreRule.meta.fixable,
schema: coreRule.meta.schema,
messages: coreRule.meta.messages,
type: coreRule.meta.type
},
create(context) {
return (0, eslint_core_1.defineWrapperListener)(coreRule, context, {
createListenerProxy(coreListener) {
return (0, eslint_core_1.buildProxyListener)(coreListener, (node) => {
return (0, eslint_core_1.getProxyNode)(node, {
get parent() {
if (node.parent?.type === 'SvelteScriptElement') {
return node.parent.parent;
}
return node.parent;
}
});
});
}
});
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,89 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const ast_utils_1 = require("../utils/ast-utils");
const PHRASES = {
ObjectExpression: 'object',
ArrayExpression: 'array',
ClassExpression: 'class',
Literal(node) {
if ('regex' in node) {
return 'regex value';
}
if ('bigint' in node) {
return 'bigint value';
}
if (node.value == null) {
return null;
}
return `${typeof node.value} value`;
},
TemplateLiteral: 'string value'
};
exports.default = (0, utils_1.createRule)('no-not-function-handler', {
meta: {
docs: {
description: 'disallow use of not function in event handler',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'Unexpected {{phrase}} in event handler.'
},
type: 'problem'
},
create(context) {
function findRootExpression(node, already = new Set()) {
if (node.type !== 'Identifier' || already.has(node)) {
return node;
}
already.add(node);
const variable = (0, ast_utils_1.findVariable)(context, node);
if (!variable || variable.defs.length !== 1) {
return node;
}
const def = variable.defs[0];
if (def.type === 'Variable') {
if (def.parent.kind === 'const' && def.node.init) {
const init = def.node.init;
return findRootExpression(init, already);
}
}
return node;
}
function verify(node) {
if (!node) {
return;
}
const expression = findRootExpression(node);
if (expression.type !== 'ObjectExpression' &&
expression.type !== 'ArrayExpression' &&
expression.type !== 'ClassExpression' &&
expression.type !== 'Literal' &&
expression.type !== 'TemplateLiteral') {
return;
}
const phraseValue = PHRASES[expression.type];
const phrase = typeof phraseValue === 'function' ? phraseValue(expression) : phraseValue;
if (phrase == null) {
return;
}
context.report({
node,
messageId: 'unexpected',
data: {
phrase
}
});
}
return {
SvelteDirective(node) {
if (node.kind !== 'EventHandler') {
return;
}
verify(node.expression);
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,50 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const PHRASES = {
ObjectExpression: 'object',
ArrayExpression: 'array',
ArrowFunctionExpression: 'function',
FunctionExpression: 'function',
ClassExpression: 'class'
};
exports.default = (0, utils_1.createRule)('no-object-in-text-mustaches', {
meta: {
docs: {
description: 'disallow objects in text mustache interpolation',
category: 'Possible Errors',
recommended: true
},
schema: [],
messages: {
unexpected: 'Unexpected {{phrase}} in text mustache interpolation.'
},
type: 'problem'
},
create(context) {
return {
SvelteMustacheTag(node) {
const { expression } = node;
if (expression.type !== 'ObjectExpression' &&
expression.type !== 'ArrayExpression' &&
expression.type !== 'ArrowFunctionExpression' &&
expression.type !== 'FunctionExpression' &&
expression.type !== 'ClassExpression') {
return;
}
if (node.parent.type === 'SvelteAttribute') {
if (node.parent.value.length === 1) {
return;
}
}
context.report({
node,
messageId: 'unexpected',
data: {
phrase: PHRASES[expression.type]
}
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,49 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-functions', {
meta: {
docs: {
description: "it's not necessary to define functions in reactive statements",
category: 'Best Practices',
recommended: false
},
hasSuggestions: true,
schema: [],
messages: {
noReactiveFns: `Do not create functions inside reactive statements unless absolutely necessary.`,
fixReactiveFns: `Move the function out of the reactive statement`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > ExpressionStatement > AssignmentExpression > :function`](node) {
const parent = node.parent?.parent?.parent;
if (!parent) {
return false;
}
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node: parent,
loc: parent.loc,
messageId: 'noReactiveFns',
suggest: [
{
messageId: 'fixReactiveFns',
fix(fixer) {
const tokens = source.getFirstTokens(parent, {
includeComments: false,
count: 3
});
const noExtraSpace = source.isSpaceBetweenTokens(tokens[1], tokens[2]);
return fixer.replaceTextRange([tokens[0].range[0], tokens[1].range[1]], noExtraSpace ? 'const' : 'const ');
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,51 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-literals', {
meta: {
docs: {
description: "don't assign literal values in reactive statements",
category: 'Best Practices',
recommended: false
},
hasSuggestions: true,
schema: [],
messages: {
noReactiveLiterals: `Do not assign literal values inside reactive statements unless absolutely necessary.`,
fixReactiveLiteral: `Move the literal out of the reactive statement into an assignment`
},
type: 'suggestion'
},
create(context) {
return {
[`SvelteReactiveStatement > ExpressionStatement > AssignmentExpression:matches(${[
`[right.type="Literal"]`,
`[right.type="ArrayExpression"][right.elements.length=0]`,
`[right.type="ObjectExpression"][right.properties.length=0]`
].join(',')})`](node) {
const parent = node.parent?.parent;
if (!parent) {
return false;
}
const source = (0, compat_1.getSourceCode)(context);
return context.report({
node: parent,
loc: parent.loc,
messageId: 'noReactiveLiterals',
suggest: [
{
messageId: 'fixReactiveLiteral',
fix(fixer) {
return [
fixer.insertTextBefore(parent, `let ${source.getText(node)}`),
fixer.remove(parent)
];
}
}
]
});
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,196 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
const eslint_utils_1 = require("@eslint-community/eslint-utils");
const compat_1 = require("../utils/compat");
exports.default = (0, utils_1.createRule)('no-reactive-reassign', {
meta: {
docs: {
description: 'disallow reassigning reactive values',
category: 'Possible Errors',
recommended: false
},
schema: [
{
type: 'object',
properties: {
props: {
type: 'boolean'
}
},
additionalProperties: false
}
],
messages: {
assignmentToReactiveValue: "Assignment to reactive value '{{name}}'.",
assignmentToReactiveValueProp: "Assignment to property of reactive value '{{name}}'."
},
type: 'problem'
},
create(context) {
const props = context.options[0]?.props !== false;
const sourceCode = (0, compat_1.getSourceCode)(context);
const scopeManager = sourceCode.scopeManager;
const globalScope = scopeManager.globalScope;
const toplevelScope = globalScope?.childScopes.find((scope) => scope.type === 'module') || globalScope;
if (!globalScope || !toplevelScope) {
return {};
}
const CHECK_REASSIGN = {
UpdateExpression: ({ parent }) => ({ type: 'reassign', node: parent }),
UnaryExpression: ({ parent }) => {
if (parent.operator === 'delete') {
return { type: 'reassign', node: parent };
}
return null;
},
AssignmentExpression: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
ForInStatement: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
ForOfStatement: ({ node, parent }) => {
if (parent.left === node) {
return { type: 'reassign', node: parent };
}
return null;
},
CallExpression: ({ node, parent, pathNodes }) => {
if (pathNodes.length > 0 && parent.callee === node) {
const mem = pathNodes[pathNodes.length - 1];
const callName = (0, eslint_utils_1.getPropertyName)(mem);
if (callName &&
/^(?:push|pop|shift|unshift|reverse|splice|sort|copyWithin|fill)$/u.test(callName)) {
return {
type: 'reassign',
node: parent,
pathNodes: pathNodes.slice(0, -1)
};
}
}
return null;
},
MemberExpression: ({ node, parent, pathNodes }) => {
if (parent.object === node) {
return {
type: 'check',
node: parent,
pathNodes: [...pathNodes, parent]
};
}
return null;
},
ChainExpression: ({ parent }) => {
return { type: 'check', node: parent };
},
ConditionalExpression: ({ node, parent }) => {
if (parent.test === node) {
return null;
}
return { type: 'check', node: parent };
},
Property: ({ node, parent }) => {
if (parent.value === node && parent.parent && parent.parent.type === 'ObjectPattern') {
return { type: 'check', node: parent.parent };
}
return null;
},
ArrayPattern: ({ node, parent }) => {
if (parent.elements.includes(node)) {
return { type: 'check', node: parent };
}
return null;
},
RestElement: ({ node, parent }) => {
if (parent.argument === node && parent.parent) {
return {
type: 'check',
node: parent.parent
};
}
return null;
},
SvelteDirective: ({ node, parent }) => {
if (parent.kind !== 'Binding') {
return null;
}
if (parent.shorthand || parent.expression === node) {
return {
type: 'reassign',
node: parent
};
}
return null;
}
};
function getReassignData(expr) {
let pathNodes = [];
let node = expr;
let parent;
while ((parent = node.parent)) {
const check = CHECK_REASSIGN[parent.type];
if (!check) {
return null;
}
const result = check({ node, parent, pathNodes });
if (!result) {
return null;
}
pathNodes = result.pathNodes || pathNodes;
if (result.type === 'reassign') {
return {
node: result.node,
pathNodes
};
}
node = result.node;
}
return null;
}
return {
SvelteReactiveStatement(node) {
if (node.body.type !== 'ExpressionStatement' ||
node.body.expression.type !== 'AssignmentExpression' ||
node.body.expression.operator !== '=') {
return;
}
const assignment = node.body.expression;
for (const variable of toplevelScope.variables) {
if (!variable.defs.some((def) => def.node === assignment)) {
continue;
}
for (const reference of variable.references) {
const id = reference.identifier;
if ((assignment.left.range[0] <= id.range[0] &&
id.range[1] <= assignment.left.range[1]) ||
id.type === 'JSXIdentifier') {
continue;
}
const reassign = getReassignData(id);
if (!reassign) {
continue;
}
if (!props && reassign.pathNodes.length > 0)
continue;
context.report({
node: reassign.node,
messageId: reassign.pathNodes.length === 0
? 'assignmentToReactiveValue'
: 'assignmentToReactiveValueProp',
data: {
name: id.name
}
});
}
}
}
};
}
});

View File

@ -0,0 +1,2 @@
declare const _default: import("../types").RuleModule;
export default _default;

View File

@ -0,0 +1,64 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const utils_1 = require("../utils");
exports.default = (0, utils_1.createRule)('no-restricted-html-elements', {
meta: {
docs: {
description: 'disallow specific HTML elements',
category: 'Stylistic Issues',
recommended: false,
conflictWithPrettier: false
},
schema: {
type: 'array',
items: {
oneOf: [
{ type: 'string' },
{
type: 'object',
properties: {
elements: {
type: 'array',
items: {
type: ['string']
},
uniqueItems: true,
minItems: 1
},
message: { type: 'string', minLength: 1 }
},
additionalProperties: false,
minItems: 1
}
]
},
uniqueItems: true,
minItems: 1
},
messages: {},
type: 'suggestion'
},
create(context) {
return {
SvelteElement(node) {
if (node.kind !== 'html')
return;
const { name } = node;
if (name.type !== 'SvelteName')
return;
for (const option of context.options) {
const message = option.message || `Unexpected use of forbidden HTML element ${name.name}.`;
const elements = option.elements || [option];
for (const element of elements) {
if (element === name.name) {
context.report({
message,
node: node.startTag
});
}
}
}
}
};
}
});

Some files were not shown because too many files have changed in this diff Show More