diff --git a/src/eslint-plugins/README.md b/src/eslint-plugins/README.md new file mode 100644 index 00000000..ac2637bd --- /dev/null +++ b/src/eslint-plugins/README.md @@ -0,0 +1 @@ +The code in this directory is designed to be used in ESLint plugins, such as `eslint-plugin-vue`. \ No newline at end of file diff --git a/src/eslint-plugins/global.d.ts b/src/eslint-plugins/global.d.ts new file mode 100644 index 00000000..285b3f83 --- /dev/null +++ b/src/eslint-plugins/global.d.ts @@ -0,0 +1,178 @@ +import * as VAST from './types/ast' +import * as VNODE from './types/node' +import * as parserServices from './types/parser-services' +import * as eslint from 'eslint' + +declare global { + // **** Rule Helpers **** + type RuleModule = eslint.Rule.RuleModule + type RuleContext = eslint.Rule.RuleContext + namespace Rule { + type ReportDescriptor = eslint.Rule.ReportDescriptor + type SuggestionReportDescriptor = eslint.Rule.SuggestionReportDescriptor + } + type SourceCode = eslint.SourceCode + namespace SourceCode { + type CursorWithSkipOptions = eslint.SourceCode.CursorWithSkipOptions + type CursorWithCountOptions = eslint.SourceCode.CursorWithCountOptions + } + type RuleFixer = eslint.Rule.RuleFixer + type Fix = eslint.Rule.Fix + + type NodeListener = eslint.Rule.NodeListener + type RuleListener = eslint.Rule.RuleListener + type TemplateListener = parserServices.TemplateListener + type ParserServices = parserServices.ParserServices + namespace ParserServices { + type TokenStore = parserServices.ParserServices.TokenStore + } + + // **** Node data **** + + type Range = VNODE.Range + type Position = VNODE.Position + type SourceLocation = VNODE.SourceLocation + type Token = VNODE.Token + type Comment = VNODE.Comment + type HTMLComment = VNODE.HTMLComment + type HTMLBogusComment = VNODE.HTMLBogusComment + + type NodeListenerMap = VAST.NodeListenerMap + type VNodeListenerMap = VAST.VNodeListenerMap + + // **** AST nodes **** + + type ASTNode = VAST.ASTNode + type ESNode = VAST.ESNode + type VNode = VAST.VNode + type TSNode = VAST.TSNode + type JSXNode = VAST.JSXNode + + // ---- Vue Template Nodes ---- + + type VAttribute = VAST.VAttribute + type VDirective = VAST.VDirective + type VDirectiveKey = VAST.VDirectiveKey + type VDocumentFragment = VAST.VDocumentFragment + type VElement = VAST.VElement + type VRootElement = VAST.VRootElement + type VEndTag = VAST.VEndTag + type VExpressionContainer = VAST.VExpressionContainer + type VIdentifier = VAST.VIdentifier + type VLiteral = VAST.VLiteral + type VStartTag = VAST.VStartTag + type VText = VAST.VText + type VForExpression = VAST.VForExpression + type VOnExpression = VAST.VOnExpression + type VSlotScopeExpression = VAST.VSlotScopeExpression + type VFilterSequenceExpression = VAST.VFilterSequenceExpression + type VFilter = VAST.VFilter + + // ---- ES Nodes ---- + + type Identifier = VAST.Identifier + type Literal = VAST.Literal + type Program = VAST.Program + type SwitchCase = VAST.SwitchCase + type CatchClause = VAST.CatchClause + type VariableDeclarator = VAST.VariableDeclarator + type Statement = VAST.Statement + type ExpressionStatement = VAST.ExpressionStatement + type BlockStatement = VAST.BlockStatement + type EmptyStatement = VAST.EmptyStatement + type DebuggerStatement = VAST.DebuggerStatement + type WithStatement = VAST.WithStatement + type ReturnStatement = VAST.ReturnStatement + type LabeledStatement = VAST.LabeledStatement + type BreakStatement = VAST.BreakStatement + type ContinueStatement = VAST.ContinueStatement + type IfStatement = VAST.IfStatement + type SwitchStatement = VAST.SwitchStatement + type ThrowStatement = VAST.ThrowStatement + type TryStatement = VAST.TryStatement + type WhileStatement = VAST.WhileStatement + type DoWhileStatement = VAST.DoWhileStatement + type ForStatement = VAST.ForStatement + type ForInStatement = VAST.ForInStatement + type ForOfStatement = VAST.ForOfStatement + type Declaration = VAST.Declaration + type FunctionDeclaration = VAST.FunctionDeclaration + type VariableDeclaration = VAST.VariableDeclaration + type ClassDeclaration = VAST.ClassDeclaration + type Expression = VAST.Expression + type ThisExpression = VAST.ThisExpression + type ArrayExpression = VAST.ArrayExpression + type ObjectExpression = VAST.ObjectExpression + type FunctionExpression = VAST.FunctionExpression + type ArrowFunctionExpression = VAST.ArrowFunctionExpression + type YieldExpression = VAST.YieldExpression + type UnaryExpression = VAST.UnaryExpression + type UpdateExpression = VAST.UpdateExpression + type BinaryExpression = VAST.BinaryExpression + type AssignmentExpression = VAST.AssignmentExpression + type LogicalExpression = VAST.LogicalExpression + type MemberExpression = VAST.MemberExpression + type ConditionalExpression = VAST.ConditionalExpression + type CallExpression = VAST.CallExpression + type NewExpression = VAST.NewExpression + type SequenceExpression = VAST.SequenceExpression + type TemplateLiteral = VAST.TemplateLiteral + type TaggedTemplateExpression = VAST.TaggedTemplateExpression + type ClassExpression = VAST.ClassExpression + type MetaProperty = VAST.MetaProperty + type AwaitExpression = VAST.AwaitExpression + type ChainExpression = VAST.ChainExpression + type ChainElement = VAST.ChainElement + type Property = VAST.Property + type AssignmentProperty = VAST.AssignmentProperty + type Super = VAST.Super + type TemplateElement = VAST.TemplateElement + type SpreadElement = VAST.SpreadElement + type Pattern = VAST.Pattern + type ObjectPattern = VAST.ObjectPattern + type ArrayPattern = VAST.ArrayPattern + type RestElement = VAST.RestElement + type AssignmentPattern = VAST.AssignmentPattern + type ClassBody = VAST.ClassBody + type MethodDefinition = VAST.MethodDefinition + type ModuleDeclaration = VAST.ModuleDeclaration + type ImportDeclaration = VAST.ImportDeclaration + type ExportNamedDeclaration = VAST.ExportNamedDeclaration + type ExportDefaultDeclaration = VAST.ExportDefaultDeclaration + type ExportAllDeclaration = VAST.ExportAllDeclaration + type ModuleSpecifier = VAST.ModuleSpecifier + type ImportSpecifier = VAST.ImportSpecifier + type ImportDefaultSpecifier = VAST.ImportDefaultSpecifier + type ImportNamespaceSpecifier = VAST.ImportNamespaceSpecifier + type ExportSpecifier = VAST.ExportSpecifier + type ImportExpression = VAST.ImportExpression + + // ---- TS Nodes ---- + + type TSAsExpression = VAST.TSAsExpression + + // ---- JSX Nodes ---- + + type JSXAttribute = VAST.JSXAttribute + type JSXClosingElement = VAST.JSXClosingElement + type JSXClosingFragment = VAST.JSXClosingFragment + type JSXElement = VAST.JSXElement + type JSXEmptyExpression = VAST.JSXEmptyExpression + type JSXExpressionContainer = VAST.JSXExpressionContainer + type JSXFragment = VAST.JSXFragment + type JSXIdentifier = VAST.JSXIdentifier + type JSXOpeningElement = VAST.JSXOpeningElement + type JSXOpeningFragment = VAST.JSXOpeningFragment + type JSXSpreadAttribute = VAST.JSXSpreadAttribute + type JSXSpreadChild = VAST.JSXSpreadChild + type JSXMemberExpression = VAST.JSXMemberExpression + type JSXText = VAST.JSXText + + // **** Variables **** + + type VVariable = VAST.VVariable + type VReference = VAST.VReference + + type Variable = eslint.Scope.Variable + type Reference = eslint.Scope.Reference +} diff --git a/src/eslint-plugins/types/ast/ast.ts b/src/eslint-plugins/types/ast/ast.ts new file mode 100644 index 00000000..d8f21315 --- /dev/null +++ b/src/eslint-plugins/types/ast/ast.ts @@ -0,0 +1,343 @@ +import * as ES from './es-ast' +import * as V from './v-ast' +import * as TS from './ts-ast' +import * as JSX from './jsx-ast' + +export type ASTNode = ES.ESNode | V.VNode | TS.TSNode | JSX.JSXNode + +export type ParamNode = never // You specify the node type in JSDoc. + +export type VNodeListenerMap = { + VAttribute: V.VAttribute | V.VDirective + 'VAttribute:exit': V.VAttribute | V.VDirective + 'VAttribute[directive=false]': V.VAttribute + 'VAttribute[directive=false]:exit': V.VAttribute + "VAttribute[directive=true][key.name.name='bind']": V.VDirective & { + value: + | (V.VExpressionContainer & { + expression: ES.Expression | V.VFilterSequenceExpression | null + }) + | null + } + "VAttribute[directive=true][key.name.name='bind']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { + expression: ES.Expression | V.VFilterSequenceExpression | null + }) + | null + } + "VAttribute[directive=true][key.name.name='cloak']": V.VDirective + "VAttribute[directive=true][key.name.name='cloak']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='else-if']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='else-if']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='else']": V.VDirective + "VAttribute[directive=true][key.name.name='else']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='for']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: V.VForExpression | null }) + | null + } + "VAttribute[directive=true][key.name.name='for']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: V.VForExpression | null }) + | null + } + "VAttribute[directive=true][key.name.name='html']": V.VDirective + "VAttribute[directive=true][key.name.name='html']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='if']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='if']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='is']": V.VDirective + "VAttribute[directive=true][key.name.name='is']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='model']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='model']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='on']": V.VDirective & { + value: + | (V.VExpressionContainer & { + expression: ES.Expression | V.VOnExpression | null + }) + | null + } + "VAttribute[directive=true][key.name.name='on']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { + expression: ES.Expression | V.VOnExpression | null + }) + | null + } + "VAttribute[directive=true][key.name.name='once']": V.VDirective + "VAttribute[directive=true][key.name.name='once']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='pre']": V.VDirective + "VAttribute[directive=true][key.name.name='pre']:exit": V.VDirective + "VAttribute[directive=true][key.name.name='show']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='show']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: ES.Expression | null }) + | null + } + "VAttribute[directive=true][key.name.name='slot']": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: V.VSlotScopeExpression | null }) + | null + } + "VAttribute[directive=true][key.name.name='slot']:exit": V.VDirective & { + value: + | (V.VExpressionContainer & { expression: V.VSlotScopeExpression | null }) + | null + } + "VAttribute[directive=true][key.name.name='text']": V.VDirective + "VAttribute[directive=true][key.name.name='text']:exit": V.VDirective + 'VAttribute[value!=null]': + | (V.VAttribute & { value: VLiteral }) + | (V.VDirective & { value: VExpressionContainer }) + // VDirective: V.VDirective + // 'VDirective:exit': V.VDirective + VDirectiveKey: V.VDirectiveKey + 'VDirectiveKey:exit': V.VDirectiveKey + VElement: V.VElement + 'VElement:exit': V.VElement + VEndTag: V.VEndTag + 'VEndTag:exit': V.VEndTag + VExpressionContainer: V.VExpressionContainer + 'VExpressionContainer:exit': V.VExpressionContainer + VIdentifier: V.VIdentifier + 'VIdentifier:exit': V.VIdentifier + VLiteral: V.VLiteral + 'VLiteral:exit': V.VLiteral + VStartTag: V.VStartTag + 'VStartTag:exit': V.VStartTag + VText: V.VText + 'VText:exit': V.VText + VForExpression: V.VForExpression + 'VForExpression:exit': V.VForExpression + VOnExpression: V.VOnExpression + 'VOnExpression:exit': V.VOnExpression + VSlotScopeExpression: V.VSlotScopeExpression + 'VSlotScopeExpression:exit': V.VSlotScopeExpression + VFilterSequenceExpression: V.VFilterSequenceExpression + 'VFilterSequenceExpression:exit': V.VFilterSequenceExpression + VFilter: V.VFilter + 'VFilter:exit': V.VFilter +} & ESNodeListenerMap +export type NodeListenerMap = { + JSXAttribute: JSX.JSXAttribute + 'JSXAttribute:exit': JSX.JSXAttribute + JSXClosingElement: JSX.JSXClosingElement + 'JSXClosingElement:exit': JSX.JSXClosingElement + JSXClosingFragment: JSX.JSXClosingFragment + 'JSXClosingFragment:exit': JSX.JSXClosingFragment + JSXElement: JSX.JSXElement + 'JSXElement:exit': JSX.JSXElement + JSXEmptyExpression: JSX.JSXEmptyExpression + 'JSXEmptyExpression:exit': JSX.JSXEmptyExpression + JSXExpressionContainer: JSX.JSXExpressionContainer + 'JSXExpressionContainer:exit': JSX.JSXExpressionContainer + JSXFragment: JSX.JSXFragment + 'JSXFragment:exit': JSX.JSXFragment + JSXIdentifier: JSX.JSXIdentifier + 'JSXIdentifier:exit': JSX.JSXIdentifier + JSXOpeningElement: JSX.JSXOpeningElement + 'JSXOpeningElement:exit': JSX.JSXOpeningElement + JSXOpeningFragment: JSX.JSXOpeningFragment + 'JSXOpeningFragment:exit': JSX.JSXOpeningFragment + JSXSpreadAttribute: JSX.JSXSpreadAttribute + 'JSXSpreadAttribute:exit': JSX.JSXSpreadAttribute + JSXSpreadChild: JSX.JSXSpreadChild + 'JSXSpreadChild:exit': JSX.JSXSpreadChild + JSXMemberExpression: JSX.JSXMemberExpression + 'JSXMemberExpression:exit': JSX.JSXMemberExpression + JSXText: JSX.JSXText + 'JSXText:exit': JSX.JSXText +} & ESNodeListenerMap +export type ESNodeListenerMap = { + Identifier: ES.Identifier + 'Identifier:exit': ES.Identifier + Literal: ES.Literal + 'Literal:exit': ES.Literal + Program: ES.Program + 'Program:exit': ES.Program + SwitchCase: ES.SwitchCase + 'SwitchCase:exit': ES.SwitchCase + CatchClause: ES.CatchClause + 'CatchClause:exit': ES.CatchClause + VariableDeclarator: ES.VariableDeclarator + 'VariableDeclarator:exit': ES.VariableDeclarator + ':statement': ES.Statement + ':statement:exit': ES.Statement + ExpressionStatement: ES.ExpressionStatement + 'ExpressionStatement:exit': ES.ExpressionStatement + BlockStatement: ES.BlockStatement + 'BlockStatement:exit': ES.BlockStatement + EmptyStatement: ES.EmptyStatement + 'EmptyStatement:exit': ES.EmptyStatement + DebuggerStatement: ES.DebuggerStatement + 'DebuggerStatement:exit': ES.DebuggerStatement + WithStatement: ES.WithStatement + 'WithStatement:exit': ES.WithStatement + ReturnStatement: ES.ReturnStatement + 'ReturnStatement:exit': ES.ReturnStatement + LabeledStatement: ES.LabeledStatement + 'LabeledStatement:exit': ES.LabeledStatement + BreakStatement: ES.BreakStatement + 'BreakStatement:exit': ES.BreakStatement + ContinueStatement: ES.ContinueStatement + 'ContinueStatement:exit': ES.ContinueStatement + IfStatement: ES.IfStatement + 'IfStatement:exit': ES.IfStatement + SwitchStatement: ES.SwitchStatement + 'SwitchStatement:exit': ES.SwitchStatement + ThrowStatement: ES.ThrowStatement + 'ThrowStatement:exit': ES.ThrowStatement + TryStatement: ES.TryStatement + 'TryStatement:exit': ES.TryStatement + WhileStatement: ES.WhileStatement + 'WhileStatement:exit': ES.WhileStatement + DoWhileStatement: ES.DoWhileStatement + 'DoWhileStatement:exit': ES.DoWhileStatement + ForStatement: ES.ForStatement + 'ForStatement:exit': ES.ForStatement + ForInStatement: ES.ForInStatement + 'ForInStatement:exit': ES.ForInStatement + ForOfStatement: ES.ForOfStatement + 'ForOfStatement:exit': ES.ForOfStatement + ':declaration': ES.Declaration + ':declaration:exit': ES.Declaration + FunctionDeclaration: ES.FunctionDeclaration + 'FunctionDeclaration:exit': ES.FunctionDeclaration + VariableDeclaration: ES.VariableDeclaration + 'VariableDeclaration:exit': ES.VariableDeclaration + ClassDeclaration: ES.ClassDeclaration + 'ClassDeclaration:exit': ES.ClassDeclaration + ':expression': ES.Expression + ':expression:exit': ES.Expression + ThisExpression: ES.ThisExpression + 'ThisExpression:exit': ES.ThisExpression + ArrayExpression: ES.ArrayExpression + 'ArrayExpression:exit': ES.ArrayExpression + ObjectExpression: ES.ObjectExpression + 'ObjectExpression:exit': ES.ObjectExpression + ':function': + | ES.FunctionExpression + | ES.ArrowFunctionExpression + | ES.FunctionDeclaration + ':function:exit': + | ES.FunctionExpression + | ES.ArrowFunctionExpression + | ES.FunctionDeclaration + FunctionExpression: ES.FunctionExpression + 'FunctionExpression:exit': ES.FunctionExpression + ArrowFunctionExpression: ES.ArrowFunctionExpression + 'ArrowFunctionExpression:exit': ES.ArrowFunctionExpression + YieldExpression: ES.YieldExpression + 'YieldExpression:exit': ES.YieldExpression + UnaryExpression: ES.UnaryExpression + 'UnaryExpression:exit': ES.UnaryExpression + UpdateExpression: ES.UpdateExpression + 'UpdateExpression:exit': ES.UpdateExpression + BinaryExpression: ES.BinaryExpression + 'BinaryExpression:exit': ES.BinaryExpression + AssignmentExpression: ES.AssignmentExpression + 'AssignmentExpression:exit': ES.AssignmentExpression + LogicalExpression: ES.LogicalExpression + 'LogicalExpression:exit': ES.LogicalExpression + MemberExpression: ES.MemberExpression + 'MemberExpression:exit': ES.MemberExpression + ConditionalExpression: ES.ConditionalExpression + 'ConditionalExpression:exit': ES.ConditionalExpression + CallExpression: ES.CallExpression + 'CallExpression:exit': ES.CallExpression + NewExpression: ES.NewExpression + 'NewExpression:exit': ES.NewExpression + SequenceExpression: ES.SequenceExpression + 'SequenceExpression:exit': ES.SequenceExpression + TemplateLiteral: ES.TemplateLiteral + 'TemplateLiteral:exit': ES.TemplateLiteral + TaggedTemplateExpression: ES.TaggedTemplateExpression + 'TaggedTemplateExpression:exit': ES.TaggedTemplateExpression + ClassExpression: ES.ClassExpression + 'ClassExpression:exit': ES.ClassExpression + MetaProperty: ES.MetaProperty + 'MetaProperty:exit': ES.MetaProperty + AwaitExpression: ES.AwaitExpression + 'AwaitExpression:exit': ES.AwaitExpression + Property: ES.Property | ES.AssignmentProperty + 'Property:exit': ES.Property | ES.AssignmentProperty + 'ObjectExpression>Property': ES.Property + 'ObjectExpression>Property:exit': ES.Property + 'ObjectExpression > Property': ES.Property + 'ObjectExpression > Property:exit': ES.Property + 'ObjectPattern>Property': ES.AssignmentProperty + 'ObjectPattern>Property:exit': ES.AssignmentProperty + 'ObjectPattern > Property': ES.AssignmentProperty + 'ObjectPattern > Property:exit': ES.AssignmentProperty + Super: ES.Super + 'Super:exit': ES.Super + TemplateElement: ES.TemplateElement + 'TemplateElement:exit': ES.TemplateElement + SpreadElement: ES.SpreadElement + 'SpreadElement:exit': ES.SpreadElement + ':pattern': ES.Pattern + ':pattern:exit': ES.Pattern + ObjectPattern: ES.ObjectPattern + 'ObjectPattern:exit': ES.ObjectPattern + ArrayPattern: ES.ArrayPattern + 'ArrayPattern:exit': ES.ArrayPattern + RestElement: ES.RestElement + 'RestElement:exit': ES.RestElement + AssignmentPattern: ES.AssignmentPattern + 'AssignmentPattern:exit': ES.AssignmentPattern + ClassBody: ES.ClassBody + 'ClassBody:exit': ES.ClassBody + MethodDefinition: ES.MethodDefinition + 'MethodDefinition:exit': ES.MethodDefinition + ImportDeclaration: ES.ImportDeclaration + 'ImportDeclaration:exit': ES.ImportDeclaration + ExportNamedDeclaration: ES.ExportNamedDeclaration + 'ExportNamedDeclaration:exit': ES.ExportNamedDeclaration + ExportDefaultDeclaration: ES.ExportDefaultDeclaration + 'ExportDefaultDeclaration:exit': ES.ExportDefaultDeclaration + ExportAllDeclaration: ES.ExportAllDeclaration + 'ExportAllDeclaration:exit': ES.ExportAllDeclaration + ImportSpecifier: ES.ImportSpecifier + 'ImportSpecifier:exit': ES.ImportSpecifier + ImportDefaultSpecifier: ES.ImportDefaultSpecifier + 'ImportDefaultSpecifier:exit': ES.ImportDefaultSpecifier + ImportNamespaceSpecifier: ES.ImportNamespaceSpecifier + 'ImportNamespaceSpecifier:exit': ES.ImportNamespaceSpecifier + ExportSpecifier: ES.ExportSpecifier + 'ExportSpecifier:exit': ES.ExportSpecifier + ImportExpression: ES.ImportExpression + 'ImportExpression:exit': ES.ImportExpression + ChainExpression: ES.ChainExpression + 'ChainExpression:exit': ES.ChainExpression + + TSAsExpression: TS.TSAsExpression + 'TSAsExpression:exit': TS.TSAsExpression +} diff --git a/src/eslint-plugins/types/ast/es-ast.ts b/src/eslint-plugins/types/ast/es-ast.ts new file mode 100644 index 00000000..9af1e7d0 --- /dev/null +++ b/src/eslint-plugins/types/ast/es-ast.ts @@ -0,0 +1,543 @@ +/** + * @see https://github.com/estree/estree + */ +import { BaseNode, HasParentNode } from '../node' +import { Token } from '../node' +import { ParseError } from '../errors' +import * as V from './v-ast' +import * as TS from './ts-ast' +import * as JSX from './jsx-ast' + +export type ESNode = + | Identifier + | Literal + | Program + | SwitchCase + | CatchClause + | VariableDeclarator + | Statement + | Expression + | Property + | AssignmentProperty + | Super + | TemplateElement + | SpreadElement + | Pattern + | ClassBody + | MethodDefinition + | ModuleDeclaration + | ModuleSpecifier + +export interface Program extends BaseNode { + type: 'Program' + sourceType: 'script' | 'module' + body: (Statement | ModuleDeclaration)[] + templateBody?: V.VRootElement + tokens: Token[] + comments: Token[] + errors: ParseError[] + parent: null +} +export type Statement = + | ExpressionStatement + | BlockStatement + | EmptyStatement + | DebuggerStatement + | WithStatement + | ReturnStatement + | LabeledStatement + | BreakStatement + | ContinueStatement + | IfStatement + | SwitchStatement + | ThrowStatement + | TryStatement + | WhileStatement + | DoWhileStatement + | ForStatement + | ForInStatement + | ForOfStatement + | Declaration +export interface EmptyStatement extends HasParentNode { + type: 'EmptyStatement' +} +export interface BlockStatement extends HasParentNode { + type: 'BlockStatement' + body: Statement[] +} +export interface ExpressionStatement extends HasParentNode { + type: 'ExpressionStatement' + expression: Expression +} +export interface IfStatement extends HasParentNode { + type: 'IfStatement' + test: Expression + consequent: Statement + alternate: Statement | null +} +export interface SwitchStatement extends HasParentNode { + type: 'SwitchStatement' + discriminant: Expression + cases: SwitchCase[] +} +export interface SwitchCase extends HasParentNode { + type: 'SwitchCase' + test: Expression | null + consequent: Statement[] +} +export interface WhileStatement extends HasParentNode { + type: 'WhileStatement' + test: Expression + body: Statement +} +export interface DoWhileStatement extends HasParentNode { + type: 'DoWhileStatement' + body: Statement + test: Expression +} +export interface ForStatement extends HasParentNode { + type: 'ForStatement' + init: VariableDeclaration | Expression | null + test: Expression | null + update: Expression | null + body: Statement +} +export interface ForInStatement extends HasParentNode { + type: 'ForInStatement' + left: VariableDeclaration | Pattern + right: Expression + body: Statement +} +export interface ForOfStatement extends HasParentNode { + type: 'ForOfStatement' + left: VariableDeclaration | Pattern + right: Expression + body: Statement + await: boolean +} +export interface LabeledStatement extends HasParentNode { + type: 'LabeledStatement' + label: Identifier + body: Statement +} +export interface BreakStatement extends HasParentNode { + type: 'BreakStatement' + label: Identifier | null +} +export interface ContinueStatement extends HasParentNode { + type: 'ContinueStatement' + label: Identifier | null +} +export interface ReturnStatement extends HasParentNode { + type: 'ReturnStatement' + argument: Expression | null +} +export interface ThrowStatement extends HasParentNode { + type: 'ThrowStatement' + argument: Expression +} +export interface TryStatement extends HasParentNode { + type: 'TryStatement' + block: BlockStatement + handler: CatchClause | null + finalizer: BlockStatement | null +} +export interface CatchClause extends HasParentNode { + type: 'CatchClause' + param: Pattern | null + body: BlockStatement +} +export interface WithStatement extends HasParentNode { + type: 'WithStatement' + object: Expression + body: Statement +} +export interface DebuggerStatement extends HasParentNode { + type: 'DebuggerStatement' +} +export type Declaration = + | FunctionDeclaration + | VariableDeclaration + | ClassDeclaration +export interface FunctionDeclaration extends HasParentNode { + type: 'FunctionDeclaration' + async: boolean + generator: boolean + id: Identifier | null + params: _FunctionParameter[] + body: BlockStatement +} +export interface VariableDeclaration extends HasParentNode { + type: 'VariableDeclaration' + kind: 'var' | 'let' | 'const' + declarations: VariableDeclarator[] +} +export interface VariableDeclarator extends HasParentNode { + type: 'VariableDeclarator' + id: Pattern + init: Expression | null +} +export interface ClassDeclaration extends HasParentNode { + type: 'ClassDeclaration' + id: Identifier | null + superClass: Expression | null + body: ClassBody +} +export interface ClassBody extends HasParentNode { + type: 'ClassBody' + body: MethodDefinition[] +} +export interface MethodDefinition extends HasParentNode { + type: 'MethodDefinition' + kind: 'constructor' | 'method' | 'get' | 'set' + computed: boolean + static: boolean + key: Expression + value: FunctionExpression +} +export type ModuleDeclaration = + | ImportDeclaration + | ExportNamedDeclaration + | ExportDefaultDeclaration + | ExportAllDeclaration +export type ModuleSpecifier = + | ImportSpecifier + | ImportDefaultSpecifier + | ImportNamespaceSpecifier + | ExportSpecifier +export interface ImportDeclaration extends HasParentNode { + type: 'ImportDeclaration' + specifiers: ( + | ImportSpecifier + | ImportDefaultSpecifier + | ImportNamespaceSpecifier + )[] + source: Literal +} +export interface ImportSpecifier extends HasParentNode { + type: 'ImportSpecifier' + imported: Identifier + local: Identifier +} +export interface ImportDefaultSpecifier extends HasParentNode { + type: 'ImportDefaultSpecifier' + local: Identifier +} +export interface ImportNamespaceSpecifier extends HasParentNode { + type: 'ImportNamespaceSpecifier' + local: Identifier +} +export interface ExportNamedDeclaration extends HasParentNode { + type: 'ExportNamedDeclaration' + declaration?: Declaration | null + specifiers: ExportSpecifier[] + source?: Literal | null +} +export interface ExportSpecifier extends HasParentNode { + type: 'ExportSpecifier' + exported: Identifier +} +export interface ExportDefaultDeclaration extends HasParentNode { + type: 'ExportDefaultDeclaration' + declaration: Declaration | Expression +} +export interface ExportAllDeclaration extends HasParentNode { + type: 'ExportAllDeclaration' + source: Literal + exported: Identifier | null +} +export interface ImportExpression extends HasParentNode { + type: 'ImportExpression' + source: Expression +} +export type Expression = + | ThisExpression + | ArrayExpression + | ObjectExpression + | FunctionExpression + | ArrowFunctionExpression + | YieldExpression + | Literal + | UnaryExpression + | UpdateExpression + | BinaryExpression + | AssignmentExpression + | LogicalExpression + | MemberExpression + | ConditionalExpression + | CallExpression + | NewExpression + | SequenceExpression + | TemplateLiteral + | TaggedTemplateExpression + | ClassExpression + | MetaProperty + | Identifier + | AwaitExpression + | ImportExpression + | ChainExpression + | JSX.JSXElement + | JSX.JSXFragment + | TS.TSAsExpression + +export interface Identifier extends HasParentNode { + type: 'Identifier' + name: string +} +export interface Literal extends HasParentNode { + type: 'Literal' + value: string | boolean | null | number | RegExp | BigInt + regex?: { + pattern: string + flags: string + } + bigint?: string +} +export interface ThisExpression extends HasParentNode { + type: 'ThisExpression' +} +export interface ArrayExpression extends HasParentNode { + type: 'ArrayExpression' + elements: (Expression | SpreadElement | null)[] +} +export interface ObjectExpression extends HasParentNode { + type: 'ObjectExpression' + properties: (Property | SpreadElement)[] +} +export interface Property extends HasParentNode { + type: 'Property' + kind: 'init' | 'get' | 'set' + method: boolean + shorthand: boolean + computed: boolean + key: Expression + value: Expression + parent: ObjectExpression +} +export interface FunctionExpression extends HasParentNode { + type: 'FunctionExpression' + async: boolean + generator: boolean + id: Identifier | null + params: _FunctionParameter[] + body: BlockStatement +} + +interface ArrowFunctionExpressionHasBlock extends HasParentNode { + type: 'ArrowFunctionExpression' + async: boolean + generator: boolean + id: Identifier | null + params: _FunctionParameter[] + body: BlockStatement + expression: false +} + +interface ArrowFunctionExpressionNoBlock extends HasParentNode { + type: 'ArrowFunctionExpression' + async: boolean + generator: boolean + id: Identifier | null + params: _FunctionParameter[] + body: Expression + expression: true +} + +export type ArrowFunctionExpression = + | ArrowFunctionExpressionNoBlock + | ArrowFunctionExpressionHasBlock + +export interface SequenceExpression extends HasParentNode { + type: 'SequenceExpression' + expressions: Expression[] +} +export type UnaryOperator = '-' | '+' | '!' | '~' | 'typeof' | 'void' | 'delete' +export interface UnaryExpression extends HasParentNode { + type: 'UnaryExpression' + operator: UnaryOperator + prefix: boolean + argument: Expression +} +export type BinaryOperator = + | '==' + | '!=' + | '===' + | '!==' + | '<' + | '<=' + | '>' + | '>=' + | '<<' + | '>>' + | '>>>' + | '+' + | '-' + | '*' + | '/' + | '%' + | '|' + | '^' + | '&' + | 'in' + | 'instanceof' + | '**' +export interface BinaryExpression extends HasParentNode { + type: 'BinaryExpression' + operator: BinaryOperator + left: Expression + right: Expression +} +export type AssignmentOperator = + | '=' + | '+=' + | '-=' + | '*=' + | '/=' + | '%=' + | '<<=' + | '>>=' + | '>>>=' + | '|=' + | '^=' + | '&=' + | '**=' + | '||=' + | '&&=' + | '??=' +export interface AssignmentExpression extends HasParentNode { + type: 'AssignmentExpression' + operator: AssignmentOperator + left: Pattern + right: Expression +} +export type UpdateOperator = '++' | '--' +export interface UpdateExpression extends HasParentNode { + type: 'UpdateExpression' + operator: UpdateOperator + argument: Expression + prefix: boolean +} +export type LogicalOperator = '||' | '&&' | '??' +export interface LogicalExpression extends HasParentNode { + type: 'LogicalExpression' + operator: LogicalOperator + left: Expression + right: Expression +} +export interface ConditionalExpression extends HasParentNode { + type: 'ConditionalExpression' + test: Expression + alternate: Expression + consequent: Expression +} +export interface CallExpression extends HasParentNode { + type: 'CallExpression' + callee: Expression | Super + arguments: (Expression | SpreadElement)[] + optional: boolean +} +export interface Super extends HasParentNode { + type: 'Super' +} +export interface NewExpression extends HasParentNode { + type: 'NewExpression' + callee: Expression + arguments: (Expression | SpreadElement)[] +} +export interface MemberExpression extends HasParentNode { + type: 'MemberExpression' + computed: boolean + object: Expression | Super + property: Expression + optional: boolean +} +export interface ChainExpression extends HasParentNode { + type: 'ChainExpression' + expression: ChainElement +} +export type ChainElement = CallExpression | MemberExpression +export interface YieldExpression extends HasParentNode { + type: 'YieldExpression' + delegate: boolean + argument: Expression | null +} +export interface AwaitExpression extends HasParentNode { + type: 'AwaitExpression' + argument: Expression +} +export interface TemplateLiteral extends HasParentNode { + type: 'TemplateLiteral' + quasis: TemplateElement[] + expressions: Expression[] +} +export interface TaggedTemplateExpression extends HasParentNode { + type: 'TaggedTemplateExpression' + tag: Expression + quasi: TemplateLiteral +} +export interface TemplateElement extends HasParentNode { + type: 'TemplateElement' + tail: boolean + value: { + cooked: string + // cooked: string | null // If the template literal is tagged and the text has an invalid escape, `cooked` will be `null`, e.g., `` tag`\unicode and \u{55}` `` + raw: string + } +} +export interface ClassExpression extends HasParentNode { + type: 'ClassExpression' + id: Identifier | null + superClass: Expression | null + body: ClassBody +} +export interface MetaProperty extends HasParentNode { + type: 'MetaProperty' + meta: Identifier + property: Identifier +} +export type Pattern = + | Identifier + | ObjectPattern + | ArrayPattern + | RestElement + | AssignmentPattern + | MemberExpression +export interface ObjectPattern extends HasParentNode { + type: 'ObjectPattern' + properties: (AssignmentProperty | RestElement)[] +} +export interface AssignmentProperty extends HasParentNode { + type: 'Property' + kind: 'init' + method: false + shorthand: boolean + computed: boolean + key: Expression + value: Pattern + parent: ObjectPattern +} +export interface ArrayPattern extends HasParentNode { + type: 'ArrayPattern' + elements: Pattern[] +} +export interface RestElement extends HasParentNode { + type: 'RestElement' + argument: Pattern +} +export interface SpreadElement extends HasParentNode { + type: 'SpreadElement' + argument: Expression +} +export interface AssignmentPattern extends HasParentNode { + type: 'AssignmentPattern' + left: Pattern + right: Expression +} + +export type _FunctionParameter = + | AssignmentPattern + | RestElement + | ArrayPattern + | ObjectPattern + | Identifier +// | TSParameterProperty; diff --git a/src/eslint-plugins/types/ast/index.ts b/src/eslint-plugins/types/ast/index.ts new file mode 100644 index 00000000..5372ff3e --- /dev/null +++ b/src/eslint-plugins/types/ast/index.ts @@ -0,0 +1,5 @@ +export * from './ast' +export * from './es-ast' +export * from './v-ast' +export * from './ts-ast' +export * from './jsx-ast' diff --git a/src/eslint-plugins/types/ast/jsx-ast.ts b/src/eslint-plugins/types/ast/jsx-ast.ts new file mode 100644 index 00000000..4f1b04af --- /dev/null +++ b/src/eslint-plugins/types/ast/jsx-ast.ts @@ -0,0 +1,106 @@ +/** + * @see https://github.com/facebook/jsx/blob/master/AST.md + * @see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/typescript-estree/src/ts-estree/ts-estree.ts + */ +import { HasParentNode } from '../node' +import * as ES from './es-ast' + +export type JSXNode = + | JSXAttribute + | JSXClosingElement + | JSXClosingFragment + | JSXElement + | JSXEmptyExpression + | JSXExpressionContainer + | JSXFragment + | JSXIdentifier + | JSXOpeningElement + | JSXOpeningFragment + | JSXSpreadAttribute + | JSXSpreadChild + | JSXMemberExpression + | JSXText + +export type JSXChild = JSXElement | JSXExpression | JSXFragment | JSXText +export type JSXExpression = + | JSXEmptyExpression + | JSXSpreadChild + | JSXExpressionContainer +export type JSXTagNameExpression = JSXIdentifier | JSXMemberExpression + +export interface JSXAttribute extends HasParentNode { + type: 'JSXAttribute' + name: JSXIdentifier + value: ES.Literal | JSXExpression | null +} + +export interface JSXClosingElement extends HasParentNode { + type: 'JSXClosingElement' + name: JSXTagNameExpression +} + +export interface JSXClosingFragment extends HasParentNode { + type: 'JSXClosingFragment' +} + +export interface JSXElement extends HasParentNode { + type: 'JSXElement' + openingElement: JSXOpeningElement + closingElement: JSXClosingElement | null + children: JSXChild[] +} + +export interface JSXEmptyExpression extends HasParentNode { + type: 'JSXEmptyExpression' +} + +export interface JSXExpressionContainer extends HasParentNode { + type: 'JSXExpressionContainer' + expression: ES.Expression | JSXEmptyExpression +} + +export interface JSXFragment extends HasParentNode { + type: 'JSXFragment' + openingFragment: JSXOpeningFragment + closingFragment: JSXClosingFragment + children: JSXChild[] +} + +export interface JSXIdentifier extends HasParentNode { + type: 'JSXIdentifier' + name: string +} + +export interface JSXMemberExpression extends HasParentNode { + type: 'JSXMemberExpression' + object: JSXTagNameExpression + property: JSXIdentifier +} + +export interface JSXOpeningElement extends HasParentNode { + type: 'JSXOpeningElement' + // typeParameters?: TSTypeParameterInstantiation; + selfClosing: boolean + name: JSXTagNameExpression + attributes: JSXAttribute[] +} + +export interface JSXOpeningFragment extends HasParentNode { + type: 'JSXOpeningFragment' +} + +export interface JSXSpreadAttribute extends HasParentNode { + type: 'JSXSpreadAttribute' + argument: ES.Expression +} + +export interface JSXSpreadChild extends HasParentNode { + type: 'JSXSpreadChild' + expression: ES.Expression | JSXEmptyExpression +} + +export interface JSXText extends HasParentNode { + type: 'JSXText' + value: string + raw: string +} diff --git a/src/eslint-plugins/types/ast/ts-ast.ts b/src/eslint-plugins/types/ast/ts-ast.ts new file mode 100644 index 00000000..28dc29fe --- /dev/null +++ b/src/eslint-plugins/types/ast/ts-ast.ts @@ -0,0 +1,11 @@ +/** + * @see https://github.com/typescript-eslint/typescript-eslint/blob/master/packages/typescript-estree/src/ts-estree/ts-estree.ts + */ +import { HasParentNode } from '../node' +import * as ES from './es-ast' +export type TSNode = TSAsExpression + +export interface TSAsExpression extends HasParentNode { + type: 'TSAsExpression' + expression: ES.Expression +} diff --git a/src/eslint-plugins/types/ast/v-ast.ts b/src/eslint-plugins/types/ast/v-ast.ts new file mode 100644 index 00000000..fe0ac637 --- /dev/null +++ b/src/eslint-plugins/types/ast/v-ast.ts @@ -0,0 +1,174 @@ +/** + * @see https://github.com/vuejs/vue-eslint-parser/blob/master/docs/ast.md + */ +import { HasParentNode, BaseNode } from '../node' +import { Token, HTMLComment, HTMLBogusComment, Comment } from '../node' +import { ParseError } from '../errors' +import * as ES from './es-ast' + +export type NS = { + HTML: 'http://www.w3.org/1999/xhtml' + MathML: 'http://www.w3.org/1998/Math/MathML' + SVG: 'http://www.w3.org/2000/svg' + XLink: 'http://www.w3.org/1999/xlink' + XML: 'http://www.w3.org/XML/1998/namespace' + XMLNS: 'http://www.w3.org/2000/xmlns/' +} +export type Namespace = + | NS['HTML'] + | NS['MathML'] + | NS['SVG'] + | NS['XLink'] + | NS['XML'] + | NS['XMLNS'] +export interface VVariable { + id: ES.Identifier + kind: 'v-for' | 'scope' + references: VReference[] +} +export interface VReference { + id: ES.Identifier + mode: 'rw' | 'r' | 'w' + variable: VVariable | null +} +export interface VForExpression extends HasParentNode { + type: 'VForExpression' + parent: VExpressionContainer + left: ES.Pattern[] + right: ES.Expression +} +export interface VOnExpression extends HasParentNode { + type: 'VOnExpression' + parent: VExpressionContainer + body: ES.Statement[] +} +export interface VSlotScopeExpression extends HasParentNode { + type: 'VSlotScopeExpression' + parent: VExpressionContainer + params: ES._FunctionParameter[] +} +export interface VFilterSequenceExpression extends HasParentNode { + type: 'VFilterSequenceExpression' + parent: VExpressionContainer + expression: ES.Expression + filters: VFilter[] +} +export interface VFilter extends HasParentNode { + type: 'VFilter' + parent: VFilterSequenceExpression + callee: ES.Identifier + arguments: (ES.Expression | ES.SpreadElement)[] +} +export type VNode = + | VAttribute + | VDirective + | VDirectiveKey + | VElement + | VEndTag + | VExpressionContainer + | VIdentifier + | VLiteral + | VStartTag + | VText + | VDocumentFragment + | VForExpression + | VOnExpression + | VSlotScopeExpression + | VFilterSequenceExpression + | VFilter + +export interface VText extends HasParentNode { + type: 'VText' + parent: VDocumentFragment | VElement + value: string +} +export interface VExpressionContainer extends HasParentNode { + type: 'VExpressionContainer' + parent: VDocumentFragment | VElement | VDirective | VDirectiveKey + expression: + | ES.Expression + | VFilterSequenceExpression + | VForExpression + | VOnExpression + | VSlotScopeExpression + | null + references: VReference[] +} +export interface VIdentifier extends HasParentNode { + type: 'VIdentifier' + parent: VAttribute | VDirectiveKey + name: string + rawName: string +} +export interface VDirectiveKey extends HasParentNode { + type: 'VDirectiveKey' + parent: VDirective + name: VIdentifier + argument: VExpressionContainer | VIdentifier | null + modifiers: VIdentifier[] +} +export interface VLiteral extends HasParentNode { + type: 'VLiteral' + parent: VAttribute + value: string +} +export interface VAttribute extends HasParentNode { + type: 'VAttribute' + parent: VStartTag + directive: false + key: VIdentifier + value: VLiteral | null +} +export interface VDirective extends HasParentNode { + type: 'VAttribute' + parent: VStartTag + directive: true + key: VDirectiveKey + value: VExpressionContainer | null +} +export interface VStartTag extends HasParentNode { + type: 'VStartTag' + parent: VElement + selfClosing: boolean + attributes: (VAttribute | VDirective)[] +} +export interface VEndTag extends HasParentNode { + type: 'VEndTag' + parent: VElement +} +interface HasConcreteInfo { + tokens: Token[] + comments: (HTMLComment | HTMLBogusComment | Comment)[] + errors: ParseError[] +} +export interface VRootElement extends HasParentNode, HasConcreteInfo { + type: 'VElement' + parent: VDocumentFragment + namespace: Namespace + name: string + rawName: string + startTag: VStartTag + children: (VElement | VText | VExpressionContainer)[] + endTag: VEndTag | null + variables: VVariable[] +} + +interface VChildElement extends HasParentNode { + type: 'VElement' + parent: VRootElement | VElement + namespace: Namespace + name: string + rawName: string + startTag: VStartTag + children: (VElement | VText | VExpressionContainer)[] + endTag: VEndTag | null + variables: VVariable[] +} + +export type VElement = VChildElement | VRootElement + +export interface VDocumentFragment extends BaseNode, HasConcreteInfo { + type: 'VDocumentFragment' + parent: null + children: (VElement | VText | VExpressionContainer)[] +} diff --git a/src/eslint-plugins/types/errors.ts b/src/eslint-plugins/types/errors.ts new file mode 100644 index 00000000..213e8038 --- /dev/null +++ b/src/eslint-plugins/types/errors.ts @@ -0,0 +1,43 @@ +export interface ParseError extends SyntaxError { + code?: VParseErrorCode + index: number + lineNumber: number + column: number +} +type VParseErrorCode = + | 'abrupt-closing-of-empty-comment' + | 'absence-of-digits-in-numeric-character-reference' + | 'cdata-in-html-content' + | 'character-reference-outside-unicode-range' + | 'control-character-in-input-stream' + | 'control-character-reference' + | 'eof-before-tag-name' + | 'eof-in-cdata' + | 'eof-in-comment' + | 'eof-in-tag' + | 'incorrectly-closed-comment' + | 'incorrectly-opened-comment' + | 'invalid-first-character-of-tag-name' + | 'missing-attribute-value' + | 'missing-end-tag-name' + | 'missing-semicolon-after-character-reference' + | 'missing-whitespace-between-attributes' + | 'nested-comment' + | 'noncharacter-character-reference' + | 'noncharacter-in-input-stream' + | 'null-character-reference' + | 'surrogate-character-reference' + | 'surrogate-in-input-stream' + | 'unexpected-character-in-attribute-name' + | 'unexpected-character-in-unquoted-attribute-value' + | 'unexpected-equals-sign-before-attribute-name' + | 'unexpected-null-character' + | 'unexpected-question-mark-instead-of-tag-name' + | 'unexpected-solidus-in-tag' + | 'unknown-named-character-reference' + | 'end-tag-with-attributes' + | 'duplicate-attribute' + | 'end-tag-with-trailing-solidus' + | 'non-void-html-element-start-tag-with-trailing-solidus' + | 'x-invalid-end-tag' + | 'x-invalid-namespace' diff --git a/src/eslint-plugins/types/node/index.ts b/src/eslint-plugins/types/node/index.ts new file mode 100644 index 00000000..b51b688c --- /dev/null +++ b/src/eslint-plugins/types/node/index.ts @@ -0,0 +1,3 @@ +export * from './locations' +export * from './tokens' +export * from './node' diff --git a/src/eslint-plugins/types/node/locations.ts b/src/eslint-plugins/types/node/locations.ts new file mode 100644 index 00000000..78a4e641 --- /dev/null +++ b/src/eslint-plugins/types/node/locations.ts @@ -0,0 +1,13 @@ +export interface Position { + line: number + column: number +} +export interface SourceLocation { + start: Position + end: Position +} +export type Range = [number, number] +export interface HasLocation { + range: Range + loc: SourceLocation +} diff --git a/src/eslint-plugins/types/node/node.ts b/src/eslint-plugins/types/node/node.ts new file mode 100644 index 00000000..93dee902 --- /dev/null +++ b/src/eslint-plugins/types/node/node.ts @@ -0,0 +1,11 @@ +import { HasLocation } from './locations' +import * as VAST from '../ast' + +export interface BaseNode extends HasLocation { + type: string + parent: VAST.ASTNode | null +} + +export interface HasParentNode extends BaseNode { + parent: VAST.ASTNode +} diff --git a/src/eslint-plugins/types/node/tokens.ts b/src/eslint-plugins/types/node/tokens.ts new file mode 100644 index 00000000..fd765281 --- /dev/null +++ b/src/eslint-plugins/types/node/tokens.ts @@ -0,0 +1,17 @@ +import { HasLocation } from './locations' +export interface Token extends HasLocation { + type: string + value: string +} +export interface Comment extends Token { + type: 'Line' | 'Block' + value: string +} +export interface HTMLComment extends Token { + type: 'HTMLComment' + value: string +} +export interface HTMLBogusComment extends Token { + type: 'HTMLBogusComment' + value: string +} diff --git a/src/eslint-plugins/types/parser-services.ts b/src/eslint-plugins/types/parser-services.ts new file mode 100644 index 00000000..8f6e2a62 --- /dev/null +++ b/src/eslint-plugins/types/parser-services.ts @@ -0,0 +1,122 @@ +import * as VNODE from './node' +import * as VAST from './ast' +import * as eslint from 'eslint' + +type TemplateListenerBase = { + [T in keyof VAST.VNodeListenerMap]?: (node: VAST.VNodeListenerMap[T]) => void +} +export interface TemplateListener + extends TemplateListenerBase, + eslint.Rule.NodeListener { + [key: string]: ((node: VAST.ParamNode) => void) | undefined +} + +export interface ParserServices { + getTemplateBodyTokenStore: () => ParserServices.TokenStore + defineTemplateBodyVisitor?: ( + templateBodyVisitor: TemplateListener, + scriptVisitor?: eslint.Rule.RuleListener + ) => eslint.Rule.RuleListener + getDocumentFragment?: () => VAST.VDocumentFragment | null +} +export namespace ParserServices { + export interface TokenStore { + getTokenByRangeStart( + offset: number, + options?: { includeComments: boolean } + ): VNODE.Token | null + getFirstToken(node: VNODE.HasLocation): VNODE.Token + getFirstToken(node: VNODE.HasLocation, options: number): VNODE.Token + getFirstToken( + node: VNODE.HasLocation, + options: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getLastToken(node: VNODE.HasLocation): VNODE.Token + getLastToken(node: VNODE.HasLocation, options: number): VNODE.Token + getLastToken( + node: VNODE.HasLocation, + options: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getTokenBefore(node: VNODE.HasLocation): VNODE.Token + getTokenBefore(node: VNODE.HasLocation, options: number): VNODE.Token + getTokenBefore( + node: VNODE.HasLocation, + options: { includeComments: boolean } + ): VNODE.Token + getTokenBefore( + node: VNODE.HasLocation, + options: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getTokenAfter(node: VNODE.HasLocation): VNODE.Token + getTokenAfter(node: VNODE.HasLocation, options: number): VNODE.Token + getTokenAfter( + node: VNODE.HasLocation, + options: { includeComments: boolean } + ): VNODE.Token + getTokenAfter( + node: VNODE.HasLocation, + options: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getFirstTokenBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getLastTokenBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithSkipOptions + ): VNODE.Token | null + getTokenOrCommentBefore( + node: VNODE.HasLocation, + skip?: number + ): VNODE.Token | null + getTokenOrCommentAfter( + node: VNODE.HasLocation, + skip?: number + ): VNODE.Token | null + getFirstTokens( + node: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getLastTokens( + node: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getTokensBefore( + node: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getTokensAfter( + node: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getFirstTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getLastTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + getTokens( + node: VNODE.HasLocation, + beforeCount?: eslint.SourceCode.CursorWithCountOptions, + afterCount?: number + ): VNODE.Token[] + getTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + padding?: eslint.SourceCode.CursorWithCountOptions + ): VNODE.Token[] + commentsExistBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation + ): boolean + getCommentsBefore(nodeOrToken: VNODE.HasLocation): VNODE.Token[] + getCommentsAfter(nodeOrToken: VNODE.HasLocation): VNODE.Token[] + getCommentsInside(node: VNODE.HasLocation): VNODE.Token[] + } +} diff --git a/src/eslint-plugins/types/utils.ts b/src/eslint-plugins/types/utils.ts new file mode 100644 index 00000000..6888e9a4 --- /dev/null +++ b/src/eslint-plugins/types/utils.ts @@ -0,0 +1,29 @@ +import * as VAST from './ast' +export type VueObjectType = 'mark' | 'export' | 'definition' | 'instance' +export type VueObjectData = { + node: ObjectExpression + type: VueObjectType + parent: VueObjectData | null + functional: boolean +} +type VueVisitorBase = { + [T in keyof NodeListenerMap]?: ( + node: NodeListenerMap[T], + obj: VueObjectData + ) => void +} +export interface VueVisitor extends VueVisitorBase { + onVueObjectEnter?(node: ObjectExpression, obj: VueObjectData): void + onVueObjectExit?(node: ObjectExpression, obj: VueObjectData): void + onSetupFunctionEnter?( + node: (FunctionExpression | ArrowFunctionExpression) & { parent: Property }, + obj: VueObjectData + ): void + onRenderFunctionEnter?( + node: (FunctionExpression | ArrowFunctionExpression) & { parent: Property }, + obj: VueObjectData + ): void + [query: string]: + | ((node: VAST.ParamNode, obj: VueObjectData) => void) + | undefined +} diff --git a/src/eslint-plugins/utils/casing.ts b/src/eslint-plugins/utils/casing.ts new file mode 100644 index 00000000..bd30fe7a --- /dev/null +++ b/src/eslint-plugins/utils/casing.ts @@ -0,0 +1,165 @@ +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +/** + * Capitalize a string. + */ +export function capitalize(str: string) { + return str.charAt(0).toUpperCase() + str.slice(1) +} + +/** + * Checks whether the given string has symbols. + */ +function hasSymbols(str: string) { + return /[!"#%&'()*+,./:;<=>?@[\\\]^`{|}]/u.exec(str) // without " ", "$", "-" and "_" +} + +/** + * Checks whether the given string has upper. + */ +function hasUpper(str: string) { + return /[A-Z]/u.exec(str) +} + +/** + * Convert text to kebab-case + * @param str Text to be converted + */ +export function kebabCase(str: string) { + return str + .replace(/_/gu, "-") + .replace(/\B([A-Z])/gu, "-$1") + .toLowerCase() +} + +/** + * Checks whether the given string is kebab-case. + */ +export function isKebabCase(str: string) { + if ( + hasUpper(str) || + hasSymbols(str) || + /^-/u.exec(str) || // starts with hyphen is not kebab-case + /_|--|\s/u.exec(str) + ) { + return false + } + return true +} + +/** + * Convert text to snake_case + * @param str Text to be converted + */ +export function snakeCase(str: string) { + return str + .replace(/\B([A-Z])/gu, "_$1") + .replace(/-/gu, "_") + .toLowerCase() +} + +/** + * Checks whether the given string is snake_case. + */ +export function isSnakeCase(str: string) { + if (hasUpper(str) || hasSymbols(str) || /-|__|\s/u.exec(str)) { + return false + } + return true +} + +/** + * Convert text to camelCase + * @param str Text to be converted + * @return Converted string + */ +export function camelCase(str: string) { + if (isPascalCase(str)) { + return str.charAt(0).toLowerCase() + str.slice(1) + } + return str.replace(/[-_](\w)/gu, (_, c) => (c ? c.toUpperCase() : "")) +} + +/** + * Checks whether the given string is camelCase. + */ +export function isCamelCase(str: string) { + if ( + hasSymbols(str) || + /^[A-Z]/u.exec(str) || + /-|_|\s/u.exec(str) // kebab or snake or space + ) { + return false + } + return true +} + +/** + * Convert text to PascalCase + * @param str Text to be converted + * @return Converted string + */ +export function pascalCase(str: string) { + return capitalize(camelCase(str)) +} + +/** + * Checks whether the given string is PascalCase. + */ +export function isPascalCase(str: string) { + if ( + hasSymbols(str) || + /^[a-z]/u.exec(str) || + /-|_|\s/u.exec(str) // kebab or snake or space + ) { + return false + } + return true +} + +const convertersMap = { + "kebab-case": kebabCase, + // eslint-disable-next-line @mysticatea/ts/camelcase + snake_case: snakeCase, + camelCase, + PascalCase: pascalCase, +} + +const checkersMap = { + "kebab-case": isKebabCase, + // eslint-disable-next-line @mysticatea/ts/camelcase + snake_case: isSnakeCase, + camelCase: isCamelCase, + PascalCase: isPascalCase, +} + +/** + * Return case checker + */ +function getChecker(name: keyof typeof checkersMap) { + return checkersMap[name] || isPascalCase +} + +/** + * Return case converter + */ +function getConverter(name: keyof typeof convertersMap) { + return convertersMap[name] || pascalCase +} + +export const allowedCaseOptions = ["camelCase", "kebab-case", "PascalCase"] + +/** + * Return case exact converter. + * If the converted result is not the correct case, the original value is returned. + */ +export function getExactConverter(name: keyof typeof convertersMap) { + const converter = getConverter(name) + const checker = getChecker(name) + return (str: string) => { + const result = converter(str) + return checker(result) ? result : str /* cannot convert */ + } +} diff --git a/src/eslint-plugins/utils/deprecated-html-elements.json b/src/eslint-plugins/utils/deprecated-html-elements.json new file mode 100644 index 00000000..daf23f51 --- /dev/null +++ b/src/eslint-plugins/utils/deprecated-html-elements.json @@ -0,0 +1 @@ +["acronym","applet","basefont","bgsound","big","blink","center","command","content","dir","element","font","frame","frameset","image","isindex","keygen","listing","marquee","menuitem","multicol","nextid","nobr","noembed","noframes","plaintext","shadow","spacer","strike","tt","xmp"] \ No newline at end of file diff --git a/src/eslint-plugins/utils/html-comments.ts b/src/eslint-plugins/utils/html-comments.ts new file mode 100644 index 00000000..7d6cf25d --- /dev/null +++ b/src/eslint-plugins/utils/html-comments.ts @@ -0,0 +1,276 @@ +// ----------------------------------------------------------------------------- +// Requirements +// ----------------------------------------------------------------------------- +import * as utils from "./" + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +type CommentParserConfig = { + exceptions?: string[] +} + +type HTMLCommentVisitor = (comment: ParsedHTMLComment) => void + +type CommentVisitorOption = { + includeDirectives?: boolean +} + +type HTMLCommentOpen = Token & { type: "HTMLCommentOpen" } +type HTMLCommentOpenDecoration = Token & { type: "HTMLCommentOpenDecoration" } +type HTMLCommentValue = Token & { type: "HTMLCommentValue" } +type HTMLCommentClose = Token & { type: "HTMLCommentClose" } +type HTMLCommentCloseDecoration = Token & { type: "HTMLCommentCloseDecoration" } +type ParsedHTMLComment = { + open: HTMLCommentOpen + openDecoration: HTMLCommentOpenDecoration | null + value: HTMLCommentValue | null + closeDecoration: HTMLCommentCloseDecoration | null + close: HTMLCommentClose +} + +// eslint-disable-next-line require-unicode-regexp +const COMMENT_DIRECTIVE = /^\s*eslint-(?:en|dis)able/ +// eslint-disable-next-line require-unicode-regexp +const IE_CONDITIONAL_IF = /^\[if\s+/ +// eslint-disable-next-line require-unicode-regexp +const IE_CONDITIONAL_ENDIF = /\[endif\]$/ + +const TYPE_HTML_COMMENT_OPEN: "HTMLCommentOpen" = "HTMLCommentOpen" +const TYPE_HTML_COMMENT_OPEN_DECORATION: "HTMLCommentOpenDecoration" = + "HTMLCommentOpenDecoration" +const TYPE_HTML_COMMENT_VALUE: "HTMLCommentValue" = "HTMLCommentValue" +const TYPE_HTML_COMMENT_CLOSE: "HTMLCommentClose" = "HTMLCommentClose" +const TYPE_HTML_COMMENT_CLOSE_DECORATION: "HTMLCommentCloseDecoration" = + "HTMLCommentCloseDecoration" + +function isCommentDirective(comment: HTMLComment) { + return COMMENT_DIRECTIVE.test(comment.value) +} + +function isIEConditionalComment(comment: HTMLComment) { + return ( + IE_CONDITIONAL_IF.test(comment.value) || + // eslint-disable-next-line @mysticatea/ts/prefer-string-starts-ends-with + IE_CONDITIONAL_ENDIF.test(comment.value) + ) +} + +/** + * Define HTML comment parser + * + * @param sourceCode The source code instance. + * @param config The config. + * @returns HTML comment parser. + */ +function defineParser( + sourceCode: SourceCode, + config: CommentParserConfig | null, +): (node: Token) => ParsedHTMLComment | null { + // eslint-disable-next-line no-param-reassign + config = config || {} + + const exceptions = config.exceptions || [] + + /** + * Get a open decoration string from comment contents. + * @param contents comment contents + * @returns decoration string + */ + function getOpenDecoration(contents: string) { + let decoration = "" + for (const exception of exceptions) { + const length = exception.length + let index = 0 + while (contents.startsWith(exception, index)) { + index += length + } + const exceptionLength = index + if (decoration.length < exceptionLength) { + decoration = contents.slice(0, exceptionLength) + } + } + return decoration + } + + /** + * Get a close decoration string from comment contents. + * @param contents comment contents + * @returns decoration string + */ + function getCloseDecoration(contents: string) { + let decoration = "" + for (const exception of exceptions) { + const length = exception.length + let index = contents.length + while (contents.endsWith(exception, index)) { + index -= length + } + const exceptionLength = contents.length - index + if (decoration.length < exceptionLength) { + decoration = contents.slice(index) + } + } + return decoration + } + + /** + * Parse HTMLComment. + * @param {ASTToken} node a comment token + * @returns {HTMLComment | null} the result of HTMLComment tokens. + */ + return function parseHTMLComment(node: Token): ParsedHTMLComment | null { + if (node.type !== "HTMLComment") { + // Is not HTMLComment + return null + } + + const htmlCommentText = sourceCode.getText(node) + + if ( + !htmlCommentText.startsWith("<!--") || + !htmlCommentText.endsWith("-->") + ) { + // Is not normal HTML Comment + // e.g. Error Code: "abrupt-closing-of-empty-comment", "incorrectly-closed-comment" + return null + } + + let valueText = htmlCommentText.slice(4, -3) + const openDecorationText = getOpenDecoration(valueText) + valueText = valueText.slice(openDecorationText.length) + // eslint-disable-next-line require-unicode-regexp + const firstCharIndex = valueText.search(/\S/) + const beforeSpace = + firstCharIndex >= 0 ? valueText.slice(0, firstCharIndex) : valueText + valueText = valueText.slice(beforeSpace.length) + + const closeDecorationText = getCloseDecoration(valueText) + if (closeDecorationText) { + valueText = valueText.slice(0, -closeDecorationText.length) + } + // eslint-disable-next-line require-unicode-regexp + const lastCharIndex = valueText.search(/\S\s*$/) + const afterSpace = + lastCharIndex >= 0 ? valueText.slice(lastCharIndex + 1) : valueText + if (afterSpace) { + valueText = valueText.slice(0, -afterSpace.length) + } + + let tokenIndex = node.range[0] + /** + * @param type + * @param value + * @returns {any} + */ + const createToken = (type: string, value: string): any => { + const range: Range = [tokenIndex, tokenIndex + value.length] + tokenIndex = range[1] + + let loc: SourceLocation + return { + type, + value, + range, + get loc() { + if (loc) { + return loc + } + return (loc = { + start: sourceCode.getLocFromIndex(range[0]), + end: sourceCode.getLocFromIndex(range[1]), + }) + }, + } + } + + const open: HTMLCommentOpen = createToken( + TYPE_HTML_COMMENT_OPEN, + "<!--", + ) + const openDecoration: HTMLCommentOpenDecoration | null = openDecorationText + ? createToken(TYPE_HTML_COMMENT_OPEN_DECORATION, openDecorationText) + : null + tokenIndex += beforeSpace.length + const value: HTMLCommentValue | null = valueText + ? createToken(TYPE_HTML_COMMENT_VALUE, valueText) + : null + tokenIndex += afterSpace.length + const closeDecoration: HTMLCommentCloseDecoration | null = closeDecorationText + ? createToken( + TYPE_HTML_COMMENT_CLOSE_DECORATION, + closeDecorationText, + ) + : null + const close: HTMLCommentClose = createToken( + TYPE_HTML_COMMENT_CLOSE, + "-->", + ) + + return { + /** HTML comment open (`<!--`) */ + open, + /** decoration of the start of HTML comments. (`*****` when `<!--*****`) */ + openDecoration, + /** value of HTML comment. whitespaces and other tokens are not included. */ + value, + /** decoration of the end of HTML comments. (`*****` when `*****-->`) */ + closeDecoration, + /** HTML comment close (`-->`) */ + close, + } + } +} + +/** + * Define HTML comment visitor + * + * @param context The rule context. + * @param config The config. + * @param visitHTMLComment The HTML comment visitor. + * @param [visitorOption] The option for visitor. + * @returns HTML comment visitor. + */ +export function defineVisitor( + context: RuleContext, + config: CommentParserConfig | null, + visitHTMLComment: HTMLCommentVisitor, + visitorOption: CommentVisitorOption, +): RuleListener { + return { + Program(node) { + // eslint-disable-next-line no-param-reassign + visitorOption = visitorOption || {} + if (utils.hasInvalidEOF(node)) { + return + } + if (!node.templateBody) { + return + } + const parse = defineParser(context.getSourceCode(), config) + + for (const comment of node.templateBody.comments) { + if (comment.type !== "HTMLComment") { + continue + } + if ( + !visitorOption.includeDirectives && + isCommentDirective(comment) + ) { + // ignore directives + continue + } + if (isIEConditionalComment(comment)) { + // ignore IE conditional + continue + } + + const tokens = parse(comment) + if (tokens) { + visitHTMLComment(tokens) + } + } + }, + } +} diff --git a/src/eslint-plugins/utils/html-elements.json b/src/eslint-plugins/utils/html-elements.json new file mode 100644 index 00000000..721f7876 --- /dev/null +++ b/src/eslint-plugins/utils/html-elements.json @@ -0,0 +1 @@ +["html","body","base","head","link","meta","style","title","address","article","aside","footer","header","h1","h2","h3","h4","h5","h6","hgroup","nav","section","div","dd","dl","dt","figcaption","figure","hr","img","li","main","ol","p","pre","ul","a","b","abbr","bdi","bdo","br","cite","code","data","dfn","em","i","kbd","mark","q","rp","rt","rtc","ruby","s","samp","small","span","strong","sub","sup","time","u","var","wbr","area","audio","map","track","video","embed","object","param","source","canvas","script","noscript","del","ins","caption","col","colgroup","table","thead","tbody","tfoot","td","th","tr","button","datalist","fieldset","form","input","label","legend","meter","optgroup","option","output","progress","select","textarea","details","dialog","menu","menuitem","summary","content","element","shadow","template","slot","blockquote","iframe","noframes","picture"] diff --git a/src/eslint-plugins/utils/indent-common.ts b/src/eslint-plugins/utils/indent-common.ts new file mode 100644 index 00000000..e9a0b158 --- /dev/null +++ b/src/eslint-plugins/utils/indent-common.ts @@ -0,0 +1,2188 @@ +/** + * @author Toru Nagashima <https://github.com/mysticatea> + * See LICENSE file in root directory for full license. + */ + +// ------------------------------------------------------------------------------ +// Requirements +// ------------------------------------------------------------------------------ + +// ------------------------------------------------------------------------------ +// Helpers +// ------------------------------------------------------------------------------ + +const KNOWN_NODES = new Set<ASTNode["type"]>([ + "ArrayExpression", + "ArrayPattern", + "ArrowFunctionExpression", + "AssignmentExpression", + "AssignmentPattern", + "AwaitExpression", + "BinaryExpression", + "BlockStatement", + "BreakStatement", + "CallExpression", + "CatchClause", + "ChainExpression", + "ClassBody", + "ClassDeclaration", + "ClassExpression", + "ConditionalExpression", + "ContinueStatement", + "DebuggerStatement", + "DoWhileStatement", + "EmptyStatement", + "ExportAllDeclaration", + "ExportDefaultDeclaration", + "ExportNamedDeclaration", + "ExportSpecifier", + "ExpressionStatement", + "ForInStatement", + "ForOfStatement", + "ForStatement", + "FunctionDeclaration", + "FunctionExpression", + "Identifier", + "IfStatement", + "ImportDeclaration", + "ImportDefaultSpecifier", + "ImportExpression", + "ImportNamespaceSpecifier", + "ImportSpecifier", + "LabeledStatement", + "Literal", + "LogicalExpression", + "MemberExpression", + "MetaProperty", + "MethodDefinition", + "NewExpression", + "ObjectExpression", + "ObjectPattern", + "Program", + "Property", + "RestElement", + "ReturnStatement", + "SequenceExpression", + "SpreadElement", + "Super", + "SwitchCase", + "SwitchStatement", + "TaggedTemplateExpression", + "TemplateElement", + "TemplateLiteral", + "ThisExpression", + "ThrowStatement", + "TryStatement", + "UnaryExpression", + "UpdateExpression", + "VariableDeclaration", + "VariableDeclarator", + "WhileStatement", + "WithStatement", + "YieldExpression", + "VAttribute", + "VDirectiveKey", + "VDocumentFragment", + "VElement", + "VEndTag", + "VExpressionContainer", + "VFilter", + "VFilterSequenceExpression", + "VForExpression", + "VIdentifier", + "VLiteral", + "VOnExpression", + "VSlotScopeExpression", + "VStartTag", + "VText", +]) +const NON_STANDARD_KNOWN_NODES = new Set([ + "ExperimentalRestProperty", + "ExperimentalSpreadProperty", +]) +// eslint-disable-next-line require-unicode-regexp +const LT_CHAR = /[\r\n\u2028\u2029]/ +// eslint-disable-next-line require-unicode-regexp +const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g +// eslint-disable-next-line require-unicode-regexp +const BLOCK_COMMENT_PREFIX = /^\s*\*/ +const ITERATION_OPTS = Object.freeze({ + includeComments: true, + filter: isNotWhitespace, +}) +const PREFORMATTED_ELEMENT_NAMES = ["pre", "textarea"] + +type IndentOptions = { + indentChar: " " | "\t" + indentSize: number + baseIndent: number + attribute: number + closeBracket: { + startTag: number + endTag: number + selfClosingTag: number + } + switchCase: number + alignAttributesVertically: boolean + ignores: string[] +} + +type IndentUserOptions = { + indentChar: " " | "\t" + indentSize: number + baseIndent: number + attribute: number + closeBracket: IndentOptions["closeBracket"] | number + switchCase: number + alignAttributesVertically: boolean + ignores: string[] +} + +function parseOptions( + type: number | "tab" | undefined, + options: IndentUserOptions, + defaultOptions: Partial<IndentOptions>, +) { + const ret: IndentOptions = Object.assign( + { + indentChar: " ", + indentSize: 2, + baseIndent: 0, + attribute: 1, + closeBracket: { + startTag: 0, + endTag: 0, + selfClosingTag: 0, + }, + switchCase: 0, + alignAttributesVertically: true, + ignores: [], + }, + defaultOptions, + ) + + if (Number.isSafeInteger(type)) { + ret.indentSize = Number(type) + } else if (type === "tab") { + ret.indentChar = "\t" + ret.indentSize = 1 + } + + if (Number.isSafeInteger(options.baseIndent)) { + ret.baseIndent = options.baseIndent + } + if (Number.isSafeInteger(options.attribute)) { + ret.attribute = options.attribute + } + if (Number.isSafeInteger(options.closeBracket)) { + const num = Number(options.closeBracket) + ret.closeBracket = { + startTag: num, + endTag: num, + selfClosingTag: num, + } + } else if (options.closeBracket) { + ret.closeBracket = Object.assign( + { + startTag: 0, + endTag: 0, + selfClosingTag: 0, + }, + options.closeBracket, + ) + } + if (Number.isSafeInteger(options.switchCase)) { + ret.switchCase = options.switchCase + } + + if (options.alignAttributesVertically != null) { + ret.alignAttributesVertically = options.alignAttributesVertically + } + if (options.ignores != null) { + ret.ignores = options.ignores + } + + return ret +} + +/** + * Check whether the given token is an arrow. + */ +function isArrow(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "=>" +} + +/** + * Check whether the given token is a left parenthesis. + */ +function isLeftParen(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "(" +} + +/** + * Check whether the given token is a left parenthesis. + */ +function isNotLeftParen(token: Token | undefined | null) { + return token != null && (token.type !== "Punctuator" || token.value !== "(") +} + +/** + * Check whether the given token is a right parenthesis. + */ +function isRightParen(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === ")" +} + +/** + * Check whether the given token is a right parenthesis. + */ +function isNotRightParen(token: Token | undefined | null) { + return token != null && (token.type !== "Punctuator" || token.value !== ")") +} + +/** + * Check whether the given token is a left brace. + */ +function isLeftBrace(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "{" +} + +/** + * Check whether the given token is a right brace. + */ +function isRightBrace(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "}" +} + +/** + * Check whether the given token is a left bracket. + */ +function isLeftBracket(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "[" +} + +/** + * Check whether the given token is a right bracket. + */ +function isRightBracket(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "]" +} + +/** + * Check whether the given token is a semicolon. + */ +function isSemicolon(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === ";" +} + +/** + * Check whether the given token is a comma. + */ +function isComma(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "," +} + +/** + * Check whether the given token is a wildcard. + */ +function isWildcard(token: Token) { + return token != null && token.type === "Punctuator" && token.value === "*" +} + +/** + * Check whether the given token is a whitespace. + */ +function isNotWhitespace(token: Token | undefined | null) { + return token != null && token.type !== "HTMLWhitespace" +} + +/** + * Check whether the given token is a comment. + */ +function isComment(token: Token | undefined | null) { + return ( + token != null && + (token.type === "Block" || + token.type === "Line" || + token.type === "Shebang" || + (typeof token.type === + "string" /* Although acorn supports new tokens, espree may not yet support new tokens. */ && + token.type.endsWith("Comment"))) + ) +} + +/** + * Check whether the given token is a comment. + */ +function isNotComment(token: Token | undefined | null) { + return ( + token != null && + token.type !== "Block" && + token.type !== "Line" && + token.type !== "Shebang" && + !( + typeof token.type === + "string" /* Although acorn supports new tokens, espree may not yet support new tokens. */ && + token.type.endsWith("Comment") + ) + ) +} + +/** + * Check whether the given node is not an empty text node. + */ +function isNotEmptyTextNode(node: ASTNode) { + return !(node.type === "VText" && node.value.trim() === "") +} + +/** + * Check whether the given token is a pipe operator. + */ +function isPipeOperator(token: Token | undefined | null) { + return token != null && token.type === "Punctuator" && token.value === "|" +} + +/** + * Get the last element. + */ +function last<T>(xs: T[]) { + return xs.length === 0 ? undefined : xs[xs.length - 1] +} + +/** + * Check whether the node is at the beginning of line. + */ +function isBeginningOfLine( + node: ASTNode | null, + index: number, + nodes: (ASTNode | null)[], +) { + if (node != null) { + for (let i = index - 1; i >= 0; --i) { + const prevNode = nodes[i] + if (prevNode == null) { + continue + } + + return node.loc.start.line !== prevNode.loc.end.line + } + } + return false +} + +/** + * Check whether a given token is a closing token which triggers unindent. + */ +function isClosingToken(token: Token) { + return ( + token != null && + (token.type === "HTMLEndTagOpen" || + token.type === "VExpressionEnd" || + (token.type === "Punctuator" && + (token.value === ")" || + token.value === "}" || + token.value === "]"))) + ) +} + +/** + * Creates AST event handlers for html-indent. + * + * @param context The rule context. + * @param tokenStore The token store object to get tokens. + * @param defaultOptions The default value of options. + * @returns {NodeListener} AST event handlers. + */ +module.exports.defineVisitor = function create( + context: RuleContext, + tokenStore: ParserServices.TokenStore | SourceCode, + defaultOptions: Partial<IndentOptions>, +): NodeListener { + if (!context.getFilename().endsWith(".vue")) { + return {} + } + + const options = parseOptions( + context.options[0], + context.options[1] || {}, + defaultOptions, + ) + const sourceCode = context.getSourceCode() + const offsets = new Map() + const ignoreTokens = new Set() + + /** + * Set offset to the given tokens. + */ + function setOffset( + token: Token | Token[] | null | (Token | null)[], + offset: number, + baseToken: Token, + ) { + if (!token) { + return + } + if (Array.isArray(token)) { + for (const t of token) { + offsets.set(t, { + baseToken, + offset, + baseline: false, + expectedIndent: undefined, + }) + } + } else { + offsets.set(token, { + baseToken, + offset, + baseline: false, + expectedIndent: undefined, + }) + } + } + + /** + * Set baseline flag to the given token. + */ + function setBaseline(token: Token) { + const offsetInfo = offsets.get(token) + if (offsetInfo != null) { + offsetInfo.baseline = true + } + } + + /** + * Sets preformatted tokens to the given element node. + */ + function setPreformattedTokens(node: VElement) { + const endToken = + (node.endTag && tokenStore.getFirstToken(node.endTag)) || + tokenStore.getTokenAfter(node) + + const option: SourceCode.CursorWithSkipOptions = { + includeComments: true, + filter: (token) => + token != null && + (token.type === "HTMLText" || + token.type === "HTMLRCDataText" || + token.type === "HTMLTagOpen" || + token.type === "HTMLEndTagOpen" || + token.type === "HTMLComment"), + } + for (const token of tokenStore.getTokensBetween( + node.startTag, + endToken, + option, + )) { + ignoreTokens.add(token) + } + ignoreTokens.add(endToken) + } + + /** + * Get the first and last tokens of the given node. + * If the node is parenthesized, this gets the outermost parentheses. + * @param node The node to get. + * @param [borderOffset] The least offset of the first token. Defailt is 0. This value is used to prevent false positive in the following case: `(a) => {}` The parentheses are enclosing the whole parameter part rather than the first parameter, but this offset parameter is needed to distinguish. + * @returns The gotten tokens. + */ + function getFirstAndLastTokens(node: ASTNode, borderOffset = 0) { + // eslint-disable-next-line no-param-reassign + borderOffset |= 0 + + let firstToken = tokenStore.getFirstToken(node) + let lastToken = tokenStore.getLastToken(node) + + // Get the outermost left parenthesis if it's parenthesized. + let t, u + while ( + (t = tokenStore.getTokenBefore(firstToken)) != null && + (u = tokenStore.getTokenAfter(lastToken)) != null && + isLeftParen(t) && + isRightParen(u) && + t.range[0] >= borderOffset + ) { + firstToken = t + lastToken = u + } + + return { firstToken, lastToken } + } + + /** + * Process the given node list. + * The first node is offsetted from the given left token. + * Rest nodes are adjusted to the first node. + * @param nodeList The node to process. + * @param left The left parenthesis token. + * @param right The right parenthesis token. + * @param offset The offset to set. + * @param [alignVertically=true] The flag to align vertically. If `false`, this doesn't align vertically even if the first node is not at beginning of line. + * @returns {void} + */ + // eslint-disable-next-line complexity + function processNodeList( + nodeList: (ASTNode | null)[], + left: ASTNode | Token | null, + right: ASTNode | Token | null, + offset: number, + alignVertically = true, + ) { + let t + const leftToken = left && tokenStore.getFirstToken(left) + const rightToken = right && tokenStore.getFirstToken(right) + + if (nodeList.length >= 1) { + let baseToken = null + let lastToken = left + const alignTokensBeforeBaseToken = [] + const alignTokens = [] + + for (const node of nodeList) { + if (node == null) { + // Holes of an array. + continue + } + const elementTokens = getFirstAndLastTokens( + node, + lastToken != null ? lastToken.range[1] : 0, + ) + + // Collect comma/comment tokens between the last token of the previous node and the first token of this node. + if (lastToken != null) { + t = lastToken + while ( + (t = tokenStore.getTokenAfter(t, ITERATION_OPTS)) != + null && + t.range[1] <= elementTokens.firstToken.range[0] + ) { + if (baseToken == null) { + alignTokensBeforeBaseToken.push(t) + } else { + alignTokens.push(t) + } + } + } + + if (baseToken == null) { + baseToken = elementTokens.firstToken + } else { + alignTokens.push(elementTokens.firstToken) + } + + // Save the last token to find tokens between this node and the next node. + lastToken = elementTokens.lastToken + } + + // Check trailing commas and comments. + if (rightToken != null && lastToken != null) { + t = lastToken + while ( + (t = tokenStore.getTokenAfter(t, ITERATION_OPTS)) != null && + t.range[1] <= rightToken.range[0] + ) { + if (baseToken == null) { + alignTokensBeforeBaseToken.push(t) + } else { + alignTokens.push(t) + } + } + } + + // Set offsets. + if (leftToken != null) { + setOffset(alignTokensBeforeBaseToken, offset, leftToken) + } + if (baseToken != null) { + // Set offset to the first token. + if (leftToken != null) { + setOffset(baseToken, offset, leftToken) + } + + // Set baseline. + if (nodeList.some(isBeginningOfLine)) { + setBaseline(baseToken) + } + + if (alignVertically === false && leftToken != null) { + // Align tokens relatively to the left token. + setOffset(alignTokens, offset, leftToken) + } else { + // Align the rest tokens to the first token. + setOffset(alignTokens, 0, baseToken) + } + } + } + + if (rightToken != null && leftToken != null) { + setOffset(rightToken, 0, leftToken) + } + } + + /** + * Process the given node as body. + * The body node maybe a block statement or an expression node. + * @param node The body node to process. + * @param baseToken The base token. + * @returns {void} + */ + function processMaybeBlock(node: ASTNode, baseToken: Token) { + const firstToken = getFirstAndLastTokens(node).firstToken + setOffset(firstToken, isLeftBrace(firstToken) ? 0 : 1, baseToken) + } + + /** + * Collect prefix tokens of the given property. + * The prefix includes `async`, `get`, `set`, `static`, and `*`. + * @param node The property node to collect prefix tokens. + */ + function getPrefixTokens(node: Property | MethodDefinition) { + const prefixes = [] + + /** @type {Token|null} */ + let token = tokenStore.getFirstToken(node) + while (token != null && token.range[1] <= node.key.range[0]) { + prefixes.push(token) + token = tokenStore.getTokenAfter(token) + } + while (isLeftParen(last(prefixes)) || isLeftBracket(last(prefixes))) { + prefixes.pop() + } + + return prefixes + } + + /** + * Find the head of chaining nodes. + * @param node The start node to find the head. + * @returns {Token} The head token of the chain. + */ + function getChainHeadToken(node: ASTNode) { + const type = node.type + while (node.parent && node.parent.type === type) { + const prevToken = tokenStore.getTokenBefore(node) + if (isLeftParen(prevToken)) { + // The chaining is broken by parentheses. + break + } + // eslint-disable-next-line no-param-reassign + node = node.parent + } + return tokenStore.getFirstToken(node) + } + + /** + * Check whether a given token is the first token of: + * + * - ExpressionStatement + * - VExpressionContainer + * - A parameter of CallExpression/NewExpression + * - An element of ArrayExpression + * - An expression of SequenceExpression + * + * @param token The token to check. + * @param belongingNode The node that the token is belonging to. + * @returns {boolean} `true` if the token is the first token of an element. + */ + function isBeginningOfElement(token: Token, belongingNode: ASTNode) { + let node = belongingNode + + while (node != null && node.parent != null) { + const parent = node.parent + if ( + parent.type.endsWith("Statement") || + parent.type.endsWith("Declaration") + ) { + return parent.range[0] === token.range[0] + } + if (parent.type === "VExpressionContainer") { + if (node.range[0] !== token.range[0]) { + return false + } + const prevToken = tokenStore.getTokenBefore(belongingNode) + if (isLeftParen(prevToken)) { + // It is not the first token because it is enclosed in parentheses. + return false + } + return true + } + if ( + parent.type === "CallExpression" || + parent.type === "NewExpression" + ) { + const openParen = tokenStore.getTokenAfter( + parent.callee, + isNotRightParen, + ) as Token + return parent.arguments.some( + (param) => + getFirstAndLastTokens(param, openParen.range[1]) + .firstToken.range[0] === token.range[0], + ) + } + if (parent.type === "ArrayExpression") { + return parent.elements.some( + (element) => + element != null && + getFirstAndLastTokens(element).firstToken.range[0] === + token.range[0], + ) + } + if (parent.type === "SequenceExpression") { + return parent.expressions.some( + (expr) => + getFirstAndLastTokens(expr).firstToken.range[0] === + token.range[0], + ) + } + + node = parent + } + + return false + } + + /** + * Set the base indentation to a given top-level AST node. + * @param node The node to set. + * @param expectedIndent The number of expected indent. + * @returns {void} + */ + function processTopLevelNode(node: ASTNode, expectedIndent: number) { + const token = tokenStore.getFirstToken(node) + const offsetInfo = offsets.get(token) + if (offsetInfo != null) { + offsetInfo.expectedIndent = expectedIndent + } else { + offsets.set(token, { + baseToken: null, + offset: 0, + baseline: false, + expectedIndent, + }) + } + } + + /** + * Ignore all tokens of the given node. + * @param node The node to ignore. + * @returns {void} + */ + function ignore(node: ASTNode) { + for (const token of tokenStore.getTokens(node)) { + offsets.delete(token) + ignoreTokens.add(token) + } + } + + /** + * Define functions to ignore nodes into the given visitor. + * @param visitor The visitor to define functions to ignore nodes. + * @returns The visitor. + */ + function processIgnores(visitor: NodeListener) { + for (const ignorePattern of options.ignores) { + const key = `${ignorePattern}:exit` + // eslint-disable-next-line no-prototype-builtins + if (visitor.hasOwnProperty(key)) { + const handler = visitor[key] + visitor[key] = function (node, ...args) { + // @ts-expect-error + const ret = handler.call(this, node, ...args) + ignore(node) + return ret + } + } else { + visitor[key] = ignore + } + } + + return visitor + } + + /** + * Calculate correct indentation of the line of the given tokens. + * @param tokens Tokens which are on the same line. + * @returns Correct indentation. If it failed to calculate then `null`. + */ + function getExpectedIndents( + tokens: Token[], + ): { expectedIndent: number; expectedBaseIndent: number } | null { + const expectedIndents = [] + + for (let i = 0; i < tokens.length; ++i) { + const token = tokens[i] + const offsetInfo = offsets.get(token) + + if (offsetInfo != null) { + if (offsetInfo.expectedIndent != null) { + expectedIndents.push(offsetInfo.expectedIndent) + } else { + const baseOffsetInfo = offsets.get(offsetInfo.baseToken) + if ( + baseOffsetInfo != null && + baseOffsetInfo.expectedIndent != null && + (i === 0 || !baseOffsetInfo.baseline) + ) { + expectedIndents.push( + // eslint-disable-next-line @mysticatea/ts/restrict-plus-operands + baseOffsetInfo.expectedIndent + + offsetInfo.offset * options.indentSize, + ) + if (baseOffsetInfo.baseline) { + break + } + } + } + } + } + if (!expectedIndents.length) { + return null + } + + return { + expectedIndent: expectedIndents[0], + expectedBaseIndent: expectedIndents.reduce((a, b) => + Math.min(a, b), + ), + } + } + + /** + * Get the text of the indentation part of the line which the given token is on. + * @param firstToken The first token on a line. + * @returns The text of indentation part. + */ + function getIndentText(firstToken: Token) { + const text = sourceCode.text + let i = firstToken.range[0] - 1 + + while (i >= 0 && !LT_CHAR.test(text[i])) { + i -= 1 + } + + return text.slice(i + 1, firstToken.range[0]) + } + + /** + * Define the function which fixes the problem. + * @param token The token to fix. + * @param actualIndent The number of actual indentation. + * @param expectedIndent The number of expected indentation. + * @returns The defined function. + */ + function defineFix( + token: Token, + actualIndent: number, + expectedIndent: number, + ): (fixer: RuleFixer) => Fix { + if ( + token.type === "Block" && + token.loc.start.line !== token.loc.end.line + ) { + // Fix indentation in multiline block comments. + const lines = sourceCode.getText(token).match(LINES) || [] + const firstLine = lines.shift() + if (lines.every((l) => BLOCK_COMMENT_PREFIX.test(l))) { + return (fixer) => { + const range: Range = [ + token.range[0] - actualIndent, + token.range[1], + ] + const indent = options.indentChar.repeat(expectedIndent) + + return fixer.replaceTextRange( + range, + `${indent}${firstLine}${lines + .map((l) => + l.replace(BLOCK_COMMENT_PREFIX, `${indent} *`), + ) + .join("")}`, + ) + } + } + } + + return (fixer) => { + const range: Range = [token.range[0] - actualIndent, token.range[0]] + const indent = options.indentChar.repeat(expectedIndent) + return fixer.replaceTextRange(range, indent) + } + } + + /** + * Validate the given token with the pre-calculated expected indentation. + * @param token The token to validate. + * @param expectedIndent The expected indentation. + * @param [optionalExpectedIndents] The optional expected indentation. + */ + function validateCore( + token: Token, + expectedIndent: number, + optionalExpectedIndents?: number[], + ) { + const line = token.loc.start.line + const indentText = getIndentText(token) + + // If there is no line terminator after the `<script>` start tag, + // `indentText` contains non-whitespace characters. + // In that case, do nothing in order to prevent removing the `<script>` tag. + if (indentText.trim() !== "") { + return + } + + const actualIndent = token.loc.start.column + const unit = options.indentChar === "\t" ? "tab" : "space" + + for (let i = 0; i < indentText.length; ++i) { + if (indentText[i] !== options.indentChar) { + context.report({ + loc: { + start: { line, column: i }, + end: { line, column: i + 1 }, + }, + message: + "Expected {{expected}} character, but found {{actual}} character.", + data: { + expected: JSON.stringify(options.indentChar), + actual: JSON.stringify(indentText[i]), + }, + fix: defineFix(token, actualIndent, expectedIndent), + }) + return + } + } + + if ( + actualIndent !== expectedIndent && + (optionalExpectedIndents == null || + !optionalExpectedIndents.includes(actualIndent)) + ) { + context.report({ + loc: { + start: { line, column: 0 }, + end: { line, column: actualIndent }, + }, + message: + "Expected indentation of {{expectedIndent}} {{unit}}{{expectedIndentPlural}} but found {{actualIndent}} {{unit}}{{actualIndentPlural}}.", + data: { + expectedIndent, + actualIndent, + unit, + expectedIndentPlural: expectedIndent === 1 ? "" : "s", + actualIndentPlural: actualIndent === 1 ? "" : "s", + }, + fix: defineFix(token, actualIndent, expectedIndent), + }) + } + } + + /** + * Get the expected indent of comments. + * @param nextToken The next token of comments. + * @param nextExpectedIndent The expected indent of the next token. + * @param lastExpectedIndent The expected indent of the last token. + */ + function getCommentExpectedIndents( + nextToken: Token, + nextExpectedIndent: number, + lastExpectedIndent: number, + ) { + if ( + typeof lastExpectedIndent === "number" && + isClosingToken(nextToken) + ) { + if (nextExpectedIndent === lastExpectedIndent) { + // For solo comment. E.g., + // <div> + // <!-- comment --> + // </div> + return [ + nextExpectedIndent + options.indentSize, + nextExpectedIndent, + ] + } + + // For last comment. E.g., + // <div> + // <div></div> + // <!-- comment --> + // </div> + return [lastExpectedIndent, nextExpectedIndent] + } + + // Adjust to next normally. E.g., + // <div> + // <!-- comment --> + // <div></div> + // </div> + return [nextExpectedIndent] + } + + /** + * Validate indentation of the line that the given tokens are on. + * @param tokens The tokens on the same line to validate. + * @param comments The comments which are on the immediately previous lines of the tokens. + * @param lastToken The last validated token. Comments can adjust to the token. + */ + function validate( + tokens: Token[], + comments: Token[], + lastToken: Token | null, + ) { + // Calculate and save expected indentation. + const firstToken = tokens[0] + const actualIndent = firstToken.loc.start.column + const expectedIndents = getExpectedIndents(tokens) + if (!expectedIndents) { + return + } + + const expectedBaseIndent = expectedIndents.expectedBaseIndent + const expectedIndent = expectedIndents.expectedIndent + + // Debug log + // console.log('line', firstToken.loc.start.line, '=', { actualIndent, expectedIndent }, 'from:') + // for (const token of tokens) { + // const offsetInfo = offsets.get(token) + // if (offsetInfo == null) { + // console.log(' ', JSON.stringify(sourceCode.getText(token)), 'is unknown.') + // } else if (offsetInfo.expectedIndent != null) { + // console.log(' ', JSON.stringify(sourceCode.getText(token)), 'is fixed at', offsetInfo.expectedIndent, '.') + // } else { + // const baseOffsetInfo = offsets.get(offsetInfo.baseToken) + // console.log(' ', JSON.stringify(sourceCode.getText(token)), 'is', offsetInfo.offset, 'offset from ', JSON.stringify(sourceCode.getText(offsetInfo.baseToken)), '( line:', offsetInfo.baseToken && offsetInfo.baseToken.loc.start.line, ', indent:', baseOffsetInfo && baseOffsetInfo.expectedIndent, ', baseline:', baseOffsetInfo && baseOffsetInfo.baseline, ')') + // } + // } + + // Save. + const baseline = new Set() + for (const token of tokens) { + const offsetInfo = offsets.get(token) + if (offsetInfo != null) { + if (offsetInfo.baseline) { + // This is a baseline token, so the expected indent is the column of this token. + if (options.indentChar === " ") { + offsetInfo.expectedIndent = Math.max( + 0, + token.loc.start.column + + expectedBaseIndent - + actualIndent, + ) + } else { + // In hard-tabs mode, it cannot align tokens strictly, so use one additional offset. + // But the additional offset isn't needed if it's at the beginning of the line. + offsetInfo.expectedIndent = + expectedBaseIndent + (token === tokens[0] ? 0 : 1) + } + baseline.add(token) + } else if (baseline.has(offsetInfo.baseToken)) { + // The base token is a baseline token on this line, so inherit it. + offsetInfo.expectedIndent = offsets.get( + offsetInfo.baseToken, + ).expectedIndent + baseline.add(token) + } else { + // Otherwise, set the expected indent of this line. + offsetInfo.expectedIndent = expectedBaseIndent + } + } + } + + // It does not validate ignore tokens. + if (ignoreTokens.has(firstToken)) { + return + } + + // Calculate the expected indents for comments. + // It allows the same indent level with the previous line. + const lastOffsetInfo = offsets.get(lastToken) + const lastExpectedIndent = + lastOffsetInfo && lastOffsetInfo.expectedIndent + const commentOptionalExpectedIndents = getCommentExpectedIndents( + firstToken, + expectedIndent, + lastExpectedIndent, + ) + + // Validate. + for (const comment of comments) { + const commentExpectedIndents = getExpectedIndents([comment]) + const commentExpectedIndent = commentExpectedIndents + ? commentExpectedIndents.expectedIndent + : commentOptionalExpectedIndents[0] + + validateCore( + comment, + commentExpectedIndent, + commentOptionalExpectedIndents, + ) + } + validateCore(firstToken, expectedIndent) + } + + // ------------------------------------------------------------------------------ + // Main + // ------------------------------------------------------------------------------ + + return processIgnores({ + VAttribute(node: VAttribute) { + const keyToken = tokenStore.getFirstToken(node) + const eqToken = tokenStore.getTokenAfter(node.key) + + if (eqToken != null && eqToken.range[1] <= node.range[1]) { + setOffset(eqToken, 1, keyToken) + + const valueToken = tokenStore.getTokenAfter(eqToken) + if ( + valueToken != null && + valueToken.range[1] <= node.range[1] + ) { + setOffset(valueToken, 1, keyToken) + } + } + }, + + VElement(node: VElement) { + if (!PREFORMATTED_ELEMENT_NAMES.includes(node.name)) { + const isTopLevel = node.parent.type !== "VElement" + const offset = isTopLevel ? options.baseIndent : 1 + processNodeList( + node.children.filter(isNotEmptyTextNode), + node.startTag, + node.endTag, + offset, + false, + ) + } else { + const startTagToken = tokenStore.getFirstToken(node) + const endTagToken = + node.endTag && tokenStore.getFirstToken(node.endTag) + setOffset(endTagToken, 0, startTagToken) + setPreformattedTokens(node) + } + }, + + VEndTag(node: VEndTag) { + const element = node.parent + const startTagOpenToken = tokenStore.getFirstToken(element.startTag) + const closeToken = tokenStore.getLastToken(node) + + if (closeToken.type.endsWith("TagClose")) { + setOffset( + closeToken, + options.closeBracket.endTag, + startTagOpenToken, + ) + } + }, + + VExpressionContainer(node: VExpressionContainer) { + if ( + node.expression != null && + node.range[0] !== node.expression.range[0] + ) { + const startQuoteToken = tokenStore.getFirstToken(node) + const endQuoteToken = tokenStore.getLastToken(node) + const childToken = tokenStore.getTokenAfter(startQuoteToken) + + setOffset(childToken, 1, startQuoteToken) + setOffset(endQuoteToken, 0, startQuoteToken) + } + }, + + VFilter(node: VFilter) { + const idToken = tokenStore.getFirstToken(node) + const lastToken = tokenStore.getLastToken(node) + if (isRightParen(lastToken)) { + const leftParenToken = tokenStore.getTokenAfter(node.callee) + setOffset(leftParenToken, 1, idToken) + processNodeList(node.arguments, leftParenToken, lastToken, 1) + } + }, + + VFilterSequenceExpression(node: VFilterSequenceExpression) { + if (node.filters.length === 0) { + return + } + + const firstToken = tokenStore.getFirstToken(node) + /** @type {(Token|null)[]} */ + const tokens = [] + + for (const filter of node.filters) { + tokens.push( + tokenStore.getTokenBefore(filter, isPipeOperator), + tokenStore.getFirstToken(filter), + ) + } + + setOffset(tokens, 1, firstToken) + }, + + VForExpression(node: VForExpression) { + const firstToken = tokenStore.getFirstToken(node) + const lastOfLeft = last(node.left) || firstToken + const inToken = tokenStore.getTokenAfter( + lastOfLeft, + isNotRightParen, + ) as Token + const rightToken = tokenStore.getFirstToken(node.right) + + if (isLeftParen(firstToken)) { + // eslint-disable-next-line no-shadow + const rightToken = tokenStore.getTokenAfter( + lastOfLeft, + isRightParen, + ) + processNodeList(node.left, firstToken, rightToken, 1) + } + setOffset(inToken, 1, firstToken) + setOffset(rightToken, 1, inToken) + }, + + VOnExpression(node: VOnExpression) { + processNodeList(node.body, null, null, 0) + }, + + VStartTag(node: VStartTag) { + const openToken = tokenStore.getFirstToken(node) + const closeToken = tokenStore.getLastToken(node) + + processNodeList( + node.attributes, + openToken, + null, + options.attribute, + options.alignAttributesVertically, + ) + if (closeToken != null && closeToken.type.endsWith("TagClose")) { + const offset = + closeToken.type !== "HTMLSelfClosingTagClose" + ? options.closeBracket.startTag + : options.closeBracket.selfClosingTag + setOffset(closeToken, offset, openToken) + } + }, + + VText(node: VText) { + const tokens = tokenStore.getTokens(node, isNotWhitespace) + const firstTokenInfo = offsets.get(tokenStore.getFirstToken(node)) + + for (const token of tokens) { + offsets.set(token, Object.assign({}, firstTokenInfo)) + } + }, + + "ArrayExpression, ArrayPattern"(node: ArrayExpression | ArrayPattern) { + processNodeList( + node.elements, + tokenStore.getFirstToken(node), + tokenStore.getLastToken(node), + 1, + ) + }, + + ArrowFunctionExpression(node: ArrowFunctionExpression) { + const firstToken = tokenStore.getFirstToken(node) + const secondToken = tokenStore.getTokenAfter(firstToken) + const leftToken = node.async ? secondToken : firstToken + const arrowToken = tokenStore.getTokenBefore(node.body, isArrow) + + if (node.async) { + setOffset(secondToken, 1, firstToken) + } + if (isLeftParen(leftToken)) { + const rightToken = tokenStore.getTokenAfter( + last(node.params) || leftToken, + isRightParen, + ) + processNodeList(node.params, leftToken, rightToken, 1) + } + + setOffset(arrowToken, 1, firstToken) + processMaybeBlock(node.body, firstToken) + }, + + "AssignmentExpression, AssignmentPattern, BinaryExpression, LogicalExpression"( + node: + | AssignmentExpression + | AssignmentPattern + | BinaryExpression + | LogicalExpression, + ) { + const leftToken = getChainHeadToken(node) + const opToken = tokenStore.getTokenAfter( + node.left, + isNotRightParen, + ) as Token + const rightToken = tokenStore.getTokenAfter(opToken) + const prevToken = tokenStore.getTokenBefore(leftToken) + const shouldIndent = + prevToken == null || + prevToken.loc.end.line === leftToken.loc.start.line || + isBeginningOfElement(leftToken, node) + + setOffset([opToken, rightToken], shouldIndent ? 1 : 0, leftToken) + }, + + "AwaitExpression, RestElement, SpreadElement, UnaryExpression"( + node: + | AwaitExpression + | RestElement + | SpreadElement + | UnaryExpression, + ) { + const firstToken = tokenStore.getFirstToken(node) + const nextToken = tokenStore.getTokenAfter(firstToken) + + setOffset(nextToken, 1, firstToken) + }, + + "BlockStatement, ClassBody"(node: BlockStatement | ClassBody) { + processNodeList( + node.body, + tokenStore.getFirstToken(node), + tokenStore.getLastToken(node), + 1, + ) + }, + + "BreakStatement, ContinueStatement, ReturnStatement, ThrowStatement"( + node: + | BreakStatement + | ContinueStatement + | ReturnStatement + | ThrowStatement, + ) { + if ( + ((node.type === "ReturnStatement" || + node.type === "ThrowStatement") && + node.argument != null) || + ((node.type === "BreakStatement" || + node.type === "ContinueStatement") && + node.label != null) + ) { + const firstToken = tokenStore.getFirstToken(node) + const nextToken = tokenStore.getTokenAfter(firstToken) + + setOffset(nextToken, 1, firstToken) + } + }, + + CallExpression(node: CallExpression) { + const firstToken = tokenStore.getFirstToken(node) + const rightToken = tokenStore.getLastToken(node) + const leftToken = tokenStore.getTokenAfter(node.callee, isLeftParen) + + setOffset(leftToken, 1, firstToken) + processNodeList(node.arguments, leftToken, rightToken, 1) + }, + + ImportExpression(node: ImportExpression) { + const firstToken = tokenStore.getFirstToken(node) + const rightToken = tokenStore.getLastToken(node) + const leftToken = tokenStore.getTokenAfter(firstToken, isLeftParen) + + setOffset(leftToken, 1, firstToken) + processNodeList([node.source], leftToken, rightToken, 1) + }, + + CatchClause(node: CatchClause) { + const firstToken = tokenStore.getFirstToken(node) + const bodyToken = tokenStore.getFirstToken(node.body) + + if (node.param != null) { + const leftToken = tokenStore.getTokenAfter(firstToken) + const rightToken = tokenStore.getTokenAfter(node.param) + + setOffset(leftToken, 1, firstToken) + processNodeList([node.param], leftToken, rightToken, 1) + } + setOffset(bodyToken, 0, firstToken) + }, + + "ClassDeclaration, ClassExpression"( + node: ClassDeclaration | ClassExpression, + ) { + const firstToken = tokenStore.getFirstToken(node) + const bodyToken = tokenStore.getFirstToken(node.body) + + if (node.id != null) { + setOffset(tokenStore.getFirstToken(node.id), 1, firstToken) + } + if (node.superClass != null) { + const extendsToken = tokenStore.getTokenAfter( + node.id || firstToken, + ) + const superClassToken = tokenStore.getTokenAfter(extendsToken) + setOffset(extendsToken, 1, firstToken) + setOffset(superClassToken, 1, extendsToken) + } + setOffset(bodyToken, 0, firstToken) + }, + + ConditionalExpression(node: ConditionalExpression) { + const prevToken = tokenStore.getTokenBefore(node) + const firstToken = tokenStore.getFirstToken(node) + const questionToken = tokenStore.getTokenAfter( + node.test, + isNotRightParen, + ) as Token + const consequentToken = tokenStore.getTokenAfter(questionToken) + const colonToken = tokenStore.getTokenAfter( + node.consequent, + isNotRightParen, + ) as Token + const alternateToken = tokenStore.getTokenAfter(colonToken) + const isFlat = + prevToken && + prevToken.loc.end.line !== node.loc.start.line && + node.test.loc.end.line === node.consequent.loc.start.line + + if (isFlat) { + setOffset( + [ + questionToken, + consequentToken, + colonToken, + alternateToken, + ], + 0, + firstToken, + ) + } else { + setOffset([questionToken, colonToken], 1, firstToken) + setOffset([consequentToken, alternateToken], 1, questionToken) + } + }, + + DoWhileStatement(node: DoWhileStatement) { + const doToken = tokenStore.getFirstToken(node) + const whileToken = tokenStore.getTokenAfter( + node.body, + isNotRightParen, + ) as Token + const leftToken = tokenStore.getTokenAfter(whileToken) + const testToken = tokenStore.getTokenAfter(leftToken) + const lastToken = tokenStore.getLastToken(node) + const rightToken = isSemicolon(lastToken) + ? tokenStore.getTokenBefore(lastToken) + : lastToken + + processMaybeBlock(node.body, doToken) + setOffset(whileToken, 0, doToken) + setOffset(leftToken, 1, whileToken) + setOffset(testToken, 1, leftToken) + setOffset(rightToken, 0, leftToken) + }, + + ExportAllDeclaration(node: ExportAllDeclaration) { + const tokens = tokenStore.getTokens(node) + const firstToken = tokens.shift() as Token + if (isSemicolon(last(tokens))) { + tokens.pop() + } + if (!node.exported) { + setOffset(tokens, 1, firstToken) + } else { + // export * as foo from "mod" + const starToken = tokens.find(isWildcard) as Token + const asToken = tokenStore.getTokenAfter(starToken) + const exportedToken = tokenStore.getTokenAfter(asToken) + const afterTokens = tokens.slice( + tokens.indexOf(exportedToken) + 1, + ) + + setOffset(starToken, 1, firstToken) + setOffset(asToken, 1, starToken) + setOffset(exportedToken, 1, starToken) + setOffset(afterTokens, 1, firstToken) + } + }, + + ExportDefaultDeclaration(node: ExportDefaultDeclaration) { + const exportToken = tokenStore.getFirstToken(node) + const defaultToken = tokenStore.getFirstToken(node, 1) + const declarationToken = getFirstAndLastTokens(node.declaration) + .firstToken + setOffset([defaultToken, declarationToken], 1, exportToken) + }, + + ExportNamedDeclaration(node: ExportNamedDeclaration) { + const exportToken = tokenStore.getFirstToken(node) + if (node.declaration) { + // export var foo = 1; + const declarationToken = tokenStore.getFirstToken(node, 1) + setOffset(declarationToken, 1, exportToken) + } else { + const firstSpecifier = node.specifiers[0] + if ( + !firstSpecifier || + firstSpecifier.type === "ExportSpecifier" + ) { + // export {foo, bar}; or export {foo, bar} from "mod"; + const leftParenToken = tokenStore.getFirstToken(node, 1) + const rightParenToken = tokenStore.getLastToken( + node, + isRightBrace, + ) as Token + setOffset(leftParenToken, 0, exportToken) + processNodeList( + node.specifiers, + leftParenToken, + rightParenToken, + 1, + ) + + const maybeFromToken = tokenStore.getTokenAfter( + rightParenToken, + ) + if ( + maybeFromToken != null && + sourceCode.getText(maybeFromToken) === "from" + ) { + const fromToken = maybeFromToken + const nameToken = tokenStore.getTokenAfter(fromToken) + setOffset([fromToken, nameToken], 1, exportToken) + } + } else { + // maybe babel-eslint + } + } + }, + + ExportSpecifier(node: ExportSpecifier) { + const tokens = tokenStore.getTokens(node) + const firstToken = tokens.shift() as Token + setOffset(tokens, 1, firstToken) + }, + + "ForInStatement, ForOfStatement"( + node: ForInStatement | ForOfStatement, + ) { + const forToken = tokenStore.getFirstToken(node) + const awaitToken = + (node.type === "ForOfStatement" && + node.await && + tokenStore.getTokenAfter(forToken)) || + null + const leftParenToken = tokenStore.getTokenAfter( + awaitToken || forToken, + ) + const leftToken = tokenStore.getTokenAfter(leftParenToken) + const inToken = tokenStore.getTokenAfter( + leftToken, + isNotRightParen, + ) as Token + const rightToken = tokenStore.getTokenAfter(inToken) + const rightParenToken = tokenStore.getTokenBefore( + node.body, + isNotLeftParen, + ) + + if (awaitToken != null) { + setOffset(awaitToken, 0, forToken) + } + setOffset(leftParenToken, 1, forToken) + setOffset(leftToken, 1, leftParenToken) + setOffset(inToken, 1, leftToken) + setOffset(rightToken, 1, leftToken) + setOffset(rightParenToken, 0, leftParenToken) + processMaybeBlock(node.body, forToken) + }, + + ForStatement(node: ForStatement) { + const forToken = tokenStore.getFirstToken(node) + const leftParenToken = tokenStore.getTokenAfter(forToken) + const rightParenToken = tokenStore.getTokenBefore( + node.body, + isNotLeftParen, + ) + + setOffset(leftParenToken, 1, forToken) + processNodeList( + [node.init, node.test, node.update], + leftParenToken, + rightParenToken, + 1, + ) + processMaybeBlock(node.body, forToken) + }, + + "FunctionDeclaration, FunctionExpression"( + node: FunctionDeclaration | FunctionExpression, + ) { + const firstToken = tokenStore.getFirstToken(node) + if (isLeftParen(firstToken)) { + // Methods. + const leftToken = firstToken + const rightToken = tokenStore.getTokenAfter( + last(node.params) || leftToken, + isRightParen, + ) + const bodyToken = tokenStore.getFirstToken(node.body) + + processNodeList(node.params, leftToken, rightToken, 1) + setOffset(bodyToken, 0, tokenStore.getFirstToken(node.parent)) + } else { + // Normal functions. + const functionToken = node.async + ? tokenStore.getTokenAfter(firstToken) + : firstToken + const starToken = node.generator + ? tokenStore.getTokenAfter(functionToken) + : null + const idToken = node.id && tokenStore.getFirstToken(node.id) + const leftToken = tokenStore.getTokenAfter( + idToken || starToken || functionToken, + ) + const rightToken = tokenStore.getTokenAfter( + last(node.params) || leftToken, + isRightParen, + ) + const bodyToken = tokenStore.getFirstToken(node.body) + + if (node.async) { + setOffset(functionToken, 0, firstToken) + } + if (node.generator) { + setOffset(starToken, 1, firstToken) + } + if (node.id != null) { + setOffset(idToken, 1, firstToken) + } + setOffset(leftToken, 1, firstToken) + processNodeList(node.params, leftToken, rightToken, 1) + setOffset(bodyToken, 0, firstToken) + } + }, + + IfStatement(node: IfStatement) { + const ifToken = tokenStore.getFirstToken(node) + const ifLeftParenToken = tokenStore.getTokenAfter(ifToken) + const ifRightParenToken = tokenStore.getTokenBefore( + node.consequent, + isRightParen, + ) + + setOffset(ifLeftParenToken, 1, ifToken) + setOffset(ifRightParenToken, 0, ifLeftParenToken) + processMaybeBlock(node.consequent, ifToken) + + if (node.alternate != null) { + const elseToken = tokenStore.getTokenAfter( + node.consequent, + isNotRightParen, + ) as Token + + setOffset(elseToken, 0, ifToken) + processMaybeBlock(node.alternate, elseToken) + } + }, + + ImportDeclaration(node: ImportDeclaration) { + const firstSpecifier = node.specifiers[0] + const secondSpecifier = node.specifiers[1] + const importToken = tokenStore.getFirstToken(node) + const hasSemi = tokenStore.getLastToken(node).value === ";" + + const tokens: Token[] = [] // tokens to one indent + + if (!firstSpecifier) { + // There are 2 patterns: + // import "foo" + // import {} from "foo" + const secondToken = tokenStore.getFirstToken(node, 1) + if (isLeftBrace(secondToken)) { + setOffset( + [secondToken, tokenStore.getTokenAfter(secondToken)], + 0, + importToken, + ) + tokens.push( + tokenStore.getLastToken(node, hasSemi ? 2 : 1), // from + tokenStore.getLastToken(node, hasSemi ? 1 : 0), // "foo" + ) + } else { + tokens.push(tokenStore.getLastToken(node, hasSemi ? 1 : 0)) + } + } else if (firstSpecifier.type === "ImportDefaultSpecifier") { + if ( + secondSpecifier && + secondSpecifier.type === "ImportNamespaceSpecifier" + ) { + // There is a pattern: + // import Foo, * as foo from "foo" + tokens.push( + tokenStore.getFirstToken(firstSpecifier), // Foo + tokenStore.getTokenAfter(firstSpecifier), // comma + tokenStore.getFirstToken(secondSpecifier), // * + tokenStore.getLastToken(node, hasSemi ? 2 : 1), // from + tokenStore.getLastToken(node, hasSemi ? 1 : 0), // "foo" + ) + } else { + // There are 3 patterns: + // import Foo from "foo" + // import Foo, {} from "foo" + // import Foo, {a} from "foo" + const idToken = tokenStore.getFirstToken(firstSpecifier) + const nextToken = tokenStore.getTokenAfter(firstSpecifier) + if (isComma(nextToken)) { + const leftBrace = tokenStore.getTokenAfter(nextToken) + const rightBrace = tokenStore.getLastToken( + node, + hasSemi ? 3 : 2, + ) + setOffset([idToken, nextToken], 1, importToken) + setOffset(leftBrace, 0, idToken) + processNodeList( + node.specifiers.slice(1), + leftBrace, + rightBrace, + 1, + ) + tokens.push( + tokenStore.getLastToken(node, hasSemi ? 2 : 1), // from + tokenStore.getLastToken(node, hasSemi ? 1 : 0), // "foo" + ) + } else { + tokens.push( + idToken, + nextToken, // from + tokenStore.getTokenAfter(nextToken), // "foo" + ) + } + } + } else if (firstSpecifier.type === "ImportNamespaceSpecifier") { + // There is a pattern: + // import * as foo from "foo" + tokens.push( + tokenStore.getFirstToken(firstSpecifier), // * + tokenStore.getLastToken(node, hasSemi ? 2 : 1), // from + tokenStore.getLastToken(node, hasSemi ? 1 : 0), // "foo" + ) + } else { + // There is a pattern: + // import {a} from "foo" + const leftBrace = tokenStore.getFirstToken(node, 1) + const rightBrace = tokenStore.getLastToken( + node, + hasSemi ? 3 : 2, + ) + setOffset(leftBrace, 0, importToken) + processNodeList(node.specifiers, leftBrace, rightBrace, 1) + tokens.push( + tokenStore.getLastToken(node, hasSemi ? 2 : 1), // from + tokenStore.getLastToken(node, hasSemi ? 1 : 0), // "foo" + ) + } + + setOffset(tokens, 1, importToken) + }, + + ImportSpecifier(node: ImportSpecifier) { + if (node.local.range[0] !== node.imported.range[0]) { + const tokens = tokenStore.getTokens(node) + const firstToken = tokens.shift() as Token + setOffset(tokens, 1, firstToken) + } + }, + + ImportNamespaceSpecifier(node: ImportNamespaceSpecifier) { + const tokens = tokenStore.getTokens(node) + const firstToken = tokens.shift() as Token + setOffset(tokens, 1, firstToken) + }, + + LabeledStatement(node: LabeledStatement) { + const labelToken = tokenStore.getFirstToken(node) + const colonToken = tokenStore.getTokenAfter(labelToken) + const bodyToken = tokenStore.getTokenAfter(colonToken) + + setOffset([colonToken, bodyToken], 1, labelToken) + }, + + "MemberExpression, MetaProperty"( + node: MemberExpression | MetaProperty, + ) { + const objectToken = tokenStore.getFirstToken(node) + if (node.type === "MemberExpression" && node.computed) { + const leftBracketToken = tokenStore.getTokenBefore( + node.property, + isLeftBracket, + ) as Token + const propertyToken = tokenStore.getTokenAfter(leftBracketToken) + const rightBracketToken = tokenStore.getTokenAfter( + node.property, + isRightBracket, + ) + + setOffset(leftBracketToken, 1, objectToken) + setOffset(propertyToken, 1, leftBracketToken) + setOffset(rightBracketToken, 0, leftBracketToken) + } else { + const dotToken = tokenStore.getTokenBefore(node.property) + const propertyToken = tokenStore.getTokenAfter(dotToken) + + setOffset([dotToken, propertyToken], 1, objectToken) + } + }, + + "MethodDefinition, Property"(node: MethodDefinition | Property) { + const isMethod = + node.type === "MethodDefinition" || node.method === true + const prefixTokens = getPrefixTokens(node) + const hasPrefix = prefixTokens.length >= 1 + + for (let i = 1; i < prefixTokens.length; ++i) { + setOffset(prefixTokens[i], 0, prefixTokens[i - 1]) + } + + let lastKeyToken: Token + if (node.computed) { + const keyLeftToken = tokenStore.getFirstToken( + node, + isLeftBracket, + ) as Token + const keyToken = tokenStore.getTokenAfter(keyLeftToken) + const keyRightToken = (lastKeyToken = tokenStore.getTokenAfter( + node.key, + isRightBracket, + ) as Token) + + if (hasPrefix) { + setOffset(keyLeftToken, 0, last(prefixTokens) as Token) + } + setOffset(keyToken, 1, keyLeftToken) + setOffset(keyRightToken, 0, keyLeftToken) + } else { + const idToken = (lastKeyToken = tokenStore.getFirstToken( + node.key, + )) + + if (hasPrefix) { + setOffset(idToken, 0, last(prefixTokens) as Token) + } + } + + if (isMethod) { + const leftParenToken = tokenStore.getTokenAfter(lastKeyToken) + + setOffset(leftParenToken, 1, lastKeyToken) + } else if (node.type === "Property" && !node.shorthand) { + const colonToken = tokenStore.getTokenAfter(lastKeyToken) + const valueToken = tokenStore.getTokenAfter(colonToken) + + setOffset([colonToken, valueToken], 1, lastKeyToken) + } + }, + + NewExpression(node: NewExpression) { + const newToken = tokenStore.getFirstToken(node) + const calleeToken = tokenStore.getTokenAfter(newToken) + const rightToken = tokenStore.getLastToken(node) + const leftToken = isRightParen(rightToken) + ? tokenStore.getFirstTokenBetween( + node.callee, + rightToken, + isLeftParen, + ) + : null + + setOffset(calleeToken, 1, newToken) + if (leftToken != null) { + setOffset(leftToken, 1, calleeToken) + processNodeList(node.arguments, leftToken, rightToken, 1) + } + }, + + "ObjectExpression, ObjectPattern"( + node: ObjectExpression | ObjectPattern, + ) { + processNodeList( + node.properties, + tokenStore.getFirstToken(node), + tokenStore.getLastToken(node), + 1, + ) + }, + + SequenceExpression(node: SequenceExpression) { + processNodeList(node.expressions, null, null, 0) + }, + + SwitchCase(node: SwitchCase) { + const caseToken = tokenStore.getFirstToken(node) + + if (node.test != null) { + const testToken = tokenStore.getTokenAfter(caseToken) + const colonToken = tokenStore.getTokenAfter( + node.test, + isNotRightParen, + ) + + setOffset([testToken, colonToken], 1, caseToken) + } else { + const colonToken = tokenStore.getTokenAfter(caseToken) + + setOffset(colonToken, 1, caseToken) + } + + if ( + node.consequent.length === 1 && + node.consequent[0].type === "BlockStatement" + ) { + setOffset( + tokenStore.getFirstToken(node.consequent[0]), + 0, + caseToken, + ) + } else if (node.consequent.length >= 1) { + setOffset( + tokenStore.getFirstToken(node.consequent[0]), + 1, + caseToken, + ) + processNodeList(node.consequent, null, null, 0) + } + }, + + SwitchStatement(node: SwitchStatement) { + const switchToken = tokenStore.getFirstToken(node) + const leftParenToken = tokenStore.getTokenAfter(switchToken) + const discriminantToken = tokenStore.getTokenAfter(leftParenToken) + const leftBraceToken = tokenStore.getTokenAfter( + node.discriminant, + isLeftBrace, + ) as Token + const rightParenToken = tokenStore.getTokenBefore(leftBraceToken) + const rightBraceToken = tokenStore.getLastToken(node) + + setOffset(leftParenToken, 1, switchToken) + setOffset(discriminantToken, 1, leftParenToken) + setOffset(rightParenToken, 0, leftParenToken) + setOffset(leftBraceToken, 0, switchToken) + processNodeList( + node.cases, + leftBraceToken, + rightBraceToken, + options.switchCase, + ) + }, + + TaggedTemplateExpression(node: TaggedTemplateExpression) { + const tagTokens = getFirstAndLastTokens(node.tag, node.range[0]) + const quasiToken = tokenStore.getTokenAfter(tagTokens.lastToken) + + setOffset(quasiToken, 1, tagTokens.firstToken) + }, + + TemplateLiteral(node: TemplateLiteral) { + const firstToken = tokenStore.getFirstToken(node) + const quasiTokens = node.quasis + .slice(1) + .map((n) => tokenStore.getFirstToken(n)) + const expressionToken = node.quasis + .slice(0, -1) + .map((n) => tokenStore.getTokenAfter(n)) + + setOffset(quasiTokens, 0, firstToken) + setOffset(expressionToken, 1, firstToken) + }, + + TryStatement(node: TryStatement) { + const tryToken = tokenStore.getFirstToken(node) + const tryBlockToken = tokenStore.getFirstToken(node.block) + + setOffset(tryBlockToken, 0, tryToken) + + if (node.handler != null) { + const catchToken = tokenStore.getFirstToken(node.handler) + + setOffset(catchToken, 0, tryToken) + } + + if (node.finalizer != null) { + const finallyToken = tokenStore.getTokenBefore(node.finalizer) + const finallyBlockToken = tokenStore.getFirstToken( + node.finalizer, + ) + + setOffset([finallyToken, finallyBlockToken], 0, tryToken) + } + }, + + UpdateExpression(node: UpdateExpression) { + const firstToken = tokenStore.getFirstToken(node) + const nextToken = tokenStore.getTokenAfter(firstToken) + + setOffset(nextToken, 1, firstToken) + }, + + VariableDeclaration(node: VariableDeclaration) { + processNodeList( + node.declarations, + tokenStore.getFirstToken(node), + null, + 1, + ) + }, + + VariableDeclarator(node: VariableDeclarator) { + if (node.init != null) { + const idToken = tokenStore.getFirstToken(node) + const eqToken = tokenStore.getTokenAfter(node.id) + const initToken = tokenStore.getTokenAfter(eqToken) + + setOffset([eqToken, initToken], 1, idToken) + } + }, + + "WhileStatement, WithStatement"(node: WhileStatement | WithStatement) { + const firstToken = tokenStore.getFirstToken(node) + const leftParenToken = tokenStore.getTokenAfter(firstToken) + const rightParenToken = tokenStore.getTokenBefore( + node.body, + isRightParen, + ) + + setOffset(leftParenToken, 1, firstToken) + setOffset(rightParenToken, 0, leftParenToken) + processMaybeBlock(node.body, firstToken) + }, + + YieldExpression(node: YieldExpression) { + if (node.argument != null) { + const yieldToken = tokenStore.getFirstToken(node) + + setOffset(tokenStore.getTokenAfter(yieldToken), 1, yieldToken) + if (node.delegate) { + setOffset( + tokenStore.getTokenAfter(yieldToken, 1), + 1, + yieldToken, + ) + } + } + }, + + // Process semicolons. + ":statement"(node: Statement) { + const firstToken = tokenStore.getFirstToken(node) + const lastToken = tokenStore.getLastToken(node) + if (isSemicolon(lastToken) && firstToken !== lastToken) { + setOffset(lastToken, 0, firstToken) + } + + // Set to the semicolon of the previous token for semicolon-free style. + // E.g., + // foo + // ;[1,2,3].forEach(f) + const info = offsets.get(firstToken) + const prevToken = tokenStore.getTokenBefore(firstToken) + if ( + info != null && + isSemicolon(prevToken) && + prevToken.loc.end.line === firstToken.loc.start.line + ) { + offsets.set(prevToken, info) + } + }, + + // Process parentheses. + // `:expression` does not match with MetaProperty and TemplateLiteral as a bug: https://github.com/estools/esquery/pull/59 + ":expression, MetaProperty, TemplateLiteral"( + node: Expression | MetaProperty | TemplateLiteral, + ) { + let leftToken = tokenStore.getTokenBefore(node) + let rightToken = tokenStore.getTokenAfter(node) + let firstToken = tokenStore.getFirstToken(node) + + while (isLeftParen(leftToken) && isRightParen(rightToken)) { + setOffset(firstToken, 1, leftToken) + setOffset(rightToken, 0, leftToken) + + firstToken = leftToken + leftToken = tokenStore.getTokenBefore(leftToken) + rightToken = tokenStore.getTokenAfter(rightToken) + } + }, + + // Ignore tokens of unknown nodes. + "*:exit"(node: ASTNode) { + if ( + !KNOWN_NODES.has(node.type) && + !NON_STANDARD_KNOWN_NODES.has(node.type) + ) { + ignore(node) + } + }, + + // Top-level process. + Program(node: Program) { + const firstToken = node.tokens[0] + const isScriptTag = + firstToken != null && + firstToken.type === "Punctuator" && + firstToken.value === "<script>" + const baseIndent = isScriptTag + ? options.indentSize * options.baseIndent + : 0 + + for (const statement of node.body) { + processTopLevelNode(statement, baseIndent) + } + }, + + "VElement[parent.type!='VElement']"(node: VElement) { + processTopLevelNode(node, 0) + }, + + // Do validation. + ":matches(Program, VElement[parent.type!='VElement']):exit"( + node: Program | VElement, + ) { + let comments = [] + let tokensOnSameLine: Token[] = [] + let isBesideMultilineToken = false + let lastValidatedToken = null + + // Validate indentation of tokens. + for (const token of tokenStore.getTokens(node, ITERATION_OPTS)) { + if ( + tokensOnSameLine.length === 0 || + tokensOnSameLine[0].loc.start.line === token.loc.start.line + ) { + // This is on the same line (or the first token). + tokensOnSameLine.push(token) + } else if (tokensOnSameLine.every(isComment)) { + // New line is detected, but the all tokens of the previous line are comment. + // Comment lines are adjusted to the next code line. + comments.push(tokensOnSameLine[0]) + isBesideMultilineToken = + (last(tokensOnSameLine) as Token).loc.end.line === + token.loc.start.line + tokensOnSameLine = [token] + } else { + // New line is detected, so validate the tokens. + if (!isBesideMultilineToken) { + validate(tokensOnSameLine, comments, lastValidatedToken) + lastValidatedToken = tokensOnSameLine[0] + } + isBesideMultilineToken = + (last(tokensOnSameLine) as Token).loc.end.line === + token.loc.start.line + tokensOnSameLine = [token] + comments = [] + } + } + if ( + tokensOnSameLine.length >= 1 && + tokensOnSameLine.some(isNotComment) + ) { + validate(tokensOnSameLine, comments, lastValidatedToken) + } + }, + }) +} diff --git a/src/eslint-plugins/utils/index.ts b/src/eslint-plugins/utils/index.ts new file mode 100644 index 00000000..ed97222d --- /dev/null +++ b/src/eslint-plugins/utils/index.ts @@ -0,0 +1,2181 @@ +/** + * @author Toru Nagashima <https://github.com/mysticatea> + * @copyright 2017 Toru Nagashima. All rights reserved. + * See LICENSE file in root directory for full license. + */ +'use strict' + +import * as ESLint from "eslint"; +import * as ESTree from "estree"; +import { VueObjectData, VueObjectType, VueVisitor } from "../types/utils"; + +type RuleModule = ESLint.Rule.RuleModule; +type Position = ESTree.Position; +type CodePath = ESLint.Rule.CodePath; +type CodePathSegment = ESLint.Rule.CodePathSegment; + +type ComponentArrayPropDetectName = { + type: "array"; + key: Literal | TemplateLiteral; + propName: string; + value: null; + node: Expression | SpreadElement; +}; + +type ComponentArrayPropUnknownName = { + type: "array"; + key: null; + propName: null; + value: null; + node: Expression | SpreadElement; +}; + +type ComponentArrayProp = + | ComponentArrayPropDetectName + | ComponentArrayPropUnknownName; + +type ComponentObjectPropDetectName = { + type: "object"; + key: Expression; + propName: string; + value: Expression; + node: Property; +}; + +type ComponentObjectPropUnknownName = { + type: "object"; + key: null; + propName: null; + value: Expression; + node: Property; +}; + +type ComponentObjectProp = + | ComponentObjectPropDetectName + | ComponentObjectPropUnknownName; + +type ComponentArrayEmitDetectName = { + type: "array"; + key: Literal | TemplateLiteral; + emitName: string; + value: null; + node: Expression | SpreadElement; +}; + +type ComponentArrayEmitUnknownName = { + type: "array"; + key: null; + emitName: null; + value: null; + node: Expression | SpreadElement; +}; + +type ComponentArrayEmit = + | ComponentArrayEmitDetectName + | ComponentArrayEmitUnknownName; + +type ComponentObjectEmitDetectName = { + type: "object"; + key: Expression; + emitName: string; + value: Expression; + node: Property; +}; + +type ComponentObjectEmitUnknownName = { + type: "object"; + key: null; + emitName: null; + value: Expression; + node: Property; +}; + +type ComponentObjectEmit = + | ComponentObjectEmitDetectName + | ComponentObjectEmitUnknownName; + +type ComponentComputedProperty = { + key: string | null; + value: BlockStatement | null; +}; + +type GroupName = "props" | "data" | "computed" | "setup" | "watch" | "methods"; +type ComponentArrayPropertyData = { + type: "array"; + name: string; + groupName: GroupName; + node: Literal | TemplateLiteral; +}; +type ComponentObjectPropertyData = { + type: "object"; + name: string; + groupName: GroupName; + node: Identifier | Literal | TemplateLiteral; + property: Property; +}; +type ComponentPropertyData = + | ComponentArrayPropertyData + | ComponentObjectPropertyData; + + + /** + // * @typedef {import('eslint').Rule.RuleModule} RuleModule + // * @typedef {import('estree').Position} Position + // * @typedef {import('eslint').Rule.CodePath} CodePath + // * @typedef {import('eslint').Rule.CodePathSegment} CodePathSegment + */ + /** + // * @typedef {object} ComponentArrayPropDetectName + // * @property {'array'} type + // * @property {Literal | TemplateLiteral} key + // * @property {string} propName + // * @property {null} value + // * @property {Expression | SpreadElement} node + * + // * @typedef {object} ComponentArrayPropUnknownName + // * @property {'array'} type + // * @property {null} key + // * @property {null} propName + // * @property {null} value + // * @property {Expression | SpreadElement} node + * + // * @typedef {ComponentArrayPropDetectName | ComponentArrayPropUnknownName} ComponentArrayProp + * + // * @typedef {object} ComponentObjectPropDetectName + // * @property {'object'} type + // * @property {Expression} key + // * @property {string} propName + // * @property {Expression} value + // * @property {Property} node + * + // * @typedef {object} ComponentObjectPropUnknownName + // * @property {'object'} type + // * @property {null} key + // * @property {null} propName + // * @property {Expression} value + // * @property {Property} node + * + // * @typedef {ComponentObjectPropDetectName | ComponentObjectPropUnknownName} ComponentObjectProp + */ + /** + // * @typedef {object} ComponentArrayEmitDetectName + // * @property {'array'} type + // * @property {Literal | TemplateLiteral} key + // * @property {string} emitName + // * @property {null} value + // * @property {Expression | SpreadElement} node + * + // * @typedef {object} ComponentArrayEmitUnknownName + // * @property {'array'} type + // * @property {null} key + // * @property {null} emitName + // * @property {null} value + // * @property {Expression | SpreadElement} node + * + // * @typedef {ComponentArrayEmitDetectName | ComponentArrayEmitUnknownName} ComponentArrayEmit + * + // * @typedef {object} ComponentObjectEmitDetectName + // * @property {'object'} type + // * @property {Expression} key + // * @property {string} emitName + // * @property {Expression} value + // * @property {Property} node + * + // * @typedef {object} ComponentObjectEmitUnknownName + // * @property {'object'} type + // * @property {null} key + // * @property {null} emitName + // * @property {Expression} value + // * @property {Property} node + * + * @typedef {ComponentObjectEmitDetectName | ComponentObjectEmitUnknownName} ComponentObjectEmit + */ + /** + * @typedef { {key: string | null, value: BlockStatement | null} } ComponentComputedProperty + */ + /** + * @typedef { 'props' | 'data' | 'computed' | 'setup' | 'watch' | 'methods' } GroupName + * @typedef { { type: 'array', name: string, groupName: GroupName, node: Literal | TemplateLiteral } } ComponentArrayPropertyData + * @typedef { { type: 'object', name: string, groupName: GroupName, node: Identifier | Literal | TemplateLiteral, property: Property } } ComponentObjectPropertyData + * @typedef { ComponentArrayPropertyData | ComponentObjectPropertyData } ComponentPropertyData + */ + /** + * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').VueObjectType} VueObjectType + * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').VueObjectData} VueObjectData + * @typedef {import('../../typings/eslint-plugin-vue/util-types/utils').VueVisitor} VueVisitor + */ + + // ------------------------------------------------------------------------------ + // Helpers + // ------------------------------------------------------------------------------ + + const HTML_ELEMENT_NAMES = new Set(require('./html-elements.json')) + const SVG_ELEMENT_NAMES = new Set(require('./svg-elements.json')) + const VOID_ELEMENT_NAMES = new Set(require('./void-elements.json')) + import path from "path"; + import vueEslintParser from "vue-eslint-parser"; + import {findVariable} from "eslint-utils"; + + + + + /** + * @type { WeakMap<RuleContext, Token[]> } + */ + const componentComments = new WeakMap() + + + let ruleMap: Map<string, RuleModule> | null = null + /** + * Get the core rule implementation from the rule name + */ + function getCoreRule(name: string): RuleModule { + const map = ruleMap || (ruleMap = new (require('eslint').Linter)().getRules()) + return map.get(name) || require(`eslint/lib/rules/${name}`) + } + + /** + * Wrap the rule context object to override methods which access to tokens (such as getTokenAfter). + * @param {RuleContext} context The rule context object. + * @param {ParserServices.TokenStore} tokenStore The token store object for template. + * @returns {RuleContext} + */ + function wrapContextToOverrideTokenMethods(context, tokenStore) { + const eslintSourceCode = context.getSourceCode() + /** @type {Token[] | null} */ + let tokensAndComments = null + function getTokensAndComments() { + if (tokensAndComments) { + return tokensAndComments + } + const templateBody = eslintSourceCode.ast.templateBody + tokensAndComments = templateBody + ? tokenStore.getTokens(templateBody, { + includeComments: true + }) + : [] + return tokensAndComments + } + const sourceCode = new Proxy(Object.assign({}, eslintSourceCode), { + get(_object, key) { + if (key === 'tokensAndComments') { + return getTokensAndComments() + } + // @ts-expect-error + return key in tokenStore ? tokenStore[key] : eslintSourceCode[key] + } + }) + + return { + // @ts-expect-error + __proto__: context, + getSourceCode() { + return sourceCode + } + } + } + + /** + * Wrap the rule context object to override report method to skip the dynamic argument. + * @param {RuleContext} context The rule context object. + * @returns {RuleContext} + */ + function wrapContextToOverrideReportMethodToSkipDynamicArgument(context) { + const sourceCode = context.getSourceCode() + const templateBody = sourceCode.ast.templateBody + if (!templateBody) { + return context + } + /** @type {Range[]} */ + const directiveKeyRanges = [] + const traverseNodes = vueEslintParser.AST.traverseNodes + traverseNodes(templateBody, { + enterNode(node, parent) { + if ( + parent && + parent.type === 'VDirectiveKey' && + node.type === 'VExpressionContainer' + ) { + directiveKeyRanges.push(node.range) + } + }, + leaveNode() {} + }) + + return { + // @ts-expect-error + __proto__: context, + report(descriptor, ...args) { + let range = null + if (descriptor.loc) { + const startLoc = descriptor.loc.start || descriptor.loc + const endLoc = descriptor.loc.end || startLoc + range = [ + sourceCode.getIndexFromLoc(startLoc), + sourceCode.getIndexFromLoc(endLoc) + ] + } else if (descriptor.node) { + range = descriptor.node.range + } + if (range) { + for (const directiveKeyRange of directiveKeyRanges) { + if ( + range[0] < directiveKeyRange[1] && + directiveKeyRange[0] < range[1] + ) { + return + } + } + } + context.report(descriptor, ...args) + } + } + } + + // ------------------------------------------------------------------------------ + // Exports + // ------------------------------------------------------------------------------ + + module.exports = { + /** + * Register the given visitor to parser services. + * If the parser service of `vue-eslint-parser` was not found, + * this generates a warning. + * + * @param {RuleContext} context The rule context to use parser services. + * @param {TemplateListener} templateBodyVisitor The visitor to traverse the template body. + * @param {RuleListener} [scriptVisitor] The visitor to traverse the script. + * @returns {RuleListener} The merged visitor. + */ + defineTemplateBodyVisitor, + + /** + * Wrap a given core rule to apply it to Vue.js template. + * @param {string} coreRuleName The name of the core rule implementation to wrap. + * @param {Object} [options] The option of this rule. + * @param {string[]} [options.categories] The categories of this rule. + * @param {boolean} [options.skipDynamicArguments] If `true`, skip validation within dynamic arguments. + * @param {boolean} [options.skipDynamicArgumentsReport] If `true`, skip report within dynamic arguments. + * @param { (context: RuleContext, options: { coreHandlers: RuleListener }) => TemplateListener } [options.create] If define, extend core rule. + */ + wrapCoreRule(coreRuleName: string, options: { + categories: string[] + skipDynamicArguments: boolean + skipDynamicArgumentsReport: boolean + create: (context: ESLint.Rule.RuleContext, + options: { + coreHandlers: ESLint.Rule.RuleListener + }) => TemplateListener + }): RuleModule { + const coreRule = getCoreRule(coreRuleName) + const { + categories, + skipDynamicArguments, + skipDynamicArgumentsReport, + create + } = options || {} + return { + create(context) { + const tokenStore = + context.parserServices.getTemplateBodyTokenStore && + context.parserServices.getTemplateBodyTokenStore() + + // The `context.getSourceCode()` cannot access the tokens of templates. + // So override the methods which access to tokens by the `tokenStore`. + if (tokenStore) { + context = wrapContextToOverrideTokenMethods(context, tokenStore) + } + + if (skipDynamicArgumentsReport) { + context = wrapContextToOverrideReportMethodToSkipDynamicArgument( + context + ) + } + + // Move `Program` handlers to `VElement[parent.type!='VElement']` + const coreHandlers = coreRule.create(context) + + const handlers = /** @type {TemplateListener} */ (Object.assign( + {}, + coreHandlers + )) + if (handlers.Program) { + handlers["VElement[parent.type!='VElement']"] = handlers.Program + delete handlers.Program + } + if (handlers['Program:exit']) { + handlers["VElement[parent.type!='VElement']:exit"] = + handlers['Program:exit'] + delete handlers['Program:exit'] + } + + if (skipDynamicArguments) { + let withinDynamicArguments = false + for (const name of Object.keys(handlers)) { + const original = handlers[name] + /** @param {any[]} args */ + handlers[name] = (...args) => { + if (withinDynamicArguments) return + // @ts-expect-error + original(...args) + } + } + handlers['VDirectiveKey > VExpressionContainer'] = () => { + withinDynamicArguments = true + } + handlers['VDirectiveKey > VExpressionContainer:exit'] = () => { + withinDynamicArguments = false + } + } + + if (create) { + compositingVisitors(handlers, create(context, { coreHandlers })) + } + + // Apply the handlers to templates. + return defineTemplateBodyVisitor(context, handlers) + }, + + meta: Object.assign({}, coreRule.meta, { + docs: Object.assign({}, coreRule.meta.docs, { + category: null, + categories, + url: `https://eslint.vuejs.org/rules/${path.basename( + coreRule.meta.docs.url || '' + )}.html`, + extensionRule: true, + coreRuleUrl: coreRule.meta.docs.url + }) + }) + } + }, + /** + * Checks whether the given value is defined. + * @template T + * @param {T | null | undefined} v + * @returns {v is T} + */ + isDef, + /** + * Get the previous sibling element of the given element. + * @param {VElement} node The element node to get the previous sibling element. + * @returns {VElement|null} The previous sibling element. + */ + prevSibling(node) { + let prevElement = null + + for (const siblingNode of (node.parent && node.parent.children) || []) { + if (siblingNode === node) { + return prevElement + } + if (siblingNode.type === 'VElement') { + prevElement = siblingNode + } + } + + return null + }, + + /** + * Check whether the given start tag has specific directive. + * @param {VElement} node The start tag node to check. + * @param {string} name The attribute name to check. + * @param {string} [value] The attribute value to check. + * @returns {boolean} `true` if the start tag has the attribute. + */ + hasAttribute(node, name, value) { + return Boolean(this.getAttribute(node, name, value)) + }, + + /** + * Check whether the given start tag has specific directive. + * @param {VElement} node The start tag node to check. + * @param {string} name The directive name to check. + * @param {string} [argument] The directive argument to check. + * @returns {boolean} `true` if the start tag has the directive. + */ + hasDirective(node, name, argument) { + return Boolean(this.getDirective(node, name, argument)) + }, + + /** + * Check whether the given directive attribute has their empty value (`=""`). + * @param {VDirective} node The directive attribute node to check. + * @param {RuleContext} context The rule context to use parser services. + * @returns {boolean} `true` if the directive attribute has their empty value (`=""`). + */ + isEmptyValueDirective(node, context) { + if (node.value == null) { + return false + } + if (node.value.expression != null) { + return false + } + + let valueText = context.getSourceCode().getText(node.value) + if ( + (valueText[0] === '"' || valueText[0] === "'") && + valueText[0] === valueText[valueText.length - 1] + ) { + // quoted + valueText = valueText.slice(1, -1) + } + if (!valueText) { + // empty + return true + } + return false + }, + + /** + * Check whether the given directive attribute has their empty expression value (e.g. `=" "`, `="/* */"`). + * @param {VDirective} node The directive attribute node to check. + * @param {RuleContext} context The rule context to use parser services. + * @returns {boolean} `true` if the directive attribute has their empty expression value. + */ + isEmptyExpressionValueDirective(node, context) { + if (node.value == null) { + return false + } + if (node.value.expression != null) { + return false + } + + const valueNode = node.value + const tokenStore = context.parserServices.getTemplateBodyTokenStore() + let quote1 = null + let quote2 = null + // `node.value` may be only comments, so cannot get the correct tokens with `tokenStore.getTokens(node.value)`. + for (const token of tokenStore.getTokens(node)) { + if (token.range[1] <= valueNode.range[0]) { + continue + } + if (valueNode.range[1] <= token.range[0]) { + // empty + return true + } + if ( + !quote1 && + token.type === 'Punctuator' && + (token.value === '"' || token.value === "'") + ) { + quote1 = token + continue + } + if ( + !quote2 && + quote1 && + token.type === 'Punctuator' && + token.value === quote1.value + ) { + quote2 = token + continue + } + // not empty + return false + } + // empty + return true + }, + + /** + * Get the attribute which has the given name. + * @param {VElement} node The start tag node to check. + * @param {string} name The attribute name to check. + * @param {string} [value] The attribute value to check. + * @returns {VAttribute | null} The found attribute. + */ + getAttribute(node, name, value) { + return ( + node.startTag.attributes.find( + /** + * @param {VAttribute | VDirective} node + * @returns {node is VAttribute} + */ + (node) => { + return ( + !node.directive && + node.key.name === name && + (value === undefined || + (node.value != null && node.value.value === value)) + ) + } + ) || null + ) + }, + + /** + * Get the directive list which has the given name. + * @param {VElement | VStartTag} node The start tag node to check. + * @param {string} name The directive name to check. + * @returns {VDirective[]} The array of `v-slot` directives. + */ + getDirectives(node, name) { + const attributes = + node.type === 'VElement' ? node.startTag.attributes : node.attributes + return attributes.filter( + /** + * @param {VAttribute | VDirective} node + * @returns {node is VDirective} + */ + (node) => { + return node.directive && node.key.name.name === name + } + ) + }, + /** + * Get the directive which has the given name. + * @param {VElement} node The start tag node to check. + * @param {string} name The directive name to check. + * @param {string} [argument] The directive argument to check. + * @returns {VDirective | null} The found directive. + */ + getDirective(node, name, argument) { + return ( + node.startTag.attributes.find( + /** + * @param {VAttribute | VDirective} node + * @returns {node is VDirective} + */ + (node) => { + return ( + node.directive && + node.key.name.name === name && + (argument === undefined || + (node.key.argument && + node.key.argument.type === 'VIdentifier' && + node.key.argument.name) === argument) + ) + } + ) || null + ) + }, + + /** + * Returns the list of all registered components + * @param {ObjectExpression} componentObject + * @returns { { node: Property, name: string }[] } Array of ASTNodes + */ + getRegisteredComponents(componentObject) { + const componentsNode = componentObject.properties.find( + /** + * @param {ESNode} p + * @returns {p is (Property & { key: Identifier & {name: 'components'}, value: ObjectExpression })} + */ + (p) => { + return ( + p.type === 'Property' && + getStaticPropertyName(p) === 'components' && + p.value.type === 'ObjectExpression' + ) + } + ) + + if (!componentsNode) { + return [] + } + + return componentsNode.value.properties + .filter(isProperty) + .map((node) => { + const name = getStaticPropertyName(node) + return name ? { node, name } : null + }) + .filter(isDef) + }, + + /** + * Check whether the previous sibling element has `if` or `else-if` directive. + * @param {VElement} node The element node to check. + * @returns {boolean} `true` if the previous sibling element has `if` or `else-if` directive. + */ + prevElementHasIf(node) { + const prev = this.prevSibling(node) + return ( + prev != null && + prev.startTag.attributes.some( + (a) => + a.directive && + (a.key.name.name === 'if' || a.key.name.name === 'else-if') + ) + ) + }, + + /** + * Check whether the given node is a custom component or not. + * @param {VElement} node The start tag node to check. + * @returns {boolean} `true` if the node is a custom component. + */ + isCustomComponent(node) { + return ( + (this.isHtmlElementNode(node) && + !this.isHtmlWellKnownElementName(node.rawName)) || + (this.isSvgElementNode(node) && + !this.isSvgWellKnownElementName(node.rawName)) || + this.hasAttribute(node, 'is') || + this.hasDirective(node, 'bind', 'is') || + this.hasDirective(node, 'is') + ) + }, + + /** + * Check whether the given node is a HTML element or not. + * @param {VElement} node The node to check. + * @returns {boolean} `true` if the node is a HTML element. + */ + isHtmlElementNode(node) { + return node.namespace === vueEslintParser.AST.NS.HTML + }, + + /** + * Check whether the given node is a SVG element or not. + * @param {VElement} node The node to check. + * @returns {boolean} `true` if the name is a SVG element. + */ + isSvgElementNode(node) { + return node.namespace === vueEslintParser.AST.NS.SVG + }, + + /** + * Check whether the given name is a MathML element or not. + * @param {VElement} node The node to check. + * @returns {boolean} `true` if the node is a MathML element. + */ + isMathMLElementNode(node) { + return node.namespace === vueEslintParser.AST.NS.MathML + }, + + /** + * Check whether the given name is an well-known element or not. + * @param {string} name The name to check. + * @returns {boolean} `true` if the name is an well-known element name. + */ + isHtmlWellKnownElementName(name) { + return HTML_ELEMENT_NAMES.has(name) + }, + + /** + * Check whether the given name is an well-known SVG element or not. + * @param {string} name The name to check. + * @returns {boolean} `true` if the name is an well-known SVG element name. + */ + isSvgWellKnownElementName(name) { + return SVG_ELEMENT_NAMES.has(name) + }, + + /** + * Check whether the given name is a void element name or not. + * @param {string} name The name to check. + * @returns {boolean} `true` if the name is a void element name. + */ + isHtmlVoidElementName(name) { + return VOID_ELEMENT_NAMES.has(name) + }, + /** + * Gets the property name of a given node. + * @param {Property|AssignmentProperty|MethodDefinition|MemberExpression} node - The node to get. + * @return {string|null} The property name if static. Otherwise, null. + */ + getStaticPropertyName, + /** + * Gets the string of a given node. + * @param {Literal|TemplateLiteral} node - The node to get. + * @return {string|null} The string if static. Otherwise, null. + */ + getStringLiteralValue, + /** + * Get all props by looking at all component's properties + * @param {ObjectExpression} componentObject Object with component definition + * @return {(ComponentArrayProp | ComponentObjectProp)[]} Array of component props in format: [{key?: String, value?: ASTNode, node: ASTNod}] + */ + getComponentProps(componentObject) { + const propsNode = componentObject.properties.find( + /** + * @param {ESNode} p + * @returns {p is (Property & { key: Identifier & {name: 'props'}, value: ObjectExpression | ArrayExpression })} + */ + (p) => { + return ( + p.type === 'Property' && + getStaticPropertyName(p) === 'props' && + (p.value.type === 'ObjectExpression' || + p.value.type === 'ArrayExpression') + ) + } + ) + + if (!propsNode) { + return [] + } + + if (propsNode.value.type === 'ObjectExpression') { + return propsNode.value.properties.filter(isProperty).map((prop) => { + const propName = getStaticPropertyName(prop) + if (propName != null) { + return { + type: 'object', + key: prop.key, + propName, + value: skipTSAsExpression(prop.value), + node: prop + } + } + return { + type: 'object', + key: null, + propName: null, + value: skipTSAsExpression(prop.value), + node: prop + } + }) + } else { + return propsNode.value.elements.filter(isDef).map((prop) => { + if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') { + const propName = getStringLiteralValue(prop) + if (propName != null) { + return { + type: 'array', + key: prop, + propName, + value: null, + node: prop + } + } + } + return { + type: 'array', + key: null, + propName: null, + value: null, + node: prop + } + }) + } + }, + + /** + * Get all emits by looking at all component's properties + * @param {ObjectExpression} componentObject Object with component definition + * @return {(ComponentArrayEmit | ComponentObjectEmit)[]} Array of component emits in format: [{key?: String, value?: ASTNode, node: ASTNod}] + */ + getComponentEmits(componentObject) { + const emitsNode = componentObject.properties.find( + /** + * @param {ESNode} p + * @returns {p is (Property & { key: Identifier & {name: 'emits'}, value: ObjectExpression | ArrayExpression })} + */ + (p) => { + return ( + p.type === 'Property' && + getStaticPropertyName(p) === 'emits' && + (p.value.type === 'ObjectExpression' || + p.value.type === 'ArrayExpression') + ) + } + ) + + if (!emitsNode) { + return [] + } + + if (emitsNode.value.type === 'ObjectExpression') { + return emitsNode.value.properties.filter(isProperty).map((prop) => { + const emitName = getStaticPropertyName(prop) + if (emitName != null) { + return { + type: 'object', + key: prop.key, + emitName, + value: skipTSAsExpression(prop.value), + node: prop + } + } + return { + type: 'object', + key: null, + emitName: null, + value: skipTSAsExpression(prop.value), + node: prop + } + }) + } else { + return emitsNode.value.elements.filter(isDef).map((prop) => { + if (prop.type === 'Literal' || prop.type === 'TemplateLiteral') { + const emitName = getStringLiteralValue(prop) + if (emitName != null) { + return { + type: 'array', + key: prop, + emitName, + value: null, + node: prop + } + } + } + return { + type: 'array', + key: null, + emitName: null, + value: null, + node: prop + } + }) + } + }, + + /** + * Get all computed properties by looking at all component's properties + * @param {ObjectExpression} componentObject Object with component definition + * @return {ComponentComputedProperty[]} Array of computed properties in format: [{key: String, value: ASTNode}] + */ + getComputedProperties(componentObject) { + const computedPropertiesNode = componentObject.properties.find( + /** + * @param {ESNode} p + * @returns {p is (Property & { key: Identifier & {name: 'computed'}, value: ObjectExpression })} + */ + (p) => { + return ( + p.type === 'Property' && + getStaticPropertyName(p) === 'computed' && + p.value.type === 'ObjectExpression' + ) + } + ) + + if (!computedPropertiesNode) { + return [] + } + + return computedPropertiesNode.value.properties + .filter(isProperty) + .map((cp) => { + const key = getStaticPropertyName(cp) + /** @type {Expression} */ + const propValue = skipTSAsExpression(cp.value) + /** @type {BlockStatement | null} */ + let value = null + + if (propValue.type === 'FunctionExpression') { + value = propValue.body + } else if (propValue.type === 'ObjectExpression') { + const get = /** @type {(Property & { value: FunctionExpression }) | null} */ (findProperty( + propValue, + 'get', + (p) => p.value.type === 'FunctionExpression' + )) + value = get ? get.value.body : null + } + + return { key, value } + }) + }, + + /** + * Get getter body from computed function + * @param {CallExpression} callExpression call of computed function + * @return {FunctionExpression | ArrowFunctionExpression | null} getter function + */ + getGetterBodyFromComputedFunction(callExpression) { + if (callExpression.arguments.length <= 0) { + return null + } + + const arg = callExpression.arguments[0] + + if ( + arg.type === 'FunctionExpression' || + arg.type === 'ArrowFunctionExpression' + ) { + return arg + } + + if (arg.type === 'ObjectExpression') { + const getProperty = /** @type {(Property & { value: FunctionExpression | ArrowFunctionExpression }) | null} */ (findProperty( + arg, + 'get', + (p) => + p.value.type === 'FunctionExpression' || + p.value.type === 'ArrowFunctionExpression' + )) + return getProperty ? getProperty.value : null + } + + return null + }, + + isVueFile, + + /** + * Check if current file is a Vue instance or component and call callback + * @param {RuleContext} context The ESLint rule context object. + * @param { (node: ObjectExpression, type: VueObjectType) => void } cb Callback function + */ + executeOnVue(context, cb) { + return compositingVisitors( + this.executeOnVueComponent(context, cb), + this.executeOnVueInstance(context, cb) + ) + }, + + /** + * Define handlers to traverse the Vue Objects. + * Some special events are available to visitor. + * + * - `onVueObjectEnter` ... Event when Vue Object is found. + * - `onVueObjectExit` ... Event when Vue Object visit ends. + * - `onSetupFunctionEnter` ... Event when setup function found. + * - `onRenderFunctionEnter` ... Event when render function found. + * + * @param {RuleContext} context The ESLint rule context object. + * @param {VueVisitor} visitor The visitor to traverse the Vue Objects. + */ + defineVueVisitor(context, visitor) { + /** @type {VueObjectData | null} */ + let vueStack = null + + /** + * @param {string} key + * @param {ESNode} node + */ + function callVisitor(key, node) { + if (visitor[key] && vueStack) { + // @ts-expect-error + visitor[key](node, vueStack) + } + } + + /** @type {NodeListener} */ + const vueVisitor = {} + for (const key in visitor) { + vueVisitor[key] = (node) => callVisitor(key, node) + } + + /** + * @param {ObjectExpression} node + */ + vueVisitor.ObjectExpression = (node) => { + const type = getVueObjectType(context, node) + if (type) { + vueStack = { + node, + type, + parent: vueStack, + get functional() { + const functional = node.properties.find( + /** + * @param {Property | SpreadElement} p + * @returns {p is Property} + */ + (p) => + p.type === 'Property' && + getStaticPropertyName(p) === 'functional' + ) + if (!functional) { + return false + } + if ( + functional.value.type === 'Literal' && + functional.value.value === false + ) { + return false + } + return true + } + } + callVisitor('onVueObjectEnter', node) + } + callVisitor('ObjectExpression', node) + } + vueVisitor['ObjectExpression:exit'] = (node) => { + callVisitor('ObjectExpression:exit', node) + if (vueStack && vueStack.node === node) { + callVisitor('onVueObjectExit', node) + vueStack = vueStack.parent + } + } + if (visitor.onSetupFunctionEnter || visitor.onRenderFunctionEnter) { + /** @param { (FunctionExpression | ArrowFunctionExpression) & { parent: Property } } node */ + vueVisitor[ + 'Property[value.type=/^(Arrow)?FunctionExpression$/] > :function' + ] = (node) => { + /** @type {Property} */ + const prop = node.parent + if (vueStack && prop.parent === vueStack.node && prop.value === node) { + const name = getStaticPropertyName(prop) + if (name === 'setup') { + callVisitor('onSetupFunctionEnter', node) + } else if (name === 'render') { + callVisitor('onRenderFunctionEnter', node) + } + } + callVisitor( + 'Property[value.type=/^(Arrow)?FunctionExpression$/] > :function', + node + ) + } + } + + return vueVisitor + }, + + getVueObjectType, + /** + * Get the Vue component definition type from given node + * Vue.component('xxx', {}) || component('xxx', {}) + * @param {ObjectExpression} node Node to check + * @returns {'component' | 'mixin' | 'extend' | 'createApp' | 'defineComponent' | null} + */ + getVueComponentDefinitionType, + compositingVisitors, + + /** + * Check if current file is a Vue instance (new Vue) and call callback + * @param {RuleContext} context The ESLint rule context object. + * @param { (node: ObjectExpression, type: VueObjectType) => void } cb Callback function + */ + executeOnVueInstance(context, cb) { + return { + /** @param {ObjectExpression} node */ + 'ObjectExpression:exit'(node) { + const type = getVueObjectType(context, node) + if (!type || type !== 'instance') return + cb(node, type) + } + } + }, + + /** + * Check if current file is a Vue component and call callback + * @param {RuleContext} context The ESLint rule context object. + * @param { (node: ObjectExpression, type: VueObjectType) => void } cb Callback function + */ + executeOnVueComponent(context, cb) { + return { + /** @param {ObjectExpression} node */ + 'ObjectExpression:exit'(node) { + const type = getVueObjectType(context, node) + if ( + !type || + (type !== 'mark' && type !== 'export' && type !== 'definition') + ) + return + cb(node, type) + } + } + }, + + /** + * Check call `Vue.component` and call callback. + * @param {RuleContext} _context The ESLint rule context object. + * @param { (node: CallExpression) => void } cb Callback function + */ + executeOnCallVueComponent(_context, cb) { + return { + /** @param {Identifier & { parent: MemberExpression & { parent: CallExpression } } } node */ + "CallExpression > MemberExpression > Identifier[name='component']": ( + node + ) => { + const callExpr = node.parent.parent + const callee = callExpr.callee + + if (callee.type === 'MemberExpression') { + const calleeObject = skipTSAsExpression(callee.object) + + if ( + calleeObject.type === 'Identifier' && + // calleeObject.name === 'Vue' && // Any names can be used in Vue.js 3.x. e.g. app.component() + callee.property === node && + callExpr.arguments.length >= 1 + ) { + cb(callExpr) + } + } + } + } + }, + /** + * Return generator with all properties + * @param {ObjectExpression} node Node to check + * @param {Set<GroupName>} groups Name of parent group + * @returns {IterableIterator<ComponentPropertyData>} + */ + *iterateProperties(node, groups) { + for (const item of node.properties) { + if (item.type !== 'Property') { + continue + } + + const name = /** @type {GroupName | null} */ (getStaticPropertyName(item)) + if (!name || !groups.has(name)) continue + + if (item.value.type === 'ArrayExpression') { + yield* this.iterateArrayExpression(item.value, name) + } else if (item.value.type === 'ObjectExpression') { + yield* this.iterateObjectExpression(item.value, name) + } else if (item.value.type === 'FunctionExpression') { + yield* this.iterateFunctionExpression(item.value, name) + } else if (item.value.type === 'ArrowFunctionExpression') { + yield* this.iterateArrowFunctionExpression(item.value, name) + } + } + }, + + /** + * Return generator with all elements inside ArrayExpression + * @param {ArrayExpression} node Node to check + * @param {GroupName} groupName Name of parent group + * @returns {IterableIterator<ComponentArrayPropertyData>} + */ + *iterateArrayExpression(node, groupName) { + for (const item of node.elements) { + if ( + item && + (item.type === 'Literal' || item.type === 'TemplateLiteral') + ) { + const name = getStringLiteralValue(item) + if (name) { + yield { type: 'array', name, groupName, node: item } + } + } + } + }, + + /** + * Return generator with all elements inside ObjectExpression + * @param {ObjectExpression} node Node to check + * @param {GroupName} groupName Name of parent group + * @returns {IterableIterator<ComponentObjectPropertyData>} + */ + *iterateObjectExpression(node, groupName) { + /** @type {Set<Property> | undefined} */ + let usedGetter + for (const item of node.properties) { + if (item.type === 'Property') { + const key = item.key + if ( + key.type === 'Identifier' || + key.type === 'Literal' || + key.type === 'TemplateLiteral' + ) { + const name = getStaticPropertyName(item) + if (name) { + if (item.kind === 'set') { + // find getter pair + if ( + node.properties.some((item2) => { + if (item2.type === 'Property' && item2.kind === 'get') { + if (!usedGetter) { + usedGetter = new Set() + } + if (usedGetter.has(item2)) { + return false + } + const getterName = getStaticPropertyName(item2) + if (getterName === name) { + usedGetter.add(item2) + return true + } + } + return false + }) + ) { + // has getter pair + continue + } + } + yield { + type: 'object', + name, + groupName, + node: key, + property: item + } + } + } + } + } + }, + + /** + * Return generator with all elements inside FunctionExpression + * @param {FunctionExpression} node Node to check + * @param {GroupName} groupName Name of parent group + * @returns {IterableIterator<ComponentObjectPropertyData>} + */ + *iterateFunctionExpression(node, groupName) { + if (node.body.type === 'BlockStatement') { + for (const item of node.body.body) { + if ( + item.type === 'ReturnStatement' && + item.argument && + item.argument.type === 'ObjectExpression' + ) { + yield* this.iterateObjectExpression(item.argument, groupName) + } + } + } + }, + + /** + * Return generator with all elements inside ArrowFunctionExpression + * @param {ArrowFunctionExpression} node Node to check + * @param {GroupName} groupName Name of parent group + * @returns {IterableIterator<ComponentObjectPropertyData>} + */ + *iterateArrowFunctionExpression(node, groupName) { + const body = node.body + if (body.type === 'BlockStatement') { + for (const item of body.body) { + if ( + item.type === 'ReturnStatement' && + item.argument && + item.argument.type === 'ObjectExpression' + ) { + yield* this.iterateObjectExpression(item.argument, groupName) + } + } + } else if (body.type === 'ObjectExpression') { + yield* this.iterateObjectExpression(body, groupName) + } + }, + + /** + * Find all functions which do not always return values + * @param {boolean} treatUndefinedAsUnspecified + * @param { (node: ESNode) => void } cb Callback function + * @returns {RuleListener} + */ + executeOnFunctionsWithoutReturn(treatUndefinedAsUnspecified, cb) { + /** + * @typedef {object} FuncInfo + * @property {FuncInfo} funcInfo + * @property {CodePath} codePath + * @property {boolean} hasReturn + * @property {boolean} hasReturnValue + * @property {ESNode} node + */ + + /** @type {FuncInfo} */ + let funcInfo + + /** @param {CodePathSegment} segment */ + function isReachable(segment) { + return segment.reachable + } + + function isValidReturn() { + if ( + funcInfo.codePath && + funcInfo.codePath.currentSegments.some(isReachable) + ) { + return false + } + return !treatUndefinedAsUnspecified || funcInfo.hasReturnValue + } + + return { + /** + * @param {CodePath} codePath + * @param {ESNode} node + */ + onCodePathStart(codePath, node) { + funcInfo = { + codePath, + funcInfo, + hasReturn: false, + hasReturnValue: false, + node + } + }, + onCodePathEnd() { + funcInfo = funcInfo.funcInfo + }, + /** @param {ReturnStatement} node */ + ReturnStatement(node) { + funcInfo.hasReturn = true + funcInfo.hasReturnValue = Boolean(node.argument) + }, + /** @param {ArrowFunctionExpression} node */ + 'ArrowFunctionExpression:exit'(node) { + if (!isValidReturn() && !node.expression) { + cb(funcInfo.node) + } + }, + 'FunctionExpression:exit'() { + if (!isValidReturn()) { + cb(funcInfo.node) + } + } + } + }, + + /** + * Check whether the component is declared in a single line or not. + * @param {ASTNode} node + * @returns {boolean} + */ + isSingleLine(node) { + return node.loc.start.line === node.loc.end.line + }, + + /** + * Check whether the templateBody of the program has invalid EOF or not. + * @param {Program} node The program node to check. + * @returns {boolean} `true` if it has invalid EOF. + */ + hasInvalidEOF(node) { + const body = node.templateBody + if (body == null || body.errors == null) { + return false + } + return body.errors.some( + (error) => typeof error.code === 'string' && error.code.startsWith('eof-') + ) + }, + + /** + * Get the chaining nodes of MemberExpression. + * + * @param {ESNode} node The node to parse + * @return {[ESNode, ...MemberExpression[]]} The chaining nodes + */ + getMemberChaining(node) { + /** @type {MemberExpression[]} */ + const nodes = [] + let n = skipChainExpression(node) + + while (n.type === 'MemberExpression') { + nodes.push(n) + n = skipChainExpression(n.object) + } + + return [n, ...nodes.reverse()] + }, + /** + * return two string editdistance + * @param {string} a string a to compare + * @param {string} b string b to compare + * @returns {number} + */ + editDistance(a, b) { + if (a === b) { + return 0 + } + const alen = a.length + const blen = b.length + const dp = Array.from({ length: alen + 1 }).map((_) => + Array.from({ length: blen + 1 }).fill(0) + ) + for (let i = 0; i <= alen; i++) { + dp[i][0] = i + } + for (let j = 0; j <= blen; j++) { + dp[0][j] = j + } + for (let i = 1; i <= alen; i++) { + for (let j = 1; j <= blen; j++) { + if (a[i - 1] === b[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + } else { + dp[i][j] = Math.min(dp[i - 1][j], dp[i][j - 1], dp[i - 1][j - 1]) + 1 + } + } + } + return dp[alen][blen] + }, + /** + * Checks whether the given node is Property. + */ + isProperty, + /** + * Checks whether the given node is AssignmentProperty. + */ + isAssignmentProperty, + /** + * Checks whether the given node is VElement. + */ + isVElement, + /** + * Finds the property with the given name from the given ObjectExpression node. + */ + findProperty, + /** + * Finds the assignment property with the given name from the given ObjectPattern node. + */ + findAssignmentProperty, + /** + * Checks if the given node is a property value. + * @param {Property} prop + * @param {Expression} node + */ + isPropertyChain, + /** + * Retrieve `TSAsExpression#expression` value if the given node a `TSAsExpression` node. Otherwise, pass through it. + */ + skipTSAsExpression, + /** + * Retrieve `AssignmentPattern#left` value if the given node a `AssignmentPattern` node. Otherwise, pass through it. + */ + skipDefaultParamValue, + /** + * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it. + */ + skipChainExpression, + + /** + * Check whether the given node is `this` or variable that stores `this`. + * @param {ESNode} node The node to check + * @param {RuleContext} context The rule context to use parser services. + * @returns {boolean} `true` if the given node is `this`. + */ + isThis(node, context) { + if (node.type === 'ThisExpression') { + return true + } + if (node.type !== 'Identifier') { + return false + } + const parent = node.parent + if (parent.type === 'MemberExpression') { + if (parent.property === node) { + return false + } + } else if (parent.type === 'Property') { + if (parent.key === node && !parent.computed) { + return false + } + } + + const variable = findVariable(context.getScope(), node) + + if (variable != null && variable.defs.length === 1) { + const def = variable.defs[0] + if ( + def.type === 'Variable' && + def.parent.kind === 'const' && + def.node.id.type === 'Identifier' + ) { + return Boolean( + def.node && def.node.init && def.node.init.type === 'ThisExpression' + ) + } + } + return false + }, + + /** + * @param {MemberExpression|Identifier} props + * @returns { { kind: 'assignment' | 'update' | 'call' , node: ESNode, pathNodes: MemberExpression[] } | null } + */ + findMutating(props) { + /** @type {MemberExpression[]} */ + const pathNodes = [] + /** @type {MemberExpression | Identifier | ChainExpression} */ + let node = props + let target = node.parent + while (true) { + if (target.type === 'AssignmentExpression') { + if (target.left === node) { + // this.xxx <=|+=|-=> + return { + kind: 'assignment', + node: target, + pathNodes + } + } + } else if (target.type === 'UpdateExpression') { + // this.xxx <++|--> + return { + kind: 'update', + node: target, + pathNodes + } + } else if (target.type === 'CallExpression') { + if (pathNodes.length > 0 && target.callee === node) { + const mem = pathNodes[pathNodes.length - 1] + const callName = getStaticPropertyName(mem) + if ( + callName && + /^push|pop|shift|unshift|reverse|splice|sort|copyWithin|fill$/u.exec( + callName + ) + ) { + // this.xxx.push() + pathNodes.pop() + return { + kind: 'call', + node: target, + pathNodes + } + } + } + } else if (target.type === 'MemberExpression') { + if (target.object === node) { + pathNodes.push(target) + node = target + target = target.parent + continue // loop + } + } else if (target.type === 'ChainExpression') { + node = target + target = target.parent + continue // loop + } + + return null + } + }, + + /** + * Return generator with the all handler nodes defined in the given watcher property. + * @param {Property|Expression} property + * @returns {IterableIterator<Expression>} + */ + iterateWatchHandlerValues, + + /** + * Wraps composition API trace map in both 'vue' and '@vue/composition-api' imports + * @param {import('eslint-utils').TYPES.TraceMap} map + */ + createCompositionApiTraceMap: (map) => ({ + vue: map, + '@vue/composition-api': map + }), + + /** + * Checks whether or not the tokens of two given nodes are same. + * @param {ASTNode} left A node 1 to compare. + * @param {ASTNode} right A node 2 to compare. + * @param {ParserServices.TokenStore | SourceCode} sourceCode The ESLint source code object. + * @returns {boolean} the source code for the given node. + */ + equalTokens(left, right, sourceCode) { + const tokensL = sourceCode.getTokens(left) + const tokensR = sourceCode.getTokens(right) + + if (tokensL.length !== tokensR.length) { + return false + } + for (let i = 0; i < tokensL.length; ++i) { + if ( + tokensL[i].type !== tokensR[i].type || + tokensL[i].value !== tokensR[i].value + ) { + return false + } + } + + return true + } + } + + // ------------------------------------------------------------------------------ + // Standard Helpers + // ------------------------------------------------------------------------------ + + /** + * Checks whether the given value is defined. + * @template T + * @param {T | null | undefined} v + * @returns {v is T} + */ + function isDef(v) { + return v != null + } + + // ------------------------------------------------------------------------------ + // Rule Helpers + // ------------------------------------------------------------------------------ + + /** + * Register the given visitor to parser services. + * If the parser service of `vue-eslint-parser` was not found, + * this generates a warning. + * + * @param {RuleContext} context The rule context to use parser services. + * @param {TemplateListener} templateBodyVisitor The visitor to traverse the template body. + * @param {RuleListener} [scriptVisitor] The visitor to traverse the script. + * @returns {RuleListener} The merged visitor. + */ + function defineTemplateBodyVisitor( + context, + templateBodyVisitor, + scriptVisitor + ) { + if (context.parserServices.defineTemplateBodyVisitor == null) { + const filename = context.getFilename() + if (path.extname(filename) === '.vue') { + context.report({ + loc: { line: 1, column: 0 }, + message: + 'Use the latest vue-eslint-parser. See also https://eslint.vuejs.org/user-guide/#what-is-the-use-the-latest-vue-eslint-parser-error.' + }) + } + return {} + } + return context.parserServices.defineTemplateBodyVisitor( + templateBodyVisitor, + scriptVisitor + ) + } + + /** + * @template T + * @param {T} visitor + * @param {...(TemplateListener | RuleListener | NodeListener)} visitors + * @returns {T} + */ + function compositingVisitors(visitor, ...visitors) { + for (const v of visitors) { + for (const key in v) { + // @ts-expect-error + if (visitor[key]) { + // @ts-expect-error + const o = visitor[key] + // @ts-expect-error + visitor[key] = (...args) => { + o(...args) + // @ts-expect-error + v[key](...args) + } + } else { + // @ts-expect-error + visitor[key] = v[key] + } + } + } + return visitor + } + + // ------------------------------------------------------------------------------ + // AST Helpers + // ------------------------------------------------------------------------------ + + /** + * Finds the property with the given name from the given ObjectExpression node. + * @param {ObjectExpression} node + * @param {string} name + * @param { (p: Property) => boolean } [filter] + * @returns { (Property) | null} + */ + function findProperty(node, name, filter) { + const predicate = filter + ? /** + * @param {Property | SpreadElement} prop + * @returns {prop is Property} + */ + (prop) => + isProperty(prop) && getStaticPropertyName(prop) === name && filter(prop) + : /** + * @param {Property | SpreadElement} prop + * @returns {prop is Property} + */ + (prop) => isProperty(prop) && getStaticPropertyName(prop) === name + return node.properties.find(predicate) || null + } + + /** + * Finds the assignment property with the given name from the given ObjectPattern node. + * @param {ObjectPattern} node + * @param {string} name + * @param { (p: AssignmentProperty) => boolean } [filter] + * @returns { (AssignmentProperty) | null} + */ + function findAssignmentProperty(node, name, filter) { + const predicate = filter + ? /** + * @param {AssignmentProperty | RestElement} prop + * @returns {prop is AssignmentProperty} + */ + (prop) => + isAssignmentProperty(prop) && + getStaticPropertyName(prop) === name && + filter(prop) + : /** + * @param {AssignmentProperty | RestElement} prop + * @returns {prop is AssignmentProperty} + */ + (prop) => + isAssignmentProperty(prop) && getStaticPropertyName(prop) === name + return node.properties.find(predicate) || null + } + + /** + * Checks whether the given node is Property. + * @param {Property | SpreadElement | AssignmentProperty} node + * @returns {node is Property} + */ + function isProperty(node) { + if (node.type !== 'Property') { + return false + } + return !node.parent || node.parent.type === 'ObjectExpression' + } + /** + * Checks whether the given node is AssignmentProperty. + * @param {AssignmentProperty | RestElement} node + * @returns {node is AssignmentProperty} + */ + function isAssignmentProperty(node) { + return node.type === 'Property' + } + /** + * Checks whether the given node is VElement. + * @param {VElement | VExpressionContainer | VText} node + * @returns {node is VElement} + */ + function isVElement(node) { + return node.type === 'VElement' + } + + /** + * Retrieve `TSAsExpression#expression` value if the given node a `TSAsExpression` node. Otherwise, pass through it. + * @template T Node type + * @param {T | TSAsExpression} node The node to address. + * @returns {T} The `TSAsExpression#expression` value if the node is a `TSAsExpression` node. Otherwise, the node. + */ + function skipTSAsExpression(node) { + if (!node) { + return node + } + // @ts-expect-error + if (node.type === 'TSAsExpression') { + // @ts-expect-error + return skipTSAsExpression(node.expression) + } + // @ts-expect-error + return node + } + + /** + * Gets the parent node of the given node. This method returns a value ignoring `X as F`. + * @param {Expression} node + * @returns {ASTNode} + */ + function getParent(node) { + let parent = node.parent + while (parent.type === 'TSAsExpression') { + parent = parent.parent + } + return parent + } + + /** + * Checks if the given node is a property value. + * @param {Property} prop + * @param {Expression} node + */ + function isPropertyChain(prop, node) { + let value = node + while (value.parent.type === 'TSAsExpression') { + value = value.parent + } + return prop === value.parent && prop.value === value + } + + /** + * Retrieve `AssignmentPattern#left` value if the given node a `AssignmentPattern` node. Otherwise, pass through it. + * @template T Node type + * @param {T | AssignmentPattern} node The node to address. + * @return {T} The `AssignmentPattern#left` value if the node is a `AssignmentPattern` node. Otherwise, the node. + */ + function skipDefaultParamValue(node) { + if (!node) { + return node + } + // @ts-expect-error + if (node.type === 'AssignmentPattern') { + // @ts-expect-error + return skipDefaultParamValue(node.left) + } + // @ts-expect-error + return node + } + + /** + * Retrieve `ChainExpression#expression` value if the given node a `ChainExpression` node. Otherwise, pass through it. + * @template T Node type + * @param {T | ChainExpression} node The node to address. + * @returns {T} The `ChainExpression#expression` value if the node is a `ChainExpression` node. Otherwise, the node. + */ + function skipChainExpression(node) { + if (!node) { + return node + } + // @ts-expect-error + if (node.type === 'ChainExpression') { + // @ts-expect-error + return skipChainExpression(node.expression) + } + // @ts-expect-error + return node + } + + /** + * Gets the property name of a given node. + * @param {Property|AssignmentProperty|MethodDefinition|MemberExpression} node - The node to get. + * @return {string|null} The property name if static. Otherwise, null. + */ + function getStaticPropertyName(node) { + if (node.type === 'Property' || node.type === 'MethodDefinition') { + const key = node.key + + if (!node.computed) { + if (key.type === 'Identifier') { + return key.name + } + } + // @ts-expect-error + return getStringLiteralValue(key) + } else if (node.type === 'MemberExpression') { + const property = node.property + if (!node.computed) { + if (property.type === 'Identifier') { + return property.name + } + return null + } + // @ts-expect-error + return getStringLiteralValue(property) + } + return null + } + + /** + * Gets the string of a given node. + * @param {Literal|TemplateLiteral} node - The node to get. + * @param {boolean} [stringOnly] + * @return {string|null} The string if static. Otherwise, null. + */ + function getStringLiteralValue(node, stringOnly) { + if (node.type === 'Literal') { + if (node.value == null) { + if (!stringOnly && node.bigint != null) { + return node.bigint + } + return null + } + if (typeof node.value === 'string') { + return node.value + } + if (!stringOnly) { + return String(node.value) + } + return null + } + if (node.type === 'TemplateLiteral') { + if (node.expressions.length === 0 && node.quasis.length === 1) { + return node.quasis[0].value.cooked + } + } + return null + } + + // ------------------------------------------------------------------------------ + // Vue Helpers + // ------------------------------------------------------------------------------ + + /** + * @param {string} path + */ + function isVueFile(path) { + return path.endsWith('.vue') || path.endsWith('.jsx') + } + + /** + * Check whether the given node is a Vue component based + * on the filename and default export type + * export default {} in .vue || .jsx + * @param {ESNode} node Node to check + * @param {string} path File name with extension + * @returns {boolean} + */ + function isVueComponentFile(node, path) { + return ( + isVueFile(path) && + node.type === 'ExportDefaultDeclaration' && + node.declaration.type === 'ObjectExpression' + ) + } + + /** + * Get the Vue component definition type from given node + * Vue.component('xxx', {}) || component('xxx', {}) + * @param {ObjectExpression} node Node to check + * @returns {'component' | 'mixin' | 'extend' | 'createApp' | 'defineComponent' | null} + */ + function getVueComponentDefinitionType(node) { + const parent = getParent(node) + if (parent.type === 'CallExpression') { + const callee = parent.callee + + if (callee.type === 'MemberExpression') { + const calleeObject = skipTSAsExpression(callee.object) + + if (calleeObject.type === 'Identifier') { + const propName = getStaticPropertyName(callee) + if (calleeObject.name === 'Vue') { + // for Vue.js 2.x + // Vue.component('xxx', {}) || Vue.mixin({}) || Vue.extend('xxx', {}) + const maybeFullVueComponentForVue2 = + propName && isObjectArgument(parent) + + return maybeFullVueComponentForVue2 && + (propName === 'component' || + propName === 'mixin' || + propName === 'extend') + ? propName + : null + } + + // for Vue.js 3.x + // app.component('xxx', {}) || app.mixin({}) + const maybeFullVueComponent = propName && isObjectArgument(parent) + + return maybeFullVueComponent && + (propName === 'component' || propName === 'mixin') + ? propName + : null + } + } + + if (callee.type === 'Identifier') { + if (callee.name === 'component') { + // for Vue.js 2.x + // component('xxx', {}) + const isDestructedVueComponent = isObjectArgument(parent) + return isDestructedVueComponent ? 'component' : null + } + if (callee.name === 'createApp') { + // for Vue.js 3.x + // createApp({}) + const isAppVueComponent = isObjectArgument(parent) + return isAppVueComponent ? 'createApp' : null + } + if (callee.name === 'defineComponent') { + // for Vue.js 3.x + // defineComponent({}) + const isDestructedVueComponent = isObjectArgument(parent) + return isDestructedVueComponent ? 'defineComponent' : null + } + } + } + + return null + + /** @param {CallExpression} node */ + function isObjectArgument(node) { + return ( + node.arguments.length > 0 && + skipTSAsExpression(node.arguments.slice(-1)[0]).type === + 'ObjectExpression' + ) + } + } + + /** + * Check whether given node is new Vue instance + * new Vue({}) + * @param {NewExpression} node Node to check + * @returns {boolean} + */ + function isVueInstance(node) { + const callee = node.callee + return Boolean( + node.type === 'NewExpression' && + callee.type === 'Identifier' && + callee.name === 'Vue' && + node.arguments.length && + skipTSAsExpression(node.arguments[0]).type === 'ObjectExpression' + ) + } + + /** + * If the given object is a Vue component or instance, returns the Vue definition type. + * @param {RuleContext} context The ESLint rule context object. + * @param {ObjectExpression} node Node to check + * @returns { VueObjectType | null } The Vue definition type. + */ + function getVueObjectType(context, node) { + if (node.type !== 'ObjectExpression') { + return null + } + const parent = getParent(node) + if (parent.type === 'ExportDefaultDeclaration') { + // export default {} in .vue || .jsx + const filePath = context.getFilename() + if ( + isVueComponentFile(parent, filePath) && + skipTSAsExpression(parent.declaration) === node + ) { + return 'export' + } + } else if (parent.type === 'CallExpression') { + // Vue.component('xxx', {}) || component('xxx', {}) + if ( + getVueComponentDefinitionType(node) != null && + skipTSAsExpression(parent.arguments.slice(-1)[0]) === node + ) { + return 'definition' + } + } else if (parent.type === 'NewExpression') { + // new Vue({}) + if ( + isVueInstance(parent) && + skipTSAsExpression(parent.arguments[0]) === node + ) { + return 'instance' + } + } + if ( + getComponentComments(context).some( + (el) => el.loc.end.line === node.loc.start.line - 1 + ) + ) { + return 'mark' + } + return null + } + + /** + * Gets the component comments of a given context. + * @param {RuleContext} context The ESLint rule context object. + * @return {Token[]} The the component comments. + */ + function getComponentComments(context) { + let tokens = componentComments.get(context) + if (tokens) { + return tokens + } + const sourceCode = context.getSourceCode() + tokens = sourceCode + .getAllComments() + .filter((comment) => /@vue\/component/g.test(comment.value)) + componentComments.set(context, tokens) + return tokens + } + + /** + * Return generator with the all handler nodes defined in the given watcher property. + * @param {Property|Expression} property + * @returns {IterableIterator<Expression>} + */ + function* iterateWatchHandlerValues(property) { + const value = property.type === 'Property' ? property.value : property + if (value.type === 'ObjectExpression') { + const handler = findProperty(value, 'handler') + if (handler) { + yield handler.value + } + } else if (value.type === 'ArrayExpression') { + for (const element of value.elements.filter(isDef)) { + if (element.type !== 'SpreadElement') { + yield* iterateWatchHandlerValues(element) + } + } + } else { + yield value + } + } + \ No newline at end of file diff --git a/src/eslint-plugins/utils/inline-non-void-elements.json b/src/eslint-plugins/utils/inline-non-void-elements.json new file mode 100644 index 00000000..b3dda839 --- /dev/null +++ b/src/eslint-plugins/utils/inline-non-void-elements.json @@ -0,0 +1,40 @@ +[ + "a", + "abbr", + "audio", + "b", + "bdi", + "bdo", + "canvas", + "cite", + "code", + "data", + "del", + "dfn", + "em", + "i", + "iframe", + "ins", + "kbd", + "label", + "map", + "mark", + "noscript", + "object", + "output", + "picture", + "q", + "ruby", + "s", + "samp", + "small", + "span", + "strong", + "sub", + "sup", + "svg", + "time", + "u", + "var", + "video" +] diff --git a/src/eslint-plugins/utils/js-reserved.json b/src/eslint-plugins/utils/js-reserved.json new file mode 100644 index 00000000..9b3eb11c --- /dev/null +++ b/src/eslint-plugins/utils/js-reserved.json @@ -0,0 +1,18 @@ +[ + "abstract", "arguments", "await", "boolean", + "break", "byte", "case", "catch", + "char", "class", "const", "continue", + "debugger", "default", "delete", "do", + "double", "else", "enum", "eval", + "export", "extends", "false", "final", + "finally", "float", "for", "function", + "goto", "if", "implements", "import", + "in", "instanceof", "int", "interface", + "let", "long", "native", "new", + "null", "package", "private", "protected", + "public", "return", "short", "static", + "super", "switch", "synchronized", "this", + "throw", "throws", "transient", "true", + "try", "typeof", "var", "void", + "volatile", "while", "with", "yield" +] diff --git a/src/eslint-plugins/utils/key-aliases.json b/src/eslint-plugins/utils/key-aliases.json new file mode 100644 index 00000000..49de3b3d --- /dev/null +++ b/src/eslint-plugins/utils/key-aliases.json @@ -0,0 +1,68 @@ +[ + "unidentified", "alt", "alt-graph", "caps-lock", "control", "fn", "fn-lock", + "meta", "num-lock", "scroll-lock", "shift", "symbol", "symbol-lock", "hyper", + "super", "enter", "tab", "arrow-down", "arrow-left", "arrow-right", + "arrow-up", "end", "home", "page-down", "page-up", "backspace", "clear", + "copy", "cr-sel", "cut", "delete", "erase-eof", "ex-sel", "insert", "paste", + "redo", "undo", "accept", "again", "attn", "cancel", "context-menu", "escape", + "execute", "find", "help", "pause", "select", "zoom-in", "zoom-out", + "brightness-down", "brightness-up", "eject", "log-off", "power", + "print-screen", "hibernate", "standby", "wake-up", "all-candidates", + "alphanumeric", "code-input", "compose", "convert", "dead", "final-mode", + "group-first", "group-last", "group-next", "group-previous", "mode-change", + "next-candidate", "non-convert", "previous-candidate", "process", + "single-candidate", "hangul-mode", "hanja-mode", "junja-mode", "eisu", + "hankaku", "hiragana", "hiragana-katakana", "kana-mode", "kanji-mode", + "katakana", "romaji", "zenkaku", "zenkaku-hankaku", "f1", "f2", "f3", "f4", + "f5", "f6", "f7", "f8", "f9", "f10", "f11", "f12", "soft1", "soft2", "soft3", + "soft4", "channel-down", "channel-up", "close", "mail-forward", "mail-reply", + "mail-send", "media-close", "media-fast-forward", "media-pause", + "media-play-pause", "media-record", "media-rewind", "media-stop", + "media-track-next", "media-track-previous", "new", "open", "print", "save", + "spell-check", "key11", "key12", "audio-balance-left", "audio-balance-right", + "audio-bass-boost-down", "audio-bass-boost-toggle", "audio-bass-boost-up", + "audio-fader-front", "audio-fader-rear", "audio-surround-mode-next", + "audio-treble-down", "audio-treble-up", "audio-volume-down", + "audio-volume-up", "audio-volume-mute", "microphone-toggle", + "microphone-volume-down", "microphone-volume-up", "microphone-volume-mute", + "speech-correction-list", "speech-input-toggle", "launch-application1", + "launch-application2", "launch-calendar", "launch-contacts", "launch-mail", + "launch-media-player", "launch-music-player", "launch-phone", + "launch-screen-saver", "launch-spreadsheet", "launch-web-browser", + "launch-web-cam", "launch-word-processor", "browser-back", + "browser-favorites", "browser-forward", "browser-home", "browser-refresh", + "browser-search", "browser-stop", "app-switch", "call", "camera", + "camera-focus", "end-call", "go-back", "go-home", "headset-hook", + "last-number-redial", "notification", "manner-mode", "voice-dial", "t-v", + "t-v3-d-mode", "t-v-antenna-cable", "t-v-audio-description", + "t-v-audio-description-mix-down", "t-v-audio-description-mix-up", + "t-v-contents-menu", "t-v-data-service", "t-v-input", "t-v-input-component1", + "t-v-input-component2", "t-v-input-composite1", "t-v-input-composite2", + "t-v-input-h-d-m-i1", "t-v-input-h-d-m-i2", "t-v-input-h-d-m-i3", + "t-v-input-h-d-m-i4", "t-v-input-v-g-a1", "t-v-media-context", "t-v-network", + "t-v-number-entry", "t-v-power", "t-v-radio-service", "t-v-satellite", + "t-v-satellite-b-s", "t-v-satellite-c-s", "t-v-satellite-toggle", + "t-v-terrestrial-analog", "t-v-terrestrial-digital", "t-v-timer", + "a-v-r-input", "a-v-r-power", "color-f0-red", "color-f1-green", + "color-f2-yellow", "color-f3-blue", "color-f4-grey", "color-f5-brown", + "closed-caption-toggle", "dimmer", "display-swap", "d-v-r", "exit", + "favorite-clear0", "favorite-clear1", "favorite-clear2", "favorite-clear3", + "favorite-recall0", "favorite-recall1", "favorite-recall2", + "favorite-recall3", "favorite-store0", "favorite-store1", "favorite-store2", + "favorite-store3", "guide", "guide-next-day", "guide-previous-day", "info", + "instant-replay", "link", "list-program", "live-content", "lock", + "media-apps", "media-last", "media-skip-backward", "media-skip-forward", + "media-step-backward", "media-step-forward", "media-top-menu", "navigate-in", + "navigate-next", "navigate-out", "navigate-previous", "next-favorite-channel", + "next-user-profile", "on-demand", "pairing", "pin-p-down", "pin-p-move", + "pin-p-toggle", "pin-p-up", "play-speed-down", "play-speed-reset", + "play-speed-up", "random-toggle", "rc-low-battery", "record-speed-next", + "rf-bypass", "scan-channels-toggle", "screen-mode-next", "settings", + "split-screen-toggle", "s-t-b-input", "s-t-b-power", "subtitle", "teletext", + "video-mode-next", "wink", "zoom-toggle", "audio-volume-down", + "audio-volume-up", "audio-volume-mute", "browser-back", "browser-forward", + "channel-down", "channel-up", "context-menu", "eject", "end", "enter", "home", + "media-fast-forward", "media-play", "media-play-pause", "media-record", + "media-rewind", "media-stop", "media-next-track", "media-pause", + "media-previous-track", "power", "unidentified" +] diff --git a/src/eslint-plugins/utils/keycode-to-key.ts b/src/eslint-plugins/utils/keycode-to-key.ts new file mode 100644 index 00000000..9adbe049 --- /dev/null +++ b/src/eslint-plugins/utils/keycode-to-key.ts @@ -0,0 +1,98 @@ +// https://developer.mozilla.org/en-US/docs/Web/API/KeyboardEvent/key/Key_Values +export = { + 8: "backspace", + 9: "tab", + 13: "enter", + 16: "shift", + 17: "ctrl", + 18: "alt", + 19: "pause", // windows + 20: "caps-lock", + 27: "escape", + 32: "space", // Vue.js specially key name. + 33: "page-up", + 34: "page-down", + 35: "end", + 36: "home", + 37: "arrow-left", + 38: "arrow-up", + 39: "arrow-right", + 40: "arrow-down", + 45: "insert", // windows + 46: "delete", + + // If mistakenly use it in Vue.js 2.x, it will be irreversibly broken. Therefore, it will not be autofix. + // '48': '0', + // '49': '1', + // '50': '2', + // '51': '3', + // '52': '4', + // '53': '5', + // '54': '6', + // '55': '7', + // '56': '8', + // '57': '9', + + 65: "a", + 66: "b", + 67: "c", + 68: "d", + 69: "e", + 70: "f", + 71: "g", + 72: "h", + 73: "i", + 74: "j", + 75: "k", + 76: "l", + 77: "m", + 78: "n", + 79: "o", + 80: "p", + 81: "q", + 82: "r", + 83: "s", + 84: "t", + 85: "u", + 86: "v", + 87: "w", + 88: "x", + 89: "y", + 90: "z", + + // The key value may change depending on the OS. + // '91': 'meta' ,// Win: 'os'? + // '92': 'meta', // Win: 'meta' Mac: ? + // '93': 'meta', // Win: 'context-menu' Mac: 'meta' + + // Cannot determine numpad with key. + // '96': 'numpad-0', + // '97': 'numpad-1', + // '98': 'numpad-2', + // '99': 'numpad-3', + // '100': 'numpad-4', + // '101': 'numpad-5', + // '102': 'numpad-6', + // '103': 'numpad-7', + // '104': 'numpad-8', + // '105': 'numpad-9', + // '106': 'multiply', + // '107': 'add', + // '109': 'subtract', + // '110': 'decimal', + // '111': 'divide', + 112: "f1", + 113: "f2", + 114: "f3", + 115: "f4", + 116: "f5", + 117: "f6", + 118: "f7", + 119: "f8", + 120: "f9", + 121: "f10", + 122: "f11", + 123: "f12", + 144: "num-lock", + 145: "scroll-lock", +} diff --git a/src/eslint-plugins/utils/regexp.ts b/src/eslint-plugins/utils/regexp.ts new file mode 100644 index 00000000..096f135c --- /dev/null +++ b/src/eslint-plugins/utils/regexp.ts @@ -0,0 +1,36 @@ +const RE_REGEXP_CHAR = /[\\^$.*+?()[\]{}|]/gu +// eslint-disable-next-line require-unicode-regexp +const RE_HAS_REGEXP_CHAR = new RegExp(RE_REGEXP_CHAR.source) + +const RE_REGEXP_STR = /^\/(.+)\/(.*)$/u + +/** + * Escapes the `RegExp` special characters "^", "$", "\", ".", "*", "+", + * "?", "(", ")", "[", "]", "{", "}", and "|" in `string`. + */ +export function escape(string: string) { + return string && RE_HAS_REGEXP_CHAR.test(string) + ? string.replace(RE_REGEXP_CHAR, "\\$&") + : string +} + +/** + * Convert a string to the `RegExp`. + * Normal strings (e.g. `"foo"`) is converted to `/^foo$/` of `RegExp`. + * Strings like `"/^foo/i"` are converted to `/^foo/i` of `RegExp`. + */ +export function toRegExp(string: string) { + const parts = RE_REGEXP_STR.exec(string) + if (parts) { + return new RegExp(parts[1], parts[2]) + } + // eslint-disable-next-line require-unicode-regexp + return new RegExp(`^${escape(string)}$`) +} + +/** + * Checks whether given string is regexp string + */ +export function isRegExp(string: string) { + return Boolean(RE_REGEXP_STR.exec(string)) +} diff --git a/src/eslint-plugins/utils/svg-elements.json b/src/eslint-plugins/utils/svg-elements.json new file mode 100644 index 00000000..aaee2e6f --- /dev/null +++ b/src/eslint-plugins/utils/svg-elements.json @@ -0,0 +1 @@ +["a","animate","animateMotion","animateTransform","audio","canvas","circle","clipPath","defs","desc","discard","ellipse","feBlend","feColorMatrix","feComponentTransfer","feComposite","feConvolveMatrix","feDiffuseLighting","feDisplacementMap","feDistantLight","feDropShadow","feFlood","feFuncA","feFuncB","feFuncG","feFuncR","feGaussianBlur","feImage","feMerge","feMergeNode","feMorphology","feOffset","fePointLight","feSpecularLighting","feSpotLight","feTile","feTurbulence","filter","foreignObject","g","iframe","image","line","linearGradient","marker","mask","metadata","mpath","path","pattern","polygon","polyline","radialGradient","rect","script","set","stop","style","svg","switch","symbol","text","textPath","title","tspan","unknown","use","video","view"] diff --git a/src/eslint-plugins/utils/void-elements.json b/src/eslint-plugins/utils/void-elements.json new file mode 100644 index 00000000..b737cc68 --- /dev/null +++ b/src/eslint-plugins/utils/void-elements.json @@ -0,0 +1 @@ +["area","base","br","col","embed","hr","img","input","keygen","link","menuitem","meta","param","source","track","wbr"] diff --git a/src/eslint-plugins/utils/vue-component-options.json b/src/eslint-plugins/utils/vue-component-options.json new file mode 100644 index 00000000..1dcce9f5 --- /dev/null +++ b/src/eslint-plugins/utils/vue-component-options.json @@ -0,0 +1,54 @@ +{ + "nuxt": ["asyncData", "fetch", "head", "key", "layout", "loading", "middleware", "scrollToTop", "transition", "validate", "watchQuery"], + "vue-router": [ + "beforeRouteEnter", + "beforeRouteUpdate", + "beforeRouteLeave" + ], + "vue": [ + "data", + "props", + "propsData", + "computed", + "methods", + "watch", + "el", + "template", + "render", + "renderError", + "staticRenderFns", + "beforeCreate", + "created", + "beforeDestroy", + "destroyed", + "beforeMount", + "mounted", + "beforeUpdate", + "updated", + "activated", + "deactivated", + "errorCaptured", + "serverPrefetch", + "directives", + "components", + "transitions", + "filters", + "provide", + "inject", + "model", + "parent", + "mixins", + "name", + "extends", + "delimiters", + "comments", + "inheritAttrs", + + "setup", + "emits", + "beforeUnmount", + "unmounted", + "renderTracked", + "renderTriggered" + ] +} diff --git a/src/eslint-plugins/utils/vue-reserved.json b/src/eslint-plugins/utils/vue-reserved.json new file mode 100644 index 00000000..03bcdcba --- /dev/null +++ b/src/eslint-plugins/utils/vue-reserved.json @@ -0,0 +1,4 @@ +[ + "$data", "$props", "$el", "$options", "$parent", "$root", "$children", "$slots", "$scopedSlots", "$refs", "$isServer", "$attrs", "$listeners", + "$watch", "$set", "$delete", "$on", "$once", "$off", "$emit", "$mount", "$forceUpdate", "$nextTick", "$destroy" +] diff --git a/src/index.ts b/src/index.ts index 92ff7408..398bef8a 100644 --- a/src/index.ts +++ b/src/index.ts @@ -5,6 +5,7 @@ */ import * as path from "path" import * as AST from "./ast" +import * as ESLintPlugins from "./eslint-plugins" import { LocationCalculator } from "./common/location-calculator" import { HTMLParser, HTMLTokenizer } from "./html" import { parseScript, parseScriptElement } from "./script" @@ -149,3 +150,4 @@ export function parse(code: string, options: any): AST.ESLintProgram { } export { AST } +export { ESLintPlugins } \ No newline at end of file diff --git a/typings/eslint-utils/index.d.ts b/typings/eslint-utils/index.d.ts new file mode 100644 index 00000000..f79d5a2b --- /dev/null +++ b/typings/eslint-utils/index.d.ts @@ -0,0 +1,81 @@ +import * as VAST from '../../src/eslint-plugins/types/ast' +import { Token, Comment } from '../../src/eslint-plugins/types/node' +import { ParserServices } from '../../src/eslint-plugins/types/parser-services' + +import eslint from 'eslint' + +export function findVariable( + initialScope: eslint.Scope.Scope, + nameOrNode: VAST.Identifier | string +): eslint.Scope.Variable + +export function getStaticValue( + node: VAST.ESNode, + initialScope?: eslint.Scope.Scope +): { value: any } | null + +export function isParenthesized( + num: number, + node: VAST.ESNode, + sourceCode: eslint.SourceCode | ParserServices.TokenStore +): boolean +export function isParenthesized( + node: VAST.ESNode, + sourceCode: eslint.SourceCode | ParserServices.TokenStore +): boolean + +export namespace TYPES { + type TraceKind = { + [ReferenceTracker.READ]?: boolean + [ReferenceTracker.CALL]?: boolean + [ReferenceTracker.CONSTRUCT]?: boolean + [ReferenceTracker.ESM]?: boolean + } + type TraceMap = { + [key: string]: TraceKind & TraceMap + } +} + +export class ReferenceTracker { + constructor( + globalScope: eslint.Scope.Scope, + options?: { + mode?: 'legacy' | 'strict' + globalObjectNames?: ('global' | 'globalThis' | 'self' | 'window')[] + } + ) + + iterateGlobalReferences( + traceMap: TYPES.TraceMap + ): IterableIterator<{ + node: VAST.ESNode + path: string[] + type: symbol + info: any + }> + iterateCjsReferences( + traceMap: TYPES.TraceMap + ): IterableIterator<{ + node: VAST.ESNode + path: string[] + type: symbol + info: any + }> + iterateEsmReferences( + traceMap: TYPES.TraceMap + ): IterableIterator<{ + node: VAST.ESNode + path: string[] + type: symbol + info: any + }> +} + +export namespace ReferenceTracker { + const READ: unique symbol + const CALL: unique symbol + const CONSTRUCT: unique symbol + const ESM: unique symbol +} + +export function isCommentToken(token: Token): token is Comment diff --git a/typings/eslint/index.d.ts b/typings/eslint/index.d.ts new file mode 100644 index 00000000..5d2f87c0 --- /dev/null +++ b/typings/eslint/index.d.ts @@ -0,0 +1,431 @@ +import { + Rule as ESLintRule, + RuleTester as ESLintRuleTester, + Linter as ESLintLinter +} from '../../node_modules/@types/eslint' +import * as VAST from '../../src/eslint-plugins/types/ast' +import * as VNODE from '../../src/eslint-plugins/types/node' +import * as parserServices from '../../src/eslint-plugins/types/parser-services' + +export namespace AST { + type Token = VNODE.Token + type Range = VNODE.Range + type SourceLocation = VNODE.SourceLocation + type Program = VAST.Program +} +export namespace Scope { + interface ScopeManager { + scopes: Scope[] + globalScope: Scope | null + acquire(node: VAST.ESNode | VAST.Program, inner?: boolean): Scope | null + getDeclaredVariables(node: VAST.ESNode): Variable[] + } + interface Scope { + type: + | 'block' + | 'catch' + | 'class' + | 'for' + | 'function' + | 'function-expression-name' + | 'global' + | 'module' + | 'switch' + | 'with' + | 'TDZ' + isStrict: boolean + upper: Scope | null + childScopes: Scope[] + variableScope: Scope + block: VAST.ESNode + variables: Variable[] + set: Map<string, Variable> + references: Reference[] + through: Reference[] + functionExpressionScope: boolean + } + interface Variable { + name: string + identifiers: VAST.Identifier[] + references: Reference[] + defs: Definition[] + + writeable?: boolean | undefined + eslintExplicitGlobal?: boolean | undefined + eslintExplicitGlobalComments?: Comment[] | undefined + eslintImplicitGlobalSetting?: 'readonly' | 'writable' | undefined + } + interface Reference { + identifier: VAST.Identifier + from: Scope + resolved: Variable | null + writeExpr: VAST.ESNode | null + init: boolean + isWrite(): boolean + isRead(): boolean + isWriteOnly(): boolean + isReadOnly(): boolean + isReadWrite(): boolean + } + type DefinitionType = + | { type: 'CatchClause'; node: VAST.CatchClause; parent: null } + | { + type: 'ClassName' + node: VAST.ClassDeclaration | VAST.ClassExpression + parent: null + } + | { + type: 'FunctionName' + node: VAST.FunctionDeclaration | VAST.FunctionExpression + parent: null + } + | { type: 'ImplicitGlobalVariable'; node: VAST.Program; parent: null } + | { + type: 'ImportBinding' + node: + | VAST.ImportSpecifier + | VAST.ImportDefaultSpecifier + | VAST.ImportNamespaceSpecifier + parent: VAST.ImportDeclaration + } + | { + type: 'Parameter' + node: + | VAST.FunctionDeclaration + | VAST.FunctionExpression + | VAST.ArrowFunctionExpression + parent: null + } + | { type: 'TDZ'; node: any; parent: null } + | { + type: 'Variable' + node: VAST.VariableDeclarator + parent: VAST.VariableDeclaration + } + type Definition = DefinitionType & { name: VAST.Identifier } +} + +export class SourceCode /*extends ESLintSourceCode*/ { + text: string + ast: AST.Program + lines: string[] + hasBOM: boolean + parserServices: SourceCode.ParserServices + scopeManager: Scope.ScopeManager + visitorKeys: SourceCode.VisitorKeys + + static splitLines(text: string): string[] + + getText( + node?: VNODE.HasLocation, + beforeCount?: number, + afterCount?: number + ): string + getLines(): string[] + getAllComments(): VNODE.Comment[] + getComments( + node: VAST.ESNode + ): { leading: VNODE.Comment[]; trailing: VNODE.Comment[] } + getJSDocComment(node: VAST.ESNode): AST.Token | null + getNodeByRangeIndex(index: number): VAST.ESNode | VAST.JSXNode + isSpaceBetweenTokens(first: AST.Token, second: AST.Token): boolean + getLocFromIndex(index: number): VNODE.Position + getIndexFromLoc(location: VNODE.Position): number + + getTokenByRangeStart( + offset: number, + options?: { includeComments?: boolean } + ): AST.Token | null + getFirstToken(node: VNODE.HasLocation): AST.Token + getFirstToken(node: VNODE.HasLocation, options: number): AST.Token + getFirstToken( + node: VNODE.HasLocation, + options: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getFirstTokens( + node: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getLastToken(node: VNODE.HasLocation): AST.Token + getLastToken(node: VNODE.HasLocation, options: number): AST.Token + getLastToken( + node: VNODE.HasLocation, + options: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getLastTokens( + node: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getTokenBefore(node: VNODE.HasLocation): AST.Token + getTokenBefore(node: VNODE.HasLocation, options: number): AST.Token + getTokenBefore( + node: VNODE.HasLocation, + options: { includeComments: boolean } + ): AST.Token + getTokenBefore( + node: VNODE.HasLocation, + options?: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getTokensBefore( + node: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getTokenAfter(node: VNODE.HasLocation): AST.Token + getTokenAfter(node: VNODE.HasLocation, options: number): AST.Token + getTokenAfter( + node: VNODE.HasLocation, + options: { includeComments: boolean } + ): AST.Token + getTokenAfter( + node: VNODE.HasLocation, + options: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getTokensAfter( + node: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getFirstTokenBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getFirstTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getLastTokenBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: SourceCode.CursorWithSkipOptions + ): AST.Token | null + getLastTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + options?: SourceCode.CursorWithCountOptions + ): AST.Token[] + getTokensBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation, + padding?: + | number + | SourceCode.FilterPredicate + | SourceCode.CursorWithCountOptions + ): AST.Token[] + getTokens( + node: VNODE.HasLocation, + beforeCount?: number, + afterCount?: number + ): AST.Token[] + getTokens( + node: VNODE.HasLocation, + options: SourceCode.FilterPredicate | SourceCode.CursorWithCountOptions + ): AST.Token[] + commentsExistBetween( + left: VNODE.HasLocation, + right: VNODE.HasLocation + ): boolean + getCommentsBefore(nodeOrToken: VNODE.HasLocation): VNODE.Comment[] + getCommentsAfter(nodeOrToken: VNODE.HasLocation): VNODE.Comment[] + getCommentsInside(node: VNODE.HasLocation): VNODE.Comment[] +} +export namespace SourceCode { + interface Config { + text: string + ast: AST.Program + parserServices?: ParserServices + scopeManager?: Scope.ScopeManager + visitorKeys?: VisitorKeys + } + + type ParserServices = parserServices.ParserServices + + interface VisitorKeys { + [nodeType: string]: string[] + } + + type FilterPredicate = (tokenOrComment: AST.Token) => boolean + + type CursorWithSkipOptions = + | number + | FilterPredicate + | { + includeComments?: boolean + filter?: FilterPredicate + skip?: number + } + + type CursorWithCountOptions = + | number + | FilterPredicate + | { + includeComments?: boolean + filter?: FilterPredicate + count?: number + } +} + +export namespace Rule { + interface RuleModule /*extends ESLintRule.RuleModule*/ { + meta: RuleMetaData + create(context: RuleContext): Rule.RuleListener + } + + type NodeTypes = VAST.ESNode['type'] + + type NodeListenerBase = { + [T in keyof VAST.NodeListenerMap]?: (node: VAST.NodeListenerMap[T]) => void + } + interface NodeListener extends NodeListenerBase { + [key: string]: ((node: VAST.ParamNode) => void) | undefined + } + + interface RuleListener extends NodeListenerBase { + onCodePathStart?(codePath: CodePath, node: VAST.ParamNode): void + onCodePathEnd?(codePath: CodePath, node: VAST.ParamNode): void + onCodePathSegmentStart?( + segment: CodePathSegment, + node: VAST.ParamNode + ): void + onCodePathSegmentEnd?(segment: CodePathSegment, node: VAST.ParamNode): void + onCodePathSegmentLoop?( + fromSegment: CodePathSegment, + toSegment: CodePathSegment, + node: VAST.ParamNode + ): void + [key: string]: + | ((codePath: CodePath, node: VAST.ParamNode) => void) + | ((segment: CodePathSegment, node: VAST.ParamNode) => void) + | (( + fromSegment: CodePathSegment, + toSegment: CodePathSegment, + node: VAST.ParamNode + ) => void) + | ((node: VAST.ParamNode) => void) + | undefined + } + interface CodePath extends ESLintRule.CodePath {} + interface CodePathSegment extends ESLintRule.CodePathSegment {} + + interface RuleMetaData extends ESLintRule.RuleMetaData { + docs: Required<ESLintRule.RuleMetaData>['docs'] + } + + interface RuleContext { + id: string + options: ESLintRule.RuleContext['options'] + settings: { [name: string]: any } + parserPath: string + parserOptions: any + parserServices: parserServices.ParserServices + + getAncestors(): VAST.ESNode[] + + getDeclaredVariables(node: VAST.ESNode): Scope.Variable[] + getFilename(): string + getScope(): Scope.Scope + getSourceCode(): SourceCode + markVariableAsUsed(name: string): boolean + report(descriptor: ReportDescriptor): void + + // eslint@6 does not have this method. + getCwd?: () => string + } + + type ReportDescriptor = + | ReportDescriptor1 + | ReportDescriptor2 + | ReportDescriptor3 + | ReportDescriptor4 + + type SuggestionReportDescriptor = + | SuggestionReportDescriptor1 + | SuggestionReportDescriptor2 + + interface RuleFixer { + insertTextAfter(nodeOrToken: VNODE.HasLocation, text: string): Fix + insertTextAfterRange(range: AST.Range, text: string): Fix + insertTextBefore(nodeOrToken: VNODE.HasLocation, text: string): Fix + insertTextBeforeRange(range: AST.Range, text: string): Fix + remove(nodeOrToken: VNODE.HasLocation): Fix + removeRange(range: AST.Range): Fix + replaceText(nodeOrToken: VNODE.HasLocation, text: string): Fix + replaceTextRange(range: AST.Range, text: string): Fix + } + + interface Fix { + range: AST.Range + text: string + } +} + +export class RuleTester extends ESLintRuleTester {} +export class Linter { + getRules(): Map<string, Rule.RuleModule> +} + +export namespace Linter { + type LintMessage = ESLintLinter.LintMessage + type LintOptions = ESLintLinter.LintOptions +} + +interface ReportDescriptorOptionsBase { + data?: { + [key: string]: string | number + } + fix?: + | null + | (( + fixer: Rule.RuleFixer + ) => null | Rule.Fix | IterableIterator<Rule.Fix> | Rule.Fix[]) +} + +interface SuggestionReportDescriptor1 extends ReportDescriptorOptionsBase { + desc: string +} + +interface SuggestionReportDescriptor2 extends ReportDescriptorOptionsBase { + messageId: string +} +interface ReportDescriptorOptions extends ReportDescriptorOptionsBase { + suggest?: Rule.SuggestionReportDescriptor[] | null +} + +interface ReportSourceLocation1 { + start: VNODE.Position + end: VNODE.Position + line?: undefined + column?: undefined +} + +interface ReportSourceLocation2 extends VNODE.Position { + start?: undefined + end?: undefined +} + +type ReportSourceLocation = ReportSourceLocation1 | ReportSourceLocation2 + +interface ReportDescriptor1 extends ReportDescriptorOptions { + message: string + messageId?: string + node: VNODE.HasLocation + loc?: ReportSourceLocation +} +interface ReportDescriptor2 extends ReportDescriptorOptions { + message: string + messageId?: string + node?: VNODE.HasLocation + loc: ReportSourceLocation +} +interface ReportDescriptor3 extends ReportDescriptorOptions { + message?: string + messageId: string + node: VNODE.HasLocation + loc?: ReportSourceLocation +} +interface ReportDescriptor4 extends ReportDescriptorOptions { + message?: string + messageId: string + node?: VNODE.HasLocation + loc: ReportSourceLocation +} diff --git a/typings/eslint/lib/rules/accessor-pairs.d.ts b/typings/eslint/lib/rules/accessor-pairs.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/accessor-pairs.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/array-bracket-newline.d.ts b/typings/eslint/lib/rules/array-bracket-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/array-bracket-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/array-bracket-spacing.d.ts b/typings/eslint/lib/rules/array-bracket-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/array-bracket-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/array-callback-return.d.ts b/typings/eslint/lib/rules/array-callback-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/array-callback-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/array-element-newline.d.ts b/typings/eslint/lib/rules/array-element-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/array-element-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/arrow-body-style.d.ts b/typings/eslint/lib/rules/arrow-body-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/arrow-body-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/arrow-parens.d.ts b/typings/eslint/lib/rules/arrow-parens.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/arrow-parens.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/arrow-spacing.d.ts b/typings/eslint/lib/rules/arrow-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/arrow-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/block-scoped-var.d.ts b/typings/eslint/lib/rules/block-scoped-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/block-scoped-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/block-spacing.d.ts b/typings/eslint/lib/rules/block-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/block-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/brace-style.d.ts b/typings/eslint/lib/rules/brace-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/brace-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/callback-return.d.ts b/typings/eslint/lib/rules/callback-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/callback-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/camelcase.d.ts b/typings/eslint/lib/rules/camelcase.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/camelcase.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/capitalized-comments.d.ts b/typings/eslint/lib/rules/capitalized-comments.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/capitalized-comments.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/class-methods-use-this.d.ts b/typings/eslint/lib/rules/class-methods-use-this.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/class-methods-use-this.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/comma-dangle.d.ts b/typings/eslint/lib/rules/comma-dangle.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/comma-dangle.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/comma-spacing.d.ts b/typings/eslint/lib/rules/comma-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/comma-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/comma-style.d.ts b/typings/eslint/lib/rules/comma-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/comma-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/complexity.d.ts b/typings/eslint/lib/rules/complexity.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/complexity.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/computed-property-spacing.d.ts b/typings/eslint/lib/rules/computed-property-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/computed-property-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/consistent-return.d.ts b/typings/eslint/lib/rules/consistent-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/consistent-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/consistent-this.d.ts b/typings/eslint/lib/rules/consistent-this.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/consistent-this.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/constructor-super.d.ts b/typings/eslint/lib/rules/constructor-super.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/constructor-super.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/curly.d.ts b/typings/eslint/lib/rules/curly.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/curly.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/default-case-last.d.ts b/typings/eslint/lib/rules/default-case-last.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/default-case-last.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/default-case.d.ts b/typings/eslint/lib/rules/default-case.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/default-case.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/default-param-last.d.ts b/typings/eslint/lib/rules/default-param-last.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/default-param-last.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/dot-location.d.ts b/typings/eslint/lib/rules/dot-location.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/dot-location.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/dot-notation.d.ts b/typings/eslint/lib/rules/dot-notation.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/dot-notation.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/eol-last.d.ts b/typings/eslint/lib/rules/eol-last.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/eol-last.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/eqeqeq.d.ts b/typings/eslint/lib/rules/eqeqeq.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/eqeqeq.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/for-direction.d.ts b/typings/eslint/lib/rules/for-direction.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/for-direction.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/func-call-spacing.d.ts b/typings/eslint/lib/rules/func-call-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/func-call-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/func-name-matching.d.ts b/typings/eslint/lib/rules/func-name-matching.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/func-name-matching.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/func-names.d.ts b/typings/eslint/lib/rules/func-names.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/func-names.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/func-style.d.ts b/typings/eslint/lib/rules/func-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/func-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/function-call-argument-newline.d.ts b/typings/eslint/lib/rules/function-call-argument-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/function-call-argument-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/function-paren-newline.d.ts b/typings/eslint/lib/rules/function-paren-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/function-paren-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/generator-star-spacing.d.ts b/typings/eslint/lib/rules/generator-star-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/generator-star-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/getter-return.d.ts b/typings/eslint/lib/rules/getter-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/getter-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/global-require.d.ts b/typings/eslint/lib/rules/global-require.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/global-require.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/grouped-accessor-pairs.d.ts b/typings/eslint/lib/rules/grouped-accessor-pairs.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/grouped-accessor-pairs.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/guard-for-in.d.ts b/typings/eslint/lib/rules/guard-for-in.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/guard-for-in.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/handle-callback-err.d.ts b/typings/eslint/lib/rules/handle-callback-err.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/handle-callback-err.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/id-blacklist.d.ts b/typings/eslint/lib/rules/id-blacklist.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/id-blacklist.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/id-length.d.ts b/typings/eslint/lib/rules/id-length.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/id-length.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/id-match.d.ts b/typings/eslint/lib/rules/id-match.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/id-match.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/implicit-arrow-linebreak.d.ts b/typings/eslint/lib/rules/implicit-arrow-linebreak.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/implicit-arrow-linebreak.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/indent-legacy.d.ts b/typings/eslint/lib/rules/indent-legacy.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/indent-legacy.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/indent.d.ts b/typings/eslint/lib/rules/indent.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/indent.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/init-declarations.d.ts b/typings/eslint/lib/rules/init-declarations.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/init-declarations.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/jsx-quotes.d.ts b/typings/eslint/lib/rules/jsx-quotes.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/jsx-quotes.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/key-spacing.d.ts b/typings/eslint/lib/rules/key-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/key-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/keyword-spacing.d.ts b/typings/eslint/lib/rules/keyword-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/keyword-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/line-comment-position.d.ts b/typings/eslint/lib/rules/line-comment-position.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/line-comment-position.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/linebreak-style.d.ts b/typings/eslint/lib/rules/linebreak-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/linebreak-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/lines-around-comment.d.ts b/typings/eslint/lib/rules/lines-around-comment.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/lines-around-comment.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/lines-around-directive.d.ts b/typings/eslint/lib/rules/lines-around-directive.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/lines-around-directive.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/lines-between-class-members.d.ts b/typings/eslint/lib/rules/lines-between-class-members.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/lines-between-class-members.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-classes-per-file.d.ts b/typings/eslint/lib/rules/max-classes-per-file.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-classes-per-file.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-depth.d.ts b/typings/eslint/lib/rules/max-depth.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-depth.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-len.d.ts b/typings/eslint/lib/rules/max-len.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-len.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-lines-per-function.d.ts b/typings/eslint/lib/rules/max-lines-per-function.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-lines-per-function.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-lines.d.ts b/typings/eslint/lib/rules/max-lines.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-lines.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-nested-callbacks.d.ts b/typings/eslint/lib/rules/max-nested-callbacks.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-nested-callbacks.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-params.d.ts b/typings/eslint/lib/rules/max-params.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-params.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-statements-per-line.d.ts b/typings/eslint/lib/rules/max-statements-per-line.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-statements-per-line.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/max-statements.d.ts b/typings/eslint/lib/rules/max-statements.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/max-statements.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/multiline-comment-style.d.ts b/typings/eslint/lib/rules/multiline-comment-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/multiline-comment-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/multiline-ternary.d.ts b/typings/eslint/lib/rules/multiline-ternary.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/multiline-ternary.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/new-cap.d.ts b/typings/eslint/lib/rules/new-cap.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/new-cap.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/new-parens.d.ts b/typings/eslint/lib/rules/new-parens.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/new-parens.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/newline-after-var.d.ts b/typings/eslint/lib/rules/newline-after-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/newline-after-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/newline-before-return.d.ts b/typings/eslint/lib/rules/newline-before-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/newline-before-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/newline-per-chained-call.d.ts b/typings/eslint/lib/rules/newline-per-chained-call.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/newline-per-chained-call.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-alert.d.ts b/typings/eslint/lib/rules/no-alert.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-alert.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-array-constructor.d.ts b/typings/eslint/lib/rules/no-array-constructor.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-array-constructor.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-async-promise-executor.d.ts b/typings/eslint/lib/rules/no-async-promise-executor.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-async-promise-executor.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-await-in-loop.d.ts b/typings/eslint/lib/rules/no-await-in-loop.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-await-in-loop.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-bitwise.d.ts b/typings/eslint/lib/rules/no-bitwise.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-bitwise.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-buffer-constructor.d.ts b/typings/eslint/lib/rules/no-buffer-constructor.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-buffer-constructor.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-caller.d.ts b/typings/eslint/lib/rules/no-caller.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-caller.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-case-declarations.d.ts b/typings/eslint/lib/rules/no-case-declarations.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-case-declarations.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-catch-shadow.d.ts b/typings/eslint/lib/rules/no-catch-shadow.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-catch-shadow.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-class-assign.d.ts b/typings/eslint/lib/rules/no-class-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-class-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-compare-neg-zero.d.ts b/typings/eslint/lib/rules/no-compare-neg-zero.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-compare-neg-zero.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-cond-assign.d.ts b/typings/eslint/lib/rules/no-cond-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-cond-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-confusing-arrow.d.ts b/typings/eslint/lib/rules/no-confusing-arrow.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-confusing-arrow.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-console.d.ts b/typings/eslint/lib/rules/no-console.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-console.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-const-assign.d.ts b/typings/eslint/lib/rules/no-const-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-const-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-constant-condition.d.ts b/typings/eslint/lib/rules/no-constant-condition.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-constant-condition.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-constructor-return.d.ts b/typings/eslint/lib/rules/no-constructor-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-constructor-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-continue.d.ts b/typings/eslint/lib/rules/no-continue.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-continue.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-control-regex.d.ts b/typings/eslint/lib/rules/no-control-regex.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-control-regex.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-debugger.d.ts b/typings/eslint/lib/rules/no-debugger.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-debugger.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-delete-var.d.ts b/typings/eslint/lib/rules/no-delete-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-delete-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-div-regex.d.ts b/typings/eslint/lib/rules/no-div-regex.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-div-regex.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-dupe-args.d.ts b/typings/eslint/lib/rules/no-dupe-args.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-dupe-args.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-dupe-class-members.d.ts b/typings/eslint/lib/rules/no-dupe-class-members.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-dupe-class-members.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-dupe-else-if.d.ts b/typings/eslint/lib/rules/no-dupe-else-if.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-dupe-else-if.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-dupe-keys.d.ts b/typings/eslint/lib/rules/no-dupe-keys.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-dupe-keys.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-duplicate-case.d.ts b/typings/eslint/lib/rules/no-duplicate-case.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-duplicate-case.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-duplicate-imports.d.ts b/typings/eslint/lib/rules/no-duplicate-imports.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-duplicate-imports.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-else-return.d.ts b/typings/eslint/lib/rules/no-else-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-else-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-empty-character-class.d.ts b/typings/eslint/lib/rules/no-empty-character-class.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-empty-character-class.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-empty-function.d.ts b/typings/eslint/lib/rules/no-empty-function.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-empty-function.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-empty-pattern.d.ts b/typings/eslint/lib/rules/no-empty-pattern.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-empty-pattern.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-empty.d.ts b/typings/eslint/lib/rules/no-empty.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-empty.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-eq-null.d.ts b/typings/eslint/lib/rules/no-eq-null.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-eq-null.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-eval.d.ts b/typings/eslint/lib/rules/no-eval.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-eval.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-ex-assign.d.ts b/typings/eslint/lib/rules/no-ex-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-ex-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extend-native.d.ts b/typings/eslint/lib/rules/no-extend-native.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extend-native.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extra-bind.d.ts b/typings/eslint/lib/rules/no-extra-bind.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extra-bind.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extra-boolean-cast.d.ts b/typings/eslint/lib/rules/no-extra-boolean-cast.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extra-boolean-cast.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extra-label.d.ts b/typings/eslint/lib/rules/no-extra-label.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extra-label.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extra-parens.d.ts b/typings/eslint/lib/rules/no-extra-parens.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extra-parens.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-extra-semi.d.ts b/typings/eslint/lib/rules/no-extra-semi.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-extra-semi.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-fallthrough.d.ts b/typings/eslint/lib/rules/no-fallthrough.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-fallthrough.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-floating-decimal.d.ts b/typings/eslint/lib/rules/no-floating-decimal.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-floating-decimal.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-func-assign.d.ts b/typings/eslint/lib/rules/no-func-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-func-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-global-assign.d.ts b/typings/eslint/lib/rules/no-global-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-global-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-implicit-coercion.d.ts b/typings/eslint/lib/rules/no-implicit-coercion.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-implicit-coercion.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-implicit-globals.d.ts b/typings/eslint/lib/rules/no-implicit-globals.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-implicit-globals.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-implied-eval.d.ts b/typings/eslint/lib/rules/no-implied-eval.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-implied-eval.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-import-assign.d.ts b/typings/eslint/lib/rules/no-import-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-import-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-inline-comments.d.ts b/typings/eslint/lib/rules/no-inline-comments.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-inline-comments.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-inner-declarations.d.ts b/typings/eslint/lib/rules/no-inner-declarations.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-inner-declarations.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-invalid-regexp.d.ts b/typings/eslint/lib/rules/no-invalid-regexp.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-invalid-regexp.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-invalid-this.d.ts b/typings/eslint/lib/rules/no-invalid-this.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-invalid-this.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-irregular-whitespace.d.ts b/typings/eslint/lib/rules/no-irregular-whitespace.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-irregular-whitespace.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-iterator.d.ts b/typings/eslint/lib/rules/no-iterator.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-iterator.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-label-var.d.ts b/typings/eslint/lib/rules/no-label-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-label-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-labels.d.ts b/typings/eslint/lib/rules/no-labels.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-labels.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-lone-blocks.d.ts b/typings/eslint/lib/rules/no-lone-blocks.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-lone-blocks.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-lonely-if.d.ts b/typings/eslint/lib/rules/no-lonely-if.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-lonely-if.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-loop-func.d.ts b/typings/eslint/lib/rules/no-loop-func.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-loop-func.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-loss-of-precision.d.ts b/typings/eslint/lib/rules/no-loss-of-precision.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-loss-of-precision.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-magic-numbers.d.ts b/typings/eslint/lib/rules/no-magic-numbers.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-magic-numbers.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-misleading-character-class.d.ts b/typings/eslint/lib/rules/no-misleading-character-class.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-misleading-character-class.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-mixed-operators.d.ts b/typings/eslint/lib/rules/no-mixed-operators.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-mixed-operators.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-mixed-requires.d.ts b/typings/eslint/lib/rules/no-mixed-requires.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-mixed-requires.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-mixed-spaces-and-tabs.d.ts b/typings/eslint/lib/rules/no-mixed-spaces-and-tabs.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-mixed-spaces-and-tabs.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-multi-assign.d.ts b/typings/eslint/lib/rules/no-multi-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-multi-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-multi-spaces.d.ts b/typings/eslint/lib/rules/no-multi-spaces.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-multi-spaces.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-multi-str.d.ts b/typings/eslint/lib/rules/no-multi-str.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-multi-str.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-multiple-empty-lines.d.ts b/typings/eslint/lib/rules/no-multiple-empty-lines.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-multiple-empty-lines.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-native-reassign.d.ts b/typings/eslint/lib/rules/no-native-reassign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-native-reassign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-negated-condition.d.ts b/typings/eslint/lib/rules/no-negated-condition.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-negated-condition.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-negated-in-lhs.d.ts b/typings/eslint/lib/rules/no-negated-in-lhs.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-negated-in-lhs.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-nested-ternary.d.ts b/typings/eslint/lib/rules/no-nested-ternary.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-nested-ternary.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new-func.d.ts b/typings/eslint/lib/rules/no-new-func.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new-func.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new-object.d.ts b/typings/eslint/lib/rules/no-new-object.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new-object.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new-require.d.ts b/typings/eslint/lib/rules/no-new-require.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new-require.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new-symbol.d.ts b/typings/eslint/lib/rules/no-new-symbol.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new-symbol.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new-wrappers.d.ts b/typings/eslint/lib/rules/no-new-wrappers.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new-wrappers.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-new.d.ts b/typings/eslint/lib/rules/no-new.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-new.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-obj-calls.d.ts b/typings/eslint/lib/rules/no-obj-calls.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-obj-calls.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-octal-escape.d.ts b/typings/eslint/lib/rules/no-octal-escape.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-octal-escape.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-octal.d.ts b/typings/eslint/lib/rules/no-octal.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-octal.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-param-reassign.d.ts b/typings/eslint/lib/rules/no-param-reassign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-param-reassign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-path-concat.d.ts b/typings/eslint/lib/rules/no-path-concat.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-path-concat.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-plusplus.d.ts b/typings/eslint/lib/rules/no-plusplus.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-plusplus.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-process-env.d.ts b/typings/eslint/lib/rules/no-process-env.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-process-env.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-process-exit.d.ts b/typings/eslint/lib/rules/no-process-exit.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-process-exit.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-promise-executor-return.d.ts b/typings/eslint/lib/rules/no-promise-executor-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-promise-executor-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-proto.d.ts b/typings/eslint/lib/rules/no-proto.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-proto.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-prototype-builtins.d.ts b/typings/eslint/lib/rules/no-prototype-builtins.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-prototype-builtins.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-redeclare.d.ts b/typings/eslint/lib/rules/no-redeclare.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-redeclare.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-regex-spaces.d.ts b/typings/eslint/lib/rules/no-regex-spaces.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-regex-spaces.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-exports.d.ts b/typings/eslint/lib/rules/no-restricted-exports.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-exports.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-globals.d.ts b/typings/eslint/lib/rules/no-restricted-globals.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-globals.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-imports.d.ts b/typings/eslint/lib/rules/no-restricted-imports.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-imports.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-modules.d.ts b/typings/eslint/lib/rules/no-restricted-modules.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-modules.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-properties.d.ts b/typings/eslint/lib/rules/no-restricted-properties.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-properties.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-restricted-syntax.d.ts b/typings/eslint/lib/rules/no-restricted-syntax.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-restricted-syntax.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-return-assign.d.ts b/typings/eslint/lib/rules/no-return-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-return-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-return-await.d.ts b/typings/eslint/lib/rules/no-return-await.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-return-await.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-script-url.d.ts b/typings/eslint/lib/rules/no-script-url.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-script-url.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-self-assign.d.ts b/typings/eslint/lib/rules/no-self-assign.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-self-assign.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-self-compare.d.ts b/typings/eslint/lib/rules/no-self-compare.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-self-compare.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-sequences.d.ts b/typings/eslint/lib/rules/no-sequences.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-sequences.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-setter-return.d.ts b/typings/eslint/lib/rules/no-setter-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-setter-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-shadow-restricted-names.d.ts b/typings/eslint/lib/rules/no-shadow-restricted-names.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-shadow-restricted-names.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-shadow.d.ts b/typings/eslint/lib/rules/no-shadow.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-shadow.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-spaced-func.d.ts b/typings/eslint/lib/rules/no-spaced-func.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-spaced-func.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-sparse-arrays.d.ts b/typings/eslint/lib/rules/no-sparse-arrays.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-sparse-arrays.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-sync.d.ts b/typings/eslint/lib/rules/no-sync.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-sync.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-tabs.d.ts b/typings/eslint/lib/rules/no-tabs.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-tabs.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-template-curly-in-string.d.ts b/typings/eslint/lib/rules/no-template-curly-in-string.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-template-curly-in-string.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-ternary.d.ts b/typings/eslint/lib/rules/no-ternary.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-ternary.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-this-before-super.d.ts b/typings/eslint/lib/rules/no-this-before-super.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-this-before-super.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-throw-literal.d.ts b/typings/eslint/lib/rules/no-throw-literal.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-throw-literal.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-trailing-spaces.d.ts b/typings/eslint/lib/rules/no-trailing-spaces.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-trailing-spaces.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-undef-init.d.ts b/typings/eslint/lib/rules/no-undef-init.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-undef-init.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-undef.d.ts b/typings/eslint/lib/rules/no-undef.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-undef.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-undefined.d.ts b/typings/eslint/lib/rules/no-undefined.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-undefined.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-underscore-dangle.d.ts b/typings/eslint/lib/rules/no-underscore-dangle.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-underscore-dangle.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unexpected-multiline.d.ts b/typings/eslint/lib/rules/no-unexpected-multiline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unexpected-multiline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unmodified-loop-condition.d.ts b/typings/eslint/lib/rules/no-unmodified-loop-condition.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unmodified-loop-condition.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unneeded-ternary.d.ts b/typings/eslint/lib/rules/no-unneeded-ternary.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unneeded-ternary.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unreachable-loop.d.ts b/typings/eslint/lib/rules/no-unreachable-loop.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unreachable-loop.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unreachable.d.ts b/typings/eslint/lib/rules/no-unreachable.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unreachable.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unsafe-finally.d.ts b/typings/eslint/lib/rules/no-unsafe-finally.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unsafe-finally.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unsafe-negation.d.ts b/typings/eslint/lib/rules/no-unsafe-negation.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unsafe-negation.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unused-expressions.d.ts b/typings/eslint/lib/rules/no-unused-expressions.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unused-expressions.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unused-labels.d.ts b/typings/eslint/lib/rules/no-unused-labels.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unused-labels.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-unused-vars.d.ts b/typings/eslint/lib/rules/no-unused-vars.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-unused-vars.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-use-before-define.d.ts b/typings/eslint/lib/rules/no-use-before-define.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-use-before-define.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-backreference.d.ts b/typings/eslint/lib/rules/no-useless-backreference.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-backreference.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-call.d.ts b/typings/eslint/lib/rules/no-useless-call.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-call.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-catch.d.ts b/typings/eslint/lib/rules/no-useless-catch.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-catch.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-computed-key.d.ts b/typings/eslint/lib/rules/no-useless-computed-key.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-computed-key.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-concat.d.ts b/typings/eslint/lib/rules/no-useless-concat.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-concat.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-constructor.d.ts b/typings/eslint/lib/rules/no-useless-constructor.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-constructor.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-escape.d.ts b/typings/eslint/lib/rules/no-useless-escape.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-escape.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-rename.d.ts b/typings/eslint/lib/rules/no-useless-rename.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-rename.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-useless-return.d.ts b/typings/eslint/lib/rules/no-useless-return.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-useless-return.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-var.d.ts b/typings/eslint/lib/rules/no-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-void.d.ts b/typings/eslint/lib/rules/no-void.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-void.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-warning-comments.d.ts b/typings/eslint/lib/rules/no-warning-comments.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-warning-comments.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-whitespace-before-property.d.ts b/typings/eslint/lib/rules/no-whitespace-before-property.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-whitespace-before-property.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/no-with.d.ts b/typings/eslint/lib/rules/no-with.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/no-with.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/nonblock-statement-body-position.d.ts b/typings/eslint/lib/rules/nonblock-statement-body-position.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/nonblock-statement-body-position.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/object-curly-newline.d.ts b/typings/eslint/lib/rules/object-curly-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/object-curly-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/object-curly-spacing.d.ts b/typings/eslint/lib/rules/object-curly-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/object-curly-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/object-property-newline.d.ts b/typings/eslint/lib/rules/object-property-newline.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/object-property-newline.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/object-shorthand.d.ts b/typings/eslint/lib/rules/object-shorthand.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/object-shorthand.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/one-var-declaration-per-line.d.ts b/typings/eslint/lib/rules/one-var-declaration-per-line.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/one-var-declaration-per-line.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/one-var.d.ts b/typings/eslint/lib/rules/one-var.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/one-var.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/operator-assignment.d.ts b/typings/eslint/lib/rules/operator-assignment.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/operator-assignment.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/operator-linebreak.d.ts b/typings/eslint/lib/rules/operator-linebreak.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/operator-linebreak.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/padded-blocks.d.ts b/typings/eslint/lib/rules/padded-blocks.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/padded-blocks.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/padding-line-between-statements.d.ts b/typings/eslint/lib/rules/padding-line-between-statements.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/padding-line-between-statements.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-arrow-callback.d.ts b/typings/eslint/lib/rules/prefer-arrow-callback.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-arrow-callback.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-const.d.ts b/typings/eslint/lib/rules/prefer-const.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-const.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-destructuring.d.ts b/typings/eslint/lib/rules/prefer-destructuring.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-destructuring.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-exponentiation-operator.d.ts b/typings/eslint/lib/rules/prefer-exponentiation-operator.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-exponentiation-operator.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-named-capture-group.d.ts b/typings/eslint/lib/rules/prefer-named-capture-group.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-named-capture-group.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-numeric-literals.d.ts b/typings/eslint/lib/rules/prefer-numeric-literals.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-numeric-literals.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-object-spread.d.ts b/typings/eslint/lib/rules/prefer-object-spread.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-object-spread.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-promise-reject-errors.d.ts b/typings/eslint/lib/rules/prefer-promise-reject-errors.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-promise-reject-errors.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-reflect.d.ts b/typings/eslint/lib/rules/prefer-reflect.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-reflect.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-regex-literals.d.ts b/typings/eslint/lib/rules/prefer-regex-literals.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-regex-literals.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-rest-params.d.ts b/typings/eslint/lib/rules/prefer-rest-params.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-rest-params.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-spread.d.ts b/typings/eslint/lib/rules/prefer-spread.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-spread.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/prefer-template.d.ts b/typings/eslint/lib/rules/prefer-template.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/prefer-template.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/quote-props.d.ts b/typings/eslint/lib/rules/quote-props.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/quote-props.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/quotes.d.ts b/typings/eslint/lib/rules/quotes.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/quotes.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/radix.d.ts b/typings/eslint/lib/rules/radix.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/radix.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/require-atomic-updates.d.ts b/typings/eslint/lib/rules/require-atomic-updates.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/require-atomic-updates.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/require-await.d.ts b/typings/eslint/lib/rules/require-await.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/require-await.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/require-jsdoc.d.ts b/typings/eslint/lib/rules/require-jsdoc.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/require-jsdoc.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/require-unicode-regexp.d.ts b/typings/eslint/lib/rules/require-unicode-regexp.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/require-unicode-regexp.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/require-yield.d.ts b/typings/eslint/lib/rules/require-yield.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/require-yield.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/rest-spread-spacing.d.ts b/typings/eslint/lib/rules/rest-spread-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/rest-spread-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/semi-spacing.d.ts b/typings/eslint/lib/rules/semi-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/semi-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/semi-style.d.ts b/typings/eslint/lib/rules/semi-style.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/semi-style.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/semi.d.ts b/typings/eslint/lib/rules/semi.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/semi.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/sort-imports.d.ts b/typings/eslint/lib/rules/sort-imports.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/sort-imports.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/sort-keys.d.ts b/typings/eslint/lib/rules/sort-keys.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/sort-keys.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/sort-vars.d.ts b/typings/eslint/lib/rules/sort-vars.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/sort-vars.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/space-before-blocks.d.ts b/typings/eslint/lib/rules/space-before-blocks.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/space-before-blocks.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/space-before-function-paren.d.ts b/typings/eslint/lib/rules/space-before-function-paren.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/space-before-function-paren.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/space-in-parens.d.ts b/typings/eslint/lib/rules/space-in-parens.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/space-in-parens.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/space-infix-ops.d.ts b/typings/eslint/lib/rules/space-infix-ops.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/space-infix-ops.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/space-unary-ops.d.ts b/typings/eslint/lib/rules/space-unary-ops.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/space-unary-ops.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/spaced-comment.d.ts b/typings/eslint/lib/rules/spaced-comment.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/spaced-comment.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/strict.d.ts b/typings/eslint/lib/rules/strict.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/strict.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/switch-colon-spacing.d.ts b/typings/eslint/lib/rules/switch-colon-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/switch-colon-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/symbol-description.d.ts b/typings/eslint/lib/rules/symbol-description.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/symbol-description.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/template-curly-spacing.d.ts b/typings/eslint/lib/rules/template-curly-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/template-curly-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/template-tag-spacing.d.ts b/typings/eslint/lib/rules/template-tag-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/template-tag-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/unicode-bom.d.ts b/typings/eslint/lib/rules/unicode-bom.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/unicode-bom.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/use-isnan.d.ts b/typings/eslint/lib/rules/use-isnan.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/use-isnan.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/valid-jsdoc.d.ts b/typings/eslint/lib/rules/valid-jsdoc.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/valid-jsdoc.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/valid-typeof.d.ts b/typings/eslint/lib/rules/valid-typeof.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/valid-typeof.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/vars-on-top.d.ts b/typings/eslint/lib/rules/vars-on-top.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/vars-on-top.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/wrap-iife.d.ts b/typings/eslint/lib/rules/wrap-iife.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/wrap-iife.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/wrap-regex.d.ts b/typings/eslint/lib/rules/wrap-regex.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/wrap-regex.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/yield-star-spacing.d.ts b/typings/eslint/lib/rules/yield-star-spacing.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/yield-star-spacing.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/eslint/lib/rules/yoda.d.ts b/typings/eslint/lib/rules/yoda.d.ts new file mode 100644 index 00000000..146fa11b --- /dev/null +++ b/typings/eslint/lib/rules/yoda.d.ts @@ -0,0 +1,3 @@ +import { Rule } from '../../index' +declare const rule: Rule.RuleModule +export = rule diff --git a/typings/vue-eslint-parser/index.d.ts b/typings/vue-eslint-parser/index.d.ts new file mode 100644 index 00000000..1330ce5c --- /dev/null +++ b/typings/vue-eslint-parser/index.d.ts @@ -0,0 +1,5 @@ +import * as VAST from '../../src/eslint-plugins/types/ast' + +export namespace AST { + export const NS: VAST.NS +}