eslint-plugin-svelte
Version:
ESLint plugin for Svelte using AST
250 lines (249 loc) • 11.2 kB
TypeScript
import type { JSONSchema4 } from 'json-schema';
import type { Linter, Rule, SourceCode as ESLintSourceCode } from 'eslint';
import type { AST, StyleContext, SvelteConfig } from 'svelte-eslint-parser';
import type { TSESTree } from '@typescript-eslint/types';
import type { ScopeManager, Scope, Variable } from '@typescript-eslint/scope-manager';
import type { Rule as StyleRule, Node } from 'postcss';
import type { Root as SelectorRoot, Node as SelectorNode } from 'postcss-selector-parser';
import type { ASTNode, ASTNodeWithParent, ASTNodeListener } from './types-for-node.js';
import type * as TS from 'typescript';
import type { SourceLocation } from 'svelte-eslint-parser/lib/ast/common.js';
import type { SvelteContext } from './utils/svelte-context.js';
export type { ASTNode, ASTNodeWithParent, ASTNodeListener };
export interface RuleListener extends ASTNodeListener {
onCodePathStart?(codePath: Rule.CodePath, node: never): void;
onCodePathEnd?(codePath: Rule.CodePath, node: never): void;
onCodePathSegmentStart?(segment: Rule.CodePathSegment, node: never): void;
onCodePathSegmentEnd?(segment: Rule.CodePathSegment, node: never): void;
onCodePathSegmentLoop?(fromSegment: Rule.CodePathSegment, toSegment: Rule.CodePathSegment, node: never): void;
[key: string]: ((codePath: Rule.CodePath, node: never) => void) | ((segment: Rule.CodePathSegment, node: never) => void) | ((fromSegment: Rule.CodePathSegment, toSegment: Rule.CodePathSegment, node: never) => void) | ASTNodeListener[keyof ASTNodeListener] | ((node: never) => void) | undefined;
}
export interface RuleModule {
meta: RuleMetaData;
create: (context: RuleContext) => RuleListener;
}
export type RuleCategory = 'Possible Errors' | 'Security Vulnerability' | 'Best Practices' | 'Stylistic Issues' | 'Extension Rules' | 'SvelteKit' | 'Experimental' | 'System';
export interface RuleMetaData {
docs: {
description: string;
category: RuleCategory;
recommended: boolean | 'base';
extensionRule?: string | {
plugin: string;
url: string;
};
url: string;
ruleId: string;
ruleName: string;
default?: 'error' | 'warn';
conflictWithPrettier?: boolean;
};
messages: {
[messageId: string]: string;
};
fixable?: 'code' | 'whitespace';
hasSuggestions?: boolean;
schema: JSONSchema4 | JSONSchema4[];
deprecated?: boolean;
replacedBy?: string[] | {
note: string;
};
type: 'problem' | 'suggestion' | 'layout';
}
export interface PartialRuleModule {
meta: PartialRuleMetaData;
create: (context: RuleContext) => RuleListener;
}
export interface PartialRuleMetaData {
docs: {
description: string;
recommended: boolean | 'base';
extensionRule?: string | {
plugin: string;
url: string;
};
default?: 'error' | 'warn';
} & ({
category: Exclude<RuleCategory, 'Stylistic Issues'>;
conflictWithPrettier?: boolean;
} | {
category: 'Stylistic Issues';
conflictWithPrettier: boolean;
});
messages: {
[messageId: string]: string;
};
fixable?: 'code' | 'whitespace';
hasSuggestions?: boolean;
schema: JSONSchema4 | JSONSchema4[];
deprecated?: boolean;
replacedBy?: string[] | {
note: string;
};
type: 'problem' | 'suggestion' | 'layout';
/**
* Conditions to determine whether this rule should be applied.
* Multiple conditions can be specified as array, and the rule will be applied if any one of them matches (logical OR).
* If not specified, the rule will be applied to all files.
*/
conditions?: {
svelteVersions?: SvelteContext['svelteVersion'][];
svelteFileTypes?: SvelteContext['svelteFileType'][];
runes?: SvelteContext['runes'][];
svelteKitVersions?: SvelteContext['svelteKitVersion'][];
svelteKitFileTypes?: SvelteContext['svelteKitFileType'][];
}[];
}
export type RuleContext = {
id: string;
options: any[];
settings?: {
svelte?: {
ignoreWarnings?: unknown;
compileOptions?: {
babel?: boolean;
postcss?: false | {
configFilePath?: unknown;
};
};
kit?: {
files?: {
routes?: string;
};
};
};
};
parserPath: string;
parserOptions: Linter.ParserOptions;
parserServices: ESLintSourceCode.ParserServices;
getAncestors(): ASTNode[];
getDeclaredVariables(node: TSESTree.Node): Variable[];
filename: string;
getScope(): Scope;
sourceCode: SourceCode;
markVariableAsUsed(name: string): boolean;
report(descriptor: ReportDescriptor): void;
cwd?: string;
physicalFilename: string;
};
export type NodeOrToken = {
type: string;
loc?: AST.SourceLocation | null;
range?: [number, number];
};
interface ReportDescriptorOptionsBase {
data?: {
[key: string]: string;
};
fix?: null | ((fixer: RuleFixer) => null | Rule.Fix | IterableIterator<Rule.Fix> | Rule.Fix[]);
}
type SuggestionDescriptorMessage = {
desc: string;
} | {
messageId: string;
};
export type SuggestionReportDescriptor = SuggestionDescriptorMessage & ReportDescriptorOptionsBase;
interface ReportDescriptorOptions extends ReportDescriptorOptionsBase {
suggest?: SuggestionReportDescriptor[] | null;
}
type ReportDescriptor = ReportDescriptorMessage & ReportDescriptorLocation & ReportDescriptorOptions;
type ReportDescriptorMessage = {
message: string;
} | {
messageId: string;
};
type ReportDescriptorLocation = {
node: NodeOrToken;
} | {
loc: AST.SourceLocation | {
line: number;
column: number;
};
};
export interface RuleFixer {
insertTextAfter(nodeOrToken: NodeOrToken, text: string): Rule.Fix;
insertTextAfterRange(range: AST.Range, text: string): Rule.Fix;
insertTextBefore(nodeOrToken: NodeOrToken, text: string): Rule.Fix;
insertTextBeforeRange(range: AST.Range, text: string): Rule.Fix;
remove(nodeOrToken: NodeOrToken): Rule.Fix;
removeRange(range: AST.Range): Rule.Fix;
replaceText(nodeOrToken: NodeOrToken, text: string): Rule.Fix;
replaceTextRange(range: AST.Range, text: string): Rule.Fix;
}
export declare namespace SourceCode {
function splitLines(text: string): string[];
}
export interface SourceCode {
text: string;
ast: AST.SvelteProgram;
lines: string[];
hasBOM: boolean;
parserServices: {
isSvelte?: boolean;
isSvelteScript?: boolean;
getSvelteHtmlAst?: () => unknown;
getStyleContext?: () => StyleContext;
getStyleSelectorAST?: (rule: StyleRule) => SelectorRoot;
styleNodeLoc?: (node: Node) => Partial<SourceLocation>;
styleNodeRange?: (node: Node) => [number | undefined, number | undefined];
styleSelectorNodeLoc?: (node: SelectorNode) => Partial<SourceLocation>;
svelteParseContext?: {
/**
* Whether to use Runes mode.
* May be `true` if the user is using Svelte v5.
* Resolved from `svelte.config.js` or `parserOptions`, but may be overridden by `<svelte:options>`.
*/
runes?: boolean;
/** The version of "svelte/compiler". */
compilerVersion?: string;
/** The result of static analysis of `svelte.config.js`. */
svelteConfig?: SvelteConfig | null;
};
program?: TS.Program;
esTreeNodeToTSNodeMap?: ReadonlyMap<unknown, TS.Node>;
tsNodeToESTreeNodeMap?: ReadonlyMap<TS.Node, ASTNode>;
hasFullTypeInformation?: boolean;
[key: string]: unknown;
};
scopeManager: ScopeManager;
visitorKeys: ESLintSourceCode.VisitorKeys;
getText(node?: NodeOrToken, beforeCount?: number, afterCount?: number): string;
getLines(): string[];
getDeclaredVariables(node: TSESTree.Node): Variable[];
getAllComments(): AST.Comment[];
getComments(node: NodeOrToken): {
leading: AST.Comment[];
trailing: AST.Comment[];
};
getJSDocComment(node: NodeOrToken): AST.Comment | null;
getNodeByRangeIndex(index: number): ASTNodeWithParent | null;
isSpaceBetweenTokens(first: AST.Token, second: AST.Token): boolean;
getLocFromIndex(index: number): AST.Position;
getIndexFromLoc(location: AST.Position): number;
getTokenByRangeStart(offset: number, options?: {
includeComments?: boolean;
}): AST.Token | AST.Comment | null;
getFirstToken(node: NodeOrToken): AST.Token;
getFirstToken(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getFirstToken']>[1]): AST.Token | AST.Comment | null;
getFirstTokens(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getFirstTokens']>[1]): (AST.Token | AST.Comment)[];
getLastToken(node: NodeOrToken): AST.Token;
getLastToken(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getLastToken']>[1]): AST.Token | AST.Comment | null;
getLastTokens(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getLastTokens']>[1]): (AST.Token | AST.Comment)[];
getTokenBefore(node: NodeOrToken): AST.Token | null;
getTokenBefore(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getTokenBefore']>[1]): AST.Token | AST.Comment | null;
getTokensBefore(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getTokensBefore']>[1]): (AST.Token | AST.Comment)[];
getTokenAfter(node: NodeOrToken): AST.Token | null;
getTokenAfter(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getTokenAfter']>[1]): AST.Token | AST.Comment | null;
getTokensAfter(node: NodeOrToken, options?: Parameters<ESLintSourceCode['getTokensAfter']>[1]): (AST.Token | AST.Comment)[];
getFirstTokenBetween(left: NodeOrToken, right: NodeOrToken, options?: Parameters<ESLintSourceCode['getFirstTokenBetween']>[2]): AST.Token | AST.Comment | null;
getFirstTokensBetween(left: NodeOrToken, right: NodeOrToken, options?: Parameters<ESLintSourceCode['getFirstTokensBetween']>[2]): (AST.Token | AST.Comment)[];
getLastTokenBetween(left: NodeOrToken, right: NodeOrToken, options?: Parameters<ESLintSourceCode['getLastTokenBetween']>[2]): AST.Token | AST.Comment | null;
getLastTokensBetween(left: NodeOrToken, right: NodeOrToken, options?: Parameters<ESLintSourceCode['getLastTokensBetween']>[2]): (AST.Token | AST.Comment)[];
getTokensBetween(left: NodeOrToken, right: NodeOrToken, padding?: Parameters<ESLintSourceCode['getTokensBetween']>[2]): (AST.Token | AST.Comment)[];
getTokens(node: NodeOrToken, beforeCount?: number, afterCount?: number): AST.Token[];
getTokens(node: NodeOrToken, options: Parameters<ESLintSourceCode['getTokens']>[1]): (AST.Token | AST.Comment)[];
commentsExistBetween(left: NodeOrToken, right: NodeOrToken): boolean;
getCommentsBefore(nodeOrToken: NodeOrToken | AST.Token): AST.Comment[];
getCommentsAfter(nodeOrToken: NodeOrToken | AST.Token): AST.Comment[];
getCommentsInside(node: NodeOrToken): AST.Comment[];
}