From f66db57652c9c86c1dcd895f929afd7c5ae7c643 Mon Sep 17 00:00:00 2001
From: tyankatsu <frips.ryilsufupe+dev@gmail.com>
Date: Tue, 4 May 2021 01:33:31 +0900
Subject: [PATCH 1/4] feat: add eslint-plugins directory
---
src/eslint-plugins/README.md | 1 +
src/eslint-plugins/index.ts | 1 +
src/eslint-plugins/utils.ts | 0
src/index.ts | 2 ++
4 files changed, 4 insertions(+)
create mode 100644 src/eslint-plugins/README.md
create mode 100644 src/eslint-plugins/index.ts
create mode 100644 src/eslint-plugins/utils.ts
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/index.ts b/src/eslint-plugins/index.ts
new file mode 100644
index 00000000..cfa334d6
--- /dev/null
+++ b/src/eslint-plugins/index.ts
@@ -0,0 +1 @@
+export * from './utils'
\ No newline at end of file
diff --git a/src/eslint-plugins/utils.ts b/src/eslint-plugins/utils.ts
new file mode 100644
index 00000000..e69de29b
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
From b3bf25df9770f71475ba75fcd6a9ad665605d408 Mon Sep 17 00:00:00 2001
From: tyankatsu <frips.ryilsufupe+dev@gmail.com>
Date: Tue, 4 May 2021 16:32:50 +0900
Subject: [PATCH 2/4] feat: move type and util from eslint-plugin-vue
---
src/eslint-plugins/global.d.ts | 178 ++
src/eslint-plugins/index.ts | 1 -
src/eslint-plugins/types/ast/ast.ts | 343 +++
src/eslint-plugins/types/ast/es-ast.ts | 543 +++++
src/eslint-plugins/types/ast/index.ts | 5 +
src/eslint-plugins/types/ast/jsx-ast.ts | 106 +
src/eslint-plugins/types/ast/ts-ast.ts | 11 +
src/eslint-plugins/types/ast/v-ast.ts | 174 ++
src/eslint-plugins/types/errors.ts | 43 +
src/eslint-plugins/types/node/index.ts | 3 +
src/eslint-plugins/types/node/locations.ts | 13 +
src/eslint-plugins/types/node/node.ts | 11 +
src/eslint-plugins/types/node/tokens.ts | 17 +
src/eslint-plugins/types/parser-services.ts | 122 +
src/eslint-plugins/types/utils.ts | 29 +
src/eslint-plugins/utils.ts | 0
src/eslint-plugins/utils/casing.js | 203 ++
.../utils/deprecated-html-elements.json | 1 +
src/eslint-plugins/utils/html-comments.js | 259 ++
src/eslint-plugins/utils/html-elements.json | 1 +
src/eslint-plugins/utils/indent-common.ts | 2085 +++++++++++++++++
src/eslint-plugins/utils/index.ts | 2068 ++++++++++++++++
.../utils/inline-non-void-elements.json | 40 +
src/eslint-plugins/utils/js-reserved.json | 18 +
src/eslint-plugins/utils/key-aliases.json | 68 +
src/eslint-plugins/utils/keycode-to-key.ts | 98 +
src/eslint-plugins/utils/regexp.ts | 35 +
src/eslint-plugins/utils/svg-elements.json | 1 +
src/eslint-plugins/utils/void-elements.json | 1 +
.../utils/vue-component-options.json | 54 +
src/eslint-plugins/utils/vue-reserved.json | 4 +
31 files changed, 6534 insertions(+), 1 deletion(-)
create mode 100644 src/eslint-plugins/global.d.ts
delete mode 100644 src/eslint-plugins/index.ts
create mode 100644 src/eslint-plugins/types/ast/ast.ts
create mode 100644 src/eslint-plugins/types/ast/es-ast.ts
create mode 100644 src/eslint-plugins/types/ast/index.ts
create mode 100644 src/eslint-plugins/types/ast/jsx-ast.ts
create mode 100644 src/eslint-plugins/types/ast/ts-ast.ts
create mode 100644 src/eslint-plugins/types/ast/v-ast.ts
create mode 100644 src/eslint-plugins/types/errors.ts
create mode 100644 src/eslint-plugins/types/node/index.ts
create mode 100644 src/eslint-plugins/types/node/locations.ts
create mode 100644 src/eslint-plugins/types/node/node.ts
create mode 100644 src/eslint-plugins/types/node/tokens.ts
create mode 100644 src/eslint-plugins/types/parser-services.ts
create mode 100644 src/eslint-plugins/types/utils.ts
delete mode 100644 src/eslint-plugins/utils.ts
create mode 100644 src/eslint-plugins/utils/casing.js
create mode 100644 src/eslint-plugins/utils/deprecated-html-elements.json
create mode 100644 src/eslint-plugins/utils/html-comments.js
create mode 100644 src/eslint-plugins/utils/html-elements.json
create mode 100644 src/eslint-plugins/utils/indent-common.ts
create mode 100644 src/eslint-plugins/utils/index.ts
create mode 100644 src/eslint-plugins/utils/inline-non-void-elements.json
create mode 100644 src/eslint-plugins/utils/js-reserved.json
create mode 100644 src/eslint-plugins/utils/key-aliases.json
create mode 100644 src/eslint-plugins/utils/keycode-to-key.ts
create mode 100644 src/eslint-plugins/utils/regexp.ts
create mode 100644 src/eslint-plugins/utils/svg-elements.json
create mode 100644 src/eslint-plugins/utils/void-elements.json
create mode 100644 src/eslint-plugins/utils/vue-component-options.json
create mode 100644 src/eslint-plugins/utils/vue-reserved.json
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/index.ts b/src/eslint-plugins/index.ts
deleted file mode 100644
index cfa334d6..00000000
--- a/src/eslint-plugins/index.ts
+++ /dev/null
@@ -1 +0,0 @@
-export * from './utils'
\ No newline at end of file
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.ts b/src/eslint-plugins/utils.ts
deleted file mode 100644
index e69de29b..00000000
diff --git a/src/eslint-plugins/utils/casing.js b/src/eslint-plugins/utils/casing.js
new file mode 100644
index 00000000..b2f2e89b
--- /dev/null
+++ b/src/eslint-plugins/utils/casing.js
@@ -0,0 +1,203 @@
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+/**
+ * Capitalize a string.
+ * @param {string} str
+ */
+function capitalize(str) {
+ return str.charAt(0).toUpperCase() + str.slice(1)
+}
+/**
+ * Checks whether the given string has symbols.
+ * @param {string} str
+ */
+function hasSymbols(str) {
+ return /[!"#%&'()*+,./:;<=>?@[\\\]^`{|}]/u.exec(str) // without " ", "$", "-" and "_"
+}
+/**
+ * Checks whether the given string has upper.
+ * @param {string} str
+ */
+function hasUpper(str) {
+ return /[A-Z]/u.exec(str)
+}
+
+/**
+ * Convert text to kebab-case
+ * @param {string} str Text to be converted
+ * @return {string}
+ */
+function kebabCase(str) {
+ return str
+ .replace(/_/gu, '-')
+ .replace(/\B([A-Z])/gu, '-$1')
+ .toLowerCase()
+}
+
+/**
+ * Checks whether the given string is kebab-case.
+ * @param {string} str
+ */
+function isKebabCase(str) {
+ 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 {string} str Text to be converted
+ * @return {string}
+ */
+function snakeCase(str) {
+ return str
+ .replace(/\B([A-Z])/gu, '_$1')
+ .replace(/-/gu, '_')
+ .toLowerCase()
+}
+
+/**
+ * Checks whether the given string is snake_case.
+ * @param {string} str
+ */
+function isSnakeCase(str) {
+ if (hasUpper(str) || hasSymbols(str) || /-|__|\s/u.exec(str)) {
+ return false
+ }
+ return true
+}
+
+/**
+ * Convert text to camelCase
+ * @param {string} str Text to be converted
+ * @return {string} Converted string
+ */
+function camelCase(str) {
+ 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.
+ * @param {string} str
+ */
+function isCamelCase(str) {
+ 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 {string} str Text to be converted
+ * @return {string} Converted string
+ */
+function pascalCase(str) {
+ return capitalize(camelCase(str))
+}
+
+/**
+ * Checks whether the given string is PascalCase.
+ * @param {string} str
+ */
+function isPascalCase(str) {
+ 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,
+ snake_case: snakeCase,
+ camelCase,
+ PascalCase: pascalCase
+}
+
+const checkersMap = {
+ 'kebab-case': isKebabCase,
+ snake_case: isSnakeCase,
+ camelCase: isCamelCase,
+ PascalCase: isPascalCase
+}
+/**
+ * Return case checker
+ * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of checker to return ('camelCase', 'kebab-case', 'PascalCase')
+ * @return {isKebabCase|isCamelCase|isPascalCase|isSnakeCase}
+ */
+function getChecker(name) {
+ return checkersMap[name] || isPascalCase
+}
+
+/**
+ * Return case converter
+ * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
+ * @return {kebabCase|camelCase|pascalCase|snakeCase}
+ */
+function getConverter(name) {
+ return convertersMap[name] || pascalCase
+}
+
+module.exports = {
+ allowedCaseOptions: ['camelCase', 'kebab-case', 'PascalCase'],
+
+ /**
+ * Return case converter
+ * @param {string} name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
+ * @return {kebabCase|camelCase|pascalCase|snakeCase}
+ */
+ getConverter,
+
+ /**
+ * Return case checker
+ * @param {string} name type of checker to return ('camelCase', 'kebab-case', 'PascalCase')
+ * @return {isKebabCase|isCamelCase|isPascalCase|isSnakeCase}
+ */
+ getChecker,
+
+ /**
+ * Return case exact converter.
+ * If the converted result is not the correct case, the original value is returned.
+ * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
+ * @return {kebabCase|camelCase|pascalCase|snakeCase}
+ */
+ getExactConverter(name) {
+ const converter = getConverter(name)
+ const checker = getChecker(name)
+ return (str) => {
+ const result = converter(str)
+ return checker(result) ? result : str /* cannot convert */
+ }
+ },
+
+ camelCase,
+ pascalCase,
+ kebabCase,
+ snakeCase,
+
+ isCamelCase,
+ isPascalCase,
+ isKebabCase,
+ isSnakeCase,
+
+ capitalize
+}
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.js b/src/eslint-plugins/utils/html-comments.js
new file mode 100644
index 00000000..aced46e7
--- /dev/null
+++ b/src/eslint-plugins/utils/html-comments.js
@@ -0,0 +1,259 @@
+/**
+ * @typedef { { exceptions?: string[] } } CommentParserConfig
+ * @typedef { (comment: ParsedHTMLComment) => void } HTMLCommentVisitor
+ * @typedef { { includeDirectives?: boolean } } CommentVisitorOption
+ *
+ * @typedef { Token & { type: 'HTMLCommentOpen' } } HTMLCommentOpen
+ * @typedef { Token & { type: 'HTMLCommentOpenDecoration' } } HTMLCommentOpenDecoration
+ * @typedef { Token & { type: 'HTMLCommentValue' } } HTMLCommentValue
+ * @typedef { Token & { type: 'HTMLCommentClose' } } HTMLCommentClose
+ * @typedef { Token & { type: 'HTMLCommentCloseDecoration' } } HTMLCommentCloseDecoration
+ * @typedef { { open: HTMLCommentOpen, openDecoration: HTMLCommentOpenDecoration | null, value: HTMLCommentValue | null, closeDecoration: HTMLCommentCloseDecoration | null, close: HTMLCommentClose } } ParsedHTMLComment
+ */
+// -----------------------------------------------------------------------------
+// Requirements
+// -----------------------------------------------------------------------------
+
+const utils = require('./')
+
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+const COMMENT_DIRECTIVE = /^\s*eslint-(?:en|dis)able/
+const IE_CONDITIONAL_IF = /^\[if\s+/
+const IE_CONDITIONAL_ENDIF = /\[endif\]$/
+
+/** @type { 'HTMLCommentOpen' } */
+const TYPE_HTML_COMMENT_OPEN = 'HTMLCommentOpen'
+/** @type { 'HTMLCommentOpenDecoration' } */
+const TYPE_HTML_COMMENT_OPEN_DECORATION = 'HTMLCommentOpenDecoration'
+/** @type { 'HTMLCommentValue' } */
+const TYPE_HTML_COMMENT_VALUE = 'HTMLCommentValue'
+/** @type { 'HTMLCommentClose' } */
+const TYPE_HTML_COMMENT_CLOSE = 'HTMLCommentClose'
+/** @type { 'HTMLCommentCloseDecoration' } */
+const TYPE_HTML_COMMENT_CLOSE_DECORATION = 'HTMLCommentCloseDecoration'
+
+/**
+ * @param {HTMLComment} comment
+ * @returns {boolean}
+ */
+function isCommentDirective(comment) {
+ return COMMENT_DIRECTIVE.test(comment.value)
+}
+
+/**
+ * @param {HTMLComment} comment
+ * @returns {boolean}
+ */
+function isIEConditionalComment(comment) {
+ return (
+ IE_CONDITIONAL_IF.test(comment.value) ||
+ IE_CONDITIONAL_ENDIF.test(comment.value)
+ )
+}
+
+/**
+ * Define HTML comment parser
+ *
+ * @param {SourceCode} sourceCode The source code instance.
+ * @param {CommentParserConfig | null} config The config.
+ * @returns { (node: Token) => (ParsedHTMLComment | null) } HTML comment parser.
+ */
+function defineParser(sourceCode, config) {
+ config = config || {}
+
+ const exceptions = config.exceptions || []
+
+ /**
+ * Get a open decoration string from comment contents.
+ * @param {string} contents comment contents
+ * @returns {string} decoration string
+ */
+ function getOpenDecoration(contents) {
+ 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 {string} contents comment contents
+ * @returns {string} decoration string
+ */
+ function getCloseDecoration(contents) {
+ 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) {
+ 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)
+ 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)
+ }
+ 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 {string} type
+ * @param {string} value
+ * @returns {any}
+ */
+ const createToken = (type, value) => {
+ /** @type {Range} */
+ const range = [tokenIndex, tokenIndex + value.length]
+ tokenIndex = range[1]
+ /** @type {SourceLocation} */
+ let loc
+ return {
+ type,
+ value,
+ range,
+ get loc() {
+ if (loc) {
+ return loc
+ }
+ return (loc = {
+ start: sourceCode.getLocFromIndex(range[0]),
+ end: sourceCode.getLocFromIndex(range[1])
+ })
+ }
+ }
+ }
+
+ /** @type {HTMLCommentOpen} */
+ const open = createToken(TYPE_HTML_COMMENT_OPEN, '<!--')
+ /** @type {HTMLCommentOpenDecoration | null} */
+ const openDecoration = openDecorationText
+ ? createToken(TYPE_HTML_COMMENT_OPEN_DECORATION, openDecorationText)
+ : null
+ tokenIndex += beforeSpace.length
+ /** @type {HTMLCommentValue | null} */
+ const value = valueText
+ ? createToken(TYPE_HTML_COMMENT_VALUE, valueText)
+ : null
+ tokenIndex += afterSpace.length
+ /** @type {HTMLCommentCloseDecoration | null} */
+ const closeDecoration = closeDecorationText
+ ? createToken(TYPE_HTML_COMMENT_CLOSE_DECORATION, closeDecorationText)
+ : null
+ /** @type {HTMLCommentClose} */
+ const close = 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 {RuleContext} context The rule context.
+ * @param {CommentParserConfig | null} config The config.
+ * @param {HTMLCommentVisitor} visitHTMLComment The HTML comment visitor.
+ * @param {CommentVisitorOption} [visitorOption] The option for visitor.
+ * @returns {RuleListener} HTML comment visitor.
+ */
+function defineVisitor(context, config, visitHTMLComment, visitorOption) {
+ return {
+ Program(node) {
+ 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)
+ }
+ }
+ }
+ }
+}
+
+module.exports = {
+ defineVisitor
+}
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..8ef9fc61
--- /dev/null
+++ b/src/eslint-plugins/utils/indent-common.ts
@@ -0,0 +1,2085 @@
+/**
+ * @author Toru Nagashima <https://github.com/mysticatea>
+ * See LICENSE file in root directory for full license.
+ */
+'use strict'
+
+// ------------------------------------------------------------------------------
+// Requirements
+// ------------------------------------------------------------------------------
+
+// ------------------------------------------------------------------------------
+// Helpers
+// ------------------------------------------------------------------------------
+
+
+const KNOWN_NODES = new Set([
+ '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'
+])
+const LT_CHAR = /[\r\n\u2028\u2029]/
+const LINES = /[^\r\n\u2028\u2029]+(?:$|\r\n|[\r\n\u2028\u2029])/g
+const BLOCK_COMMENT_PREFIX = /^\s*\*/
+const ITERATION_OPTS = Object.freeze({
+ includeComments: true,
+ filter: isNotWhitespace
+})
+const PREFORMATTED_ELEMENT_NAMES = ['pre', 'textarea']
+
+/**
+ * @typedef {object} IndentOptions
+ * @property { " " | "\t" } IndentOptions.indentChar
+ * @property {number} IndentOptions.indentSize
+ * @property {number} IndentOptions.baseIndent
+ * @property {number} IndentOptions.attribute
+ * @property {object} IndentOptions.closeBracket
+ * @property {number} IndentOptions.closeBracket.startTag
+ * @property {number} IndentOptions.closeBracket.endTag
+ * @property {number} IndentOptions.closeBracket.selfClosingTag
+ * @property {number} IndentOptions.switchCase
+ * @property {boolean} IndentOptions.alignAttributesVertically
+ * @property {string[]} IndentOptions.ignores
+ */
+/**
+ * @typedef {object} IndentUserOptions
+ * @property { " " | "\t" } [IndentUserOptions.indentChar]
+ * @property {number} [IndentUserOptions.indentSize]
+ * @property {number} [IndentUserOptions.baseIndent]
+ * @property {number} [IndentUserOptions.attribute]
+ * @property {IndentOptions['closeBracket'] | number} [IndentUserOptions.closeBracket]
+ * @property {number} [IndentUserOptions.switchCase]
+ * @property {boolean} [IndentUserOptions.alignAttributesVertically]
+ * @property {string[]} [IndentUserOptions.ignores]
+ */
+/**
+ * Normalize options.
+ * @param {number|"tab"|undefined} type The type of indentation.
+ * @param {IndentUserOptions} options Other options.
+ * @param {Partial<IndentOptions>} defaultOptions The default value of options.
+ * @returns {IndentOptions} Normalized options.
+ */
+function parseOptions(type, options, defaultOptions) {
+ /** @type {IndentOptions} */
+ const ret = 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.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is an arrow.
+ */
+function isArrow(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '=>'
+}
+
+/**
+ * Check whether the given token is a left parenthesis.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a left parenthesis.
+ */
+function isLeftParen(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '('
+}
+
+/**
+ * Check whether the given token is a left parenthesis.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `false` if the token is a left parenthesis.
+ */
+function isNotLeftParen(token) {
+ return token != null && (token.type !== 'Punctuator' || token.value !== '(')
+}
+
+/**
+ * Check whether the given token is a right parenthesis.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a right parenthesis.
+ */
+function isRightParen(token) {
+ return token != null && token.type === 'Punctuator' && token.value === ')'
+}
+
+/**
+ * Check whether the given token is a right parenthesis.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `false` if the token is a right parenthesis.
+ */
+function isNotRightParen(token) {
+ return token != null && (token.type !== 'Punctuator' || token.value !== ')')
+}
+
+/**
+ * Check whether the given token is a left brace.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a left brace.
+ */
+function isLeftBrace(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '{'
+}
+
+/**
+ * Check whether the given token is a right brace.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a right brace.
+ */
+function isRightBrace(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '}'
+}
+
+/**
+ * Check whether the given token is a left bracket.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a left bracket.
+ */
+function isLeftBracket(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '['
+}
+
+/**
+ * Check whether the given token is a right bracket.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a right bracket.
+ */
+function isRightBracket(token) {
+ return token != null && token.type === 'Punctuator' && token.value === ']'
+}
+
+/**
+ * Check whether the given token is a semicolon.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a semicolon.
+ */
+function isSemicolon(token) {
+ return token != null && token.type === 'Punctuator' && token.value === ';'
+}
+
+/**
+ * Check whether the given token is a comma.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a comma.
+ */
+function isComma(token) {
+ return token != null && token.type === 'Punctuator' && token.value === ','
+}
+/**
+ * Check whether the given token is a wildcard.
+ * @param {Token} token The token to check.
+ * @returns {boolean} `true` if the token is a wildcard.
+ */
+function isWildcard(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '*'
+}
+
+/**
+ * Check whether the given token is a whitespace.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a whitespace.
+ */
+function isNotWhitespace(token) {
+ return token != null && token.type !== 'HTMLWhitespace'
+}
+
+/**
+ * Check whether the given token is a comment.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a comment.
+ */
+function isComment(token) {
+ 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.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `false` if the token is a comment.
+ */
+function isNotComment(token) {
+ 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.
+ * @param {ASTNode} node The node to check.
+ * @returns {boolean} `false` if the token is empty text node.
+ */
+function isNotEmptyTextNode(node) {
+ return !(node.type === 'VText' && node.value.trim() === '')
+}
+
+/**
+ * Check whether the given token is a pipe operator.
+ * @param {Token|undefined|null} token The token to check.
+ * @returns {boolean} `true` if the token is a pipe operator.
+ */
+function isPipeOperator(token) {
+ return token != null && token.type === 'Punctuator' && token.value === '|'
+}
+
+/**
+ * Get the last element.
+ * @template T
+ * @param {T[]} xs The array to get the last element.
+ * @returns {T | undefined} The last element or undefined.
+ */
+function last(xs) {
+ return xs.length === 0 ? undefined : xs[xs.length - 1]
+}
+
+/**
+ * Check whether the node is at the beginning of line.
+ * @param {ASTNode|null} node The node to check.
+ * @param {number} index The index of the node in the nodes.
+ * @param {(ASTNode|null)[]} nodes The array of nodes.
+ * @returns {boolean} `true` if the node is at the beginning of line.
+ */
+function isBeginningOfLine(node, index, nodes) {
+ 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.
+ * @param {Token} token The token to check.
+ * @returns {boolean} `true` if the token is a closing token.
+ */
+function isClosingToken(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 {RuleContext} context The rule context.
+ * @param {ParserServices.TokenStore | SourceCode} tokenStore The token store object to get tokens.
+ * @param {Partial<IndentOptions>} defaultOptions The default value of options.
+ * @returns {NodeListener} AST event handlers.
+ */
+module.exports.defineVisitor = function create(
+ context,
+ tokenStore,
+ defaultOptions
+) {
+ 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.
+ * @param {Token|Token[]|null|(Token|null)[]} token The token to set.
+ * @param {number} offset The offset of the tokens.
+ * @param {Token} baseToken The token of the base offset.
+ * @returns {void}
+ */
+ function setOffset(token, offset, baseToken) {
+ 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.
+ * @param {Token} token The token to set.
+ * @returns {void}
+ */
+ function setBaseline(token) {
+ const offsetInfo = offsets.get(token)
+ if (offsetInfo != null) {
+ offsetInfo.baseline = true
+ }
+ }
+
+ /**
+ * Sets preformatted tokens to the given element node.
+ * @param {VElement} node The node to set.
+ * @returns {void}
+ */
+ function setPreformattedTokens(node) {
+ const endToken =
+ (node.endTag && tokenStore.getFirstToken(node.endTag)) ||
+ tokenStore.getTokenAfter(node)
+
+ /** @type {SourceCode.CursorWithSkipOptions} */
+ const option = {
+ 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 {ASTNode} node The node to get.
+ * @param {number} [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 {{firstToken:Token,lastToken:Token}} The gotten tokens.
+ */
+ function getFirstAndLastTokens(node, borderOffset = 0) {
+ 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 {(ASTNode|null)[]} nodeList The node to process.
+ * @param {ASTNode|Token|null} left The left parenthesis token.
+ * @param {ASTNode|Token|null} right The right parenthesis token.
+ * @param {number} offset The offset to set.
+ * @param {boolean} [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}
+ */
+ function processNodeList(nodeList, left, right, offset, alignVertically) {
+ 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 (let i = 0; i < nodeList.length; ++i) {
+ const node = nodeList[i]
+ 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 {ASTNode} node The body node to process.
+ * @param {Token} baseToken The base token.
+ * @returns {void}
+ */
+ function processMaybeBlock(node, baseToken) {
+ 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 {Property|MethodDefinition} node The property node to collect prefix tokens.
+ */
+ function getPrefixTokens(node) {
+ 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 {ASTNode} node The start node to find the head.
+ * @returns {Token} The head token of the chain.
+ */
+ function getChainHeadToken(node) {
+ 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
+ }
+ 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} token The token to check.
+ * @param {ASTNode} 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, belongingNode) {
+ 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 = /** @type {Token} */ (tokenStore.getTokenAfter(
+ parent.callee,
+ isNotRightParen
+ ))
+ 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 {ASTNode} node The node to set.
+ * @param {number} expectedIndent The number of expected indent.
+ * @returns {void}
+ */
+ function processTopLevelNode(node, expectedIndent) {
+ 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 {ASTNode} node The node to ignore.
+ * @returns {void}
+ */
+ function ignore(node) {
+ for (const token of tokenStore.getTokens(node)) {
+ offsets.delete(token)
+ ignoreTokens.add(token)
+ }
+ }
+
+ /**
+ * Define functions to ignore nodes into the given visitor.
+ * @param {NodeListener} visitor The visitor to define functions to ignore nodes.
+ * @returns {NodeListener} The visitor.
+ */
+ function processIgnores(visitor) {
+ for (const ignorePattern of options.ignores) {
+ const key = `${ignorePattern}:exit`
+
+ 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 {Token[]} tokens Tokens which are on the same line.
+ * @returns { { expectedIndent: number, expectedBaseIndent: number } |null } Correct indentation. If it failed to calculate then `null`.
+ */
+ function getExpectedIndents(tokens) {
+ 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(
+ 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 {Token} firstToken The first token on a line.
+ * @returns {string} The text of indentation part.
+ */
+ function getIndentText(firstToken) {
+ 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} token The token to fix.
+ * @param {number} actualIndent The number of actual indentation.
+ * @param {number} expectedIndent The number of expected indentation.
+ * @returns { (fixer: RuleFixer) => Fix } The defined function.
+ */
+ function defineFix(token, actualIndent, expectedIndent) {
+ 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) => {
+ /** @type {Range} */
+ const 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) => {
+ /** @type {Range} */
+ const 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} token The token to validate.
+ * @param {number} expectedIndent The expected indentation.
+ * @param {number[]} [optionalExpectedIndents] The optional expected indentation.
+ * @returns {void}
+ */
+ function validateCore(token, expectedIndent, optionalExpectedIndents) {
+ 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 {Token} nextToken The next token of comments.
+ * @param {number} nextExpectedIndent The expected indent of the next token.
+ * @param {number} lastExpectedIndent The expected indent of the last token.
+ * @returns {number[]}
+ */
+ function getCommentExpectedIndents(
+ nextToken,
+ nextExpectedIndent,
+ lastExpectedIndent
+ ) {
+ 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 {Token[]} tokens The tokens on the same line to validate.
+ * @param {Token[]} comments The comments which are on the immediately previous lines of the tokens.
+ * @param {Token|null} lastToken The last validated token. Comments can adjust to the token.
+ * @returns {void}
+ */
+ function validate(tokens, comments, lastToken) {
+ // 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({
+ /** @param {VAttribute} node */
+ VAttribute(node) {
+ 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)
+ }
+ }
+ },
+ /** @param {VElement} node */
+ VElement(node) {
+ 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)
+ }
+ },
+ /** @param {VEndTag} node */
+ VEndTag(node) {
+ 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)
+ }
+ },
+ /** @param {VExpressionContainer} node */
+ VExpressionContainer(node) {
+ 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)
+ }
+ },
+ /** @param {VFilter} node */
+ VFilter(node) {
+ 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)
+ }
+ },
+ /** @param {VFilterSequenceExpression} node */
+ VFilterSequenceExpression(node) {
+ 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)
+ },
+ /** @param {VForExpression} node */
+ VForExpression(node) {
+ const firstToken = tokenStore.getFirstToken(node)
+ const lastOfLeft = last(node.left) || firstToken
+ const inToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ lastOfLeft,
+ isNotRightParen
+ ))
+ const rightToken = tokenStore.getFirstToken(node.right)
+
+ if (isLeftParen(firstToken)) {
+ const rightToken = tokenStore.getTokenAfter(lastOfLeft, isRightParen)
+ processNodeList(node.left, firstToken, rightToken, 1)
+ }
+ setOffset(inToken, 1, firstToken)
+ setOffset(rightToken, 1, inToken)
+ },
+ /** @param {VOnExpression} node */
+ VOnExpression(node) {
+ processNodeList(node.body, null, null, 0)
+ },
+ /** @param {VStartTag} node */
+ VStartTag(node) {
+ 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)
+ }
+ },
+ /** @param {VText} node */
+ VText(node) {
+ const tokens = tokenStore.getTokens(node, isNotWhitespace)
+ const firstTokenInfo = offsets.get(tokenStore.getFirstToken(node))
+
+ for (const token of tokens) {
+ offsets.set(token, Object.assign({}, firstTokenInfo))
+ }
+ },
+ /** @param {ArrayExpression | ArrayPattern} node */
+ 'ArrayExpression, ArrayPattern'(node) {
+ processNodeList(
+ node.elements,
+ tokenStore.getFirstToken(node),
+ tokenStore.getLastToken(node),
+ 1
+ )
+ },
+ /** @param {ArrowFunctionExpression} node */
+ ArrowFunctionExpression(node) {
+ 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)
+ },
+ /** @param {AssignmentExpression | AssignmentPattern | BinaryExpression | LogicalExpression} node */
+ 'AssignmentExpression, AssignmentPattern, BinaryExpression, LogicalExpression'(
+ node
+ ) {
+ const leftToken = getChainHeadToken(node)
+ const opToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.left,
+ isNotRightParen
+ ))
+ 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)
+ },
+ /** @param {AwaitExpression | RestElement | SpreadElement | UnaryExpression} node */
+ 'AwaitExpression, RestElement, SpreadElement, UnaryExpression'(node) {
+ const firstToken = tokenStore.getFirstToken(node)
+ const nextToken = tokenStore.getTokenAfter(firstToken)
+
+ setOffset(nextToken, 1, firstToken)
+ },
+ /** @param {BlockStatement | ClassBody} node */
+ 'BlockStatement, ClassBody'(node) {
+ processNodeList(
+ node.body,
+ tokenStore.getFirstToken(node),
+ tokenStore.getLastToken(node),
+ 1
+ )
+ },
+ /** @param {BreakStatement | ContinueStatement | ReturnStatement | ThrowStatement} node */
+ 'BreakStatement, ContinueStatement, ReturnStatement, ThrowStatement'(node) {
+ 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)
+ }
+ },
+ /** @param {CallExpression} node */
+ CallExpression(node) {
+ 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)
+ },
+ /** @param {ImportExpression} node */
+ ImportExpression(node) {
+ 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)
+ },
+ /** @param {CatchClause} node */
+ CatchClause(node) {
+ 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)
+ },
+ /** @param {ClassDeclaration | ClassExpression} node */
+ 'ClassDeclaration, ClassExpression'(node) {
+ 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)
+ },
+ /** @param {ConditionalExpression} node */
+ ConditionalExpression(node) {
+ const prevToken = tokenStore.getTokenBefore(node)
+ const firstToken = tokenStore.getFirstToken(node)
+ const questionToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.test,
+ isNotRightParen
+ ))
+ const consequentToken = tokenStore.getTokenAfter(questionToken)
+ const colonToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.consequent,
+ isNotRightParen
+ ))
+ 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)
+ }
+ },
+ /** @param {DoWhileStatement} node */
+ DoWhileStatement(node) {
+ const doToken = tokenStore.getFirstToken(node)
+ const whileToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.body,
+ isNotRightParen
+ ))
+ 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)
+ },
+ /** @param {ExportAllDeclaration} node */
+ ExportAllDeclaration(node) {
+ const tokens = tokenStore.getTokens(node)
+ const firstToken = /** @type {Token} */ (tokens.shift())
+ if (isSemicolon(last(tokens))) {
+ tokens.pop()
+ }
+ if (!node.exported) {
+ setOffset(tokens, 1, firstToken)
+ } else {
+ // export * as foo from "mod"
+ const starToken = /** @type {Token} */ (tokens.find(isWildcard))
+ 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)
+ }
+ },
+ /** @param {ExportDefaultDeclaration} node */
+ ExportDefaultDeclaration(node) {
+ const exportToken = tokenStore.getFirstToken(node)
+ const defaultToken = tokenStore.getFirstToken(node, 1)
+ const declarationToken = getFirstAndLastTokens(node.declaration)
+ .firstToken
+ setOffset([defaultToken, declarationToken], 1, exportToken)
+ },
+ /** @param {ExportNamedDeclaration} node */
+ ExportNamedDeclaration(node) {
+ 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 = /** @type {Token} */ (tokenStore.getLastToken(
+ node,
+ isRightBrace
+ ))
+ 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
+ }
+ }
+ },
+ /** @param {ExportSpecifier} node */
+ ExportSpecifier(node) {
+ const tokens = tokenStore.getTokens(node)
+ const firstToken = /** @type {Token} */ (tokens.shift())
+ setOffset(tokens, 1, firstToken)
+ },
+ /** @param {ForInStatement | ForOfStatement} node */
+ 'ForInStatement, ForOfStatement'(node) {
+ 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 = /** @type {Token} */ (tokenStore.getTokenAfter(
+ leftToken,
+ isNotRightParen
+ ))
+ 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)
+ },
+ /** @param {ForStatement} node */
+ ForStatement(node) {
+ 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)
+ },
+ /** @param {FunctionDeclaration | FunctionExpression} node */
+ 'FunctionDeclaration, FunctionExpression'(node) {
+ 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)
+ }
+ },
+ /** @param {IfStatement} node */
+ IfStatement(node) {
+ 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 = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.consequent,
+ isNotRightParen
+ ))
+
+ setOffset(elseToken, 0, ifToken)
+ processMaybeBlock(node.alternate, elseToken)
+ }
+ },
+ /** @param {ImportDeclaration} node */
+ ImportDeclaration(node) {
+ const firstSpecifier = node.specifiers[0]
+ const secondSpecifier = node.specifiers[1]
+ const importToken = tokenStore.getFirstToken(node)
+ const hasSemi = tokenStore.getLastToken(node).value === ';'
+ /** @type {Token[]} */
+ const tokens = [] // 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)
+ },
+ /** @param {ImportSpecifier} node */
+ ImportSpecifier(node) {
+ if (node.local.range[0] !== node.imported.range[0]) {
+ const tokens = tokenStore.getTokens(node)
+ const firstToken = /** @type {Token} */ (tokens.shift())
+ setOffset(tokens, 1, firstToken)
+ }
+ },
+ /** @param {ImportNamespaceSpecifier} node */
+ ImportNamespaceSpecifier(node) {
+ const tokens = tokenStore.getTokens(node)
+ const firstToken = /** @type {Token} */ (tokens.shift())
+ setOffset(tokens, 1, firstToken)
+ },
+ /** @param {LabeledStatement} node */
+ LabeledStatement(node) {
+ const labelToken = tokenStore.getFirstToken(node)
+ const colonToken = tokenStore.getTokenAfter(labelToken)
+ const bodyToken = tokenStore.getTokenAfter(colonToken)
+
+ setOffset([colonToken, bodyToken], 1, labelToken)
+ },
+ /** @param {MemberExpression | MetaProperty} node */
+ 'MemberExpression, MetaProperty'(node) {
+ const objectToken = tokenStore.getFirstToken(node)
+ if (node.type === 'MemberExpression' && node.computed) {
+ const leftBracketToken = /** @type {Token} */ (tokenStore.getTokenBefore(
+ node.property,
+ isLeftBracket
+ ))
+ 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)
+ }
+ },
+ /** @param {MethodDefinition | Property} node */
+ 'MethodDefinition, Property'(node) {
+ 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])
+ }
+
+ /** @type {Token} */
+ let lastKeyToken
+ if (node.computed) {
+ const keyLeftToken = /** @type {Token} */ (tokenStore.getFirstToken(
+ node,
+ isLeftBracket
+ ))
+ const keyToken = tokenStore.getTokenAfter(keyLeftToken)
+ const keyRightToken = (lastKeyToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.key,
+ isRightBracket
+ )))
+
+ if (hasPrefix) {
+ setOffset(keyLeftToken, 0, /** @type {Token} */ (last(prefixTokens)))
+ }
+ setOffset(keyToken, 1, keyLeftToken)
+ setOffset(keyRightToken, 0, keyLeftToken)
+ } else {
+ const idToken = (lastKeyToken = tokenStore.getFirstToken(node.key))
+
+ if (hasPrefix) {
+ setOffset(idToken, 0, /** @type {Token} */ (last(prefixTokens)))
+ }
+ }
+
+ 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)
+ }
+ },
+ /** @param {NewExpression} node */
+ NewExpression(node) {
+ 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)
+ }
+ },
+ /** @param {ObjectExpression | ObjectPattern} node */
+ 'ObjectExpression, ObjectPattern'(node) {
+ processNodeList(
+ node.properties,
+ tokenStore.getFirstToken(node),
+ tokenStore.getLastToken(node),
+ 1
+ )
+ },
+ /** @param {SequenceExpression} node */
+ SequenceExpression(node) {
+ processNodeList(node.expressions, null, null, 0)
+ },
+ /** @param {SwitchCase} node */
+ SwitchCase(node) {
+ 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)
+ }
+ },
+ /** @param {SwitchStatement} node */
+ SwitchStatement(node) {
+ const switchToken = tokenStore.getFirstToken(node)
+ const leftParenToken = tokenStore.getTokenAfter(switchToken)
+ const discriminantToken = tokenStore.getTokenAfter(leftParenToken)
+ const leftBraceToken = /** @type {Token} */ (tokenStore.getTokenAfter(
+ node.discriminant,
+ isLeftBrace
+ ))
+ 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
+ )
+ },
+ /** @param {TaggedTemplateExpression} node */
+ TaggedTemplateExpression(node) {
+ const tagTokens = getFirstAndLastTokens(node.tag, node.range[0])
+ const quasiToken = tokenStore.getTokenAfter(tagTokens.lastToken)
+
+ setOffset(quasiToken, 1, tagTokens.firstToken)
+ },
+ /** @param {TemplateLiteral} node */
+ TemplateLiteral(node) {
+ 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)
+ },
+ /** @param {TryStatement} node */
+ TryStatement(node) {
+ 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)
+ }
+ },
+ /** @param {UpdateExpression} node */
+ UpdateExpression(node) {
+ const firstToken = tokenStore.getFirstToken(node)
+ const nextToken = tokenStore.getTokenAfter(firstToken)
+
+ setOffset(nextToken, 1, firstToken)
+ },
+ /** @param {VariableDeclaration} node */
+ VariableDeclaration(node) {
+ processNodeList(
+ node.declarations,
+ tokenStore.getFirstToken(node),
+ null,
+ 1
+ )
+ },
+ /** @param {VariableDeclarator} node */
+ VariableDeclarator(node) {
+ 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)
+ }
+ },
+ /** @param {WhileStatement | WithStatement} node */
+ 'WhileStatement, WithStatement'(node) {
+ 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)
+ },
+ /** @param {YieldExpression} node */
+ YieldExpression(node) {
+ 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)
+ }
+ }
+ },
+ /** @param {Statement} node */
+ // Process semicolons.
+ ':statement'(node) {
+ 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)
+ }
+ },
+ /** @param {Expression | MetaProperty | TemplateLiteral} node */
+ // Process parentheses.
+ // `:expression` does not match with MetaProperty and TemplateLiteral as a bug: https://github.com/estools/esquery/pull/59
+ ':expression, MetaProperty, TemplateLiteral'(node) {
+ 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)
+ }
+ },
+ /** @param {ASTNode} node */
+ // Ignore tokens of unknown nodes.
+ '*:exit'(node) {
+ if (
+ !KNOWN_NODES.has(node.type) &&
+ !NON_STANDARD_KNOWN_NODES.has(node.type)
+ ) {
+ ignore(node)
+ }
+ },
+ /** @param {Program} node */
+ // Top-level process.
+ Program(node) {
+ 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)
+ }
+ },
+ /** @param {VElement} node */
+ "VElement[parent.type!='VElement']"(node) {
+ processTopLevelNode(node, 0)
+ },
+ /** @param {Program | VElement} node */
+ // Do validation.
+ ":matches(Program, VElement[parent.type!='VElement']):exit"(node) {
+ let comments = []
+ /** @type {Token[]} */
+ let tokensOnSameLine = []
+ 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 =
+ /** @type {Token} */ (last(tokensOnSameLine)).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 =
+ /** @type {Token} */ (last(tokensOnSameLine)).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..6f77ab61
--- /dev/null
+++ b/src/eslint-plugins/utils/index.ts
@@ -0,0 +1,2068 @@
+/**
+ * @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";
+
+ /**
+ * @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'))
+ const path = require('path')
+ const vueEslintParser = require('vue-eslint-parser')
+ const { findVariable } = require('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..3defe3bf
--- /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..2b71bc2f
--- /dev/null
+++ b/src/eslint-plugins/utils/regexp.ts
@@ -0,0 +1,35 @@
+const RE_REGEXP_CHAR = /[\\^$.*+?()[\]{}|]/gu
+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])
+ }
+ 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"
+]
From 0c903df4eb1ac04993b981e08d3002e75c86b617 Mon Sep 17 00:00:00 2001
From: tyankatsu <frips.ryilsufupe+dev@gmail.com>
Date: Sat, 8 May 2021 01:15:36 +0900
Subject: [PATCH 3/4] feat: change to ts
---
src/eslint-plugins/utils/casing.js | 203 -
src/eslint-plugins/utils/casing.ts | 165 +
src/eslint-plugins/utils/html-comments.js | 259 --
src/eslint-plugins/utils/html-comments.ts | 276 ++
src/eslint-plugins/utils/indent-common.ts | 3867 +++++++++--------
src/eslint-plugins/utils/index.ts | 237 +-
src/eslint-plugins/utils/keycode-to-key.ts | 182 +-
src/eslint-plugins/utils/regexp.ts | 19 +-
typings/eslint-utils/index.d.ts | 81 +
typings/eslint/index.d.ts | 431 ++
typings/eslint/lib/rules/accessor-pairs.d.ts | 3 +
.../lib/rules/array-bracket-newline.d.ts | 3 +
.../lib/rules/array-bracket-spacing.d.ts | 3 +
.../lib/rules/array-callback-return.d.ts | 3 +
.../lib/rules/array-element-newline.d.ts | 3 +
.../eslint/lib/rules/arrow-body-style.d.ts | 3 +
typings/eslint/lib/rules/arrow-parens.d.ts | 3 +
typings/eslint/lib/rules/arrow-spacing.d.ts | 3 +
.../eslint/lib/rules/block-scoped-var.d.ts | 3 +
typings/eslint/lib/rules/block-spacing.d.ts | 3 +
typings/eslint/lib/rules/brace-style.d.ts | 3 +
typings/eslint/lib/rules/callback-return.d.ts | 3 +
typings/eslint/lib/rules/camelcase.d.ts | 3 +
.../lib/rules/capitalized-comments.d.ts | 3 +
.../lib/rules/class-methods-use-this.d.ts | 3 +
typings/eslint/lib/rules/comma-dangle.d.ts | 3 +
typings/eslint/lib/rules/comma-spacing.d.ts | 3 +
typings/eslint/lib/rules/comma-style.d.ts | 3 +
typings/eslint/lib/rules/complexity.d.ts | 3 +
.../lib/rules/computed-property-spacing.d.ts | 3 +
.../eslint/lib/rules/consistent-return.d.ts | 3 +
typings/eslint/lib/rules/consistent-this.d.ts | 3 +
.../eslint/lib/rules/constructor-super.d.ts | 3 +
typings/eslint/lib/rules/curly.d.ts | 3 +
.../eslint/lib/rules/default-case-last.d.ts | 3 +
typings/eslint/lib/rules/default-case.d.ts | 3 +
.../eslint/lib/rules/default-param-last.d.ts | 3 +
typings/eslint/lib/rules/dot-location.d.ts | 3 +
typings/eslint/lib/rules/dot-notation.d.ts | 3 +
typings/eslint/lib/rules/eol-last.d.ts | 3 +
typings/eslint/lib/rules/eqeqeq.d.ts | 3 +
typings/eslint/lib/rules/for-direction.d.ts | 3 +
.../eslint/lib/rules/func-call-spacing.d.ts | 3 +
.../eslint/lib/rules/func-name-matching.d.ts | 3 +
typings/eslint/lib/rules/func-names.d.ts | 3 +
typings/eslint/lib/rules/func-style.d.ts | 3 +
.../rules/function-call-argument-newline.d.ts | 3 +
.../lib/rules/function-paren-newline.d.ts | 3 +
.../lib/rules/generator-star-spacing.d.ts | 3 +
typings/eslint/lib/rules/getter-return.d.ts | 3 +
typings/eslint/lib/rules/global-require.d.ts | 3 +
.../lib/rules/grouped-accessor-pairs.d.ts | 3 +
typings/eslint/lib/rules/guard-for-in.d.ts | 3 +
.../eslint/lib/rules/handle-callback-err.d.ts | 3 +
typings/eslint/lib/rules/id-blacklist.d.ts | 3 +
typings/eslint/lib/rules/id-length.d.ts | 3 +
typings/eslint/lib/rules/id-match.d.ts | 3 +
.../lib/rules/implicit-arrow-linebreak.d.ts | 3 +
typings/eslint/lib/rules/indent-legacy.d.ts | 3 +
typings/eslint/lib/rules/indent.d.ts | 3 +
.../eslint/lib/rules/init-declarations.d.ts | 3 +
typings/eslint/lib/rules/jsx-quotes.d.ts | 3 +
typings/eslint/lib/rules/key-spacing.d.ts | 3 +
typings/eslint/lib/rules/keyword-spacing.d.ts | 3 +
.../lib/rules/line-comment-position.d.ts | 3 +
typings/eslint/lib/rules/linebreak-style.d.ts | 3 +
.../lib/rules/lines-around-comment.d.ts | 3 +
.../lib/rules/lines-around-directive.d.ts | 3 +
.../rules/lines-between-class-members.d.ts | 3 +
.../lib/rules/max-classes-per-file.d.ts | 3 +
typings/eslint/lib/rules/max-depth.d.ts | 3 +
typings/eslint/lib/rules/max-len.d.ts | 3 +
.../lib/rules/max-lines-per-function.d.ts | 3 +
typings/eslint/lib/rules/max-lines.d.ts | 3 +
.../lib/rules/max-nested-callbacks.d.ts | 3 +
typings/eslint/lib/rules/max-params.d.ts | 3 +
.../lib/rules/max-statements-per-line.d.ts | 3 +
typings/eslint/lib/rules/max-statements.d.ts | 3 +
.../lib/rules/multiline-comment-style.d.ts | 3 +
.../eslint/lib/rules/multiline-ternary.d.ts | 3 +
typings/eslint/lib/rules/new-cap.d.ts | 3 +
typings/eslint/lib/rules/new-parens.d.ts | 3 +
.../eslint/lib/rules/newline-after-var.d.ts | 3 +
.../lib/rules/newline-before-return.d.ts | 3 +
.../lib/rules/newline-per-chained-call.d.ts | 3 +
typings/eslint/lib/rules/no-alert.d.ts | 3 +
.../lib/rules/no-array-constructor.d.ts | 3 +
.../lib/rules/no-async-promise-executor.d.ts | 3 +
.../eslint/lib/rules/no-await-in-loop.d.ts | 3 +
typings/eslint/lib/rules/no-bitwise.d.ts | 3 +
.../lib/rules/no-buffer-constructor.d.ts | 3 +
typings/eslint/lib/rules/no-caller.d.ts | 3 +
.../lib/rules/no-case-declarations.d.ts | 3 +
typings/eslint/lib/rules/no-catch-shadow.d.ts | 3 +
typings/eslint/lib/rules/no-class-assign.d.ts | 3 +
.../eslint/lib/rules/no-compare-neg-zero.d.ts | 3 +
typings/eslint/lib/rules/no-cond-assign.d.ts | 3 +
.../eslint/lib/rules/no-confusing-arrow.d.ts | 3 +
typings/eslint/lib/rules/no-console.d.ts | 3 +
typings/eslint/lib/rules/no-const-assign.d.ts | 3 +
.../lib/rules/no-constant-condition.d.ts | 3 +
.../lib/rules/no-constructor-return.d.ts | 3 +
typings/eslint/lib/rules/no-continue.d.ts | 3 +
.../eslint/lib/rules/no-control-regex.d.ts | 3 +
typings/eslint/lib/rules/no-debugger.d.ts | 3 +
typings/eslint/lib/rules/no-delete-var.d.ts | 3 +
typings/eslint/lib/rules/no-div-regex.d.ts | 3 +
typings/eslint/lib/rules/no-dupe-args.d.ts | 3 +
.../lib/rules/no-dupe-class-members.d.ts | 3 +
typings/eslint/lib/rules/no-dupe-else-if.d.ts | 3 +
typings/eslint/lib/rules/no-dupe-keys.d.ts | 3 +
.../eslint/lib/rules/no-duplicate-case.d.ts | 3 +
.../lib/rules/no-duplicate-imports.d.ts | 3 +
typings/eslint/lib/rules/no-else-return.d.ts | 3 +
.../lib/rules/no-empty-character-class.d.ts | 3 +
.../eslint/lib/rules/no-empty-function.d.ts | 3 +
.../eslint/lib/rules/no-empty-pattern.d.ts | 3 +
typings/eslint/lib/rules/no-empty.d.ts | 3 +
typings/eslint/lib/rules/no-eq-null.d.ts | 3 +
typings/eslint/lib/rules/no-eval.d.ts | 3 +
typings/eslint/lib/rules/no-ex-assign.d.ts | 3 +
.../eslint/lib/rules/no-extend-native.d.ts | 3 +
typings/eslint/lib/rules/no-extra-bind.d.ts | 3 +
.../lib/rules/no-extra-boolean-cast.d.ts | 3 +
typings/eslint/lib/rules/no-extra-label.d.ts | 3 +
typings/eslint/lib/rules/no-extra-parens.d.ts | 3 +
typings/eslint/lib/rules/no-extra-semi.d.ts | 3 +
typings/eslint/lib/rules/no-fallthrough.d.ts | 3 +
.../eslint/lib/rules/no-floating-decimal.d.ts | 3 +
typings/eslint/lib/rules/no-func-assign.d.ts | 3 +
.../eslint/lib/rules/no-global-assign.d.ts | 3 +
.../lib/rules/no-implicit-coercion.d.ts | 3 +
.../eslint/lib/rules/no-implicit-globals.d.ts | 3 +
typings/eslint/lib/rules/no-implied-eval.d.ts | 3 +
.../eslint/lib/rules/no-import-assign.d.ts | 3 +
.../eslint/lib/rules/no-inline-comments.d.ts | 3 +
.../lib/rules/no-inner-declarations.d.ts | 3 +
.../eslint/lib/rules/no-invalid-regexp.d.ts | 3 +
typings/eslint/lib/rules/no-invalid-this.d.ts | 3 +
.../lib/rules/no-irregular-whitespace.d.ts | 3 +
typings/eslint/lib/rules/no-iterator.d.ts | 3 +
typings/eslint/lib/rules/no-label-var.d.ts | 3 +
typings/eslint/lib/rules/no-labels.d.ts | 3 +
typings/eslint/lib/rules/no-lone-blocks.d.ts | 3 +
typings/eslint/lib/rules/no-lonely-if.d.ts | 3 +
typings/eslint/lib/rules/no-loop-func.d.ts | 3 +
.../lib/rules/no-loss-of-precision.d.ts | 3 +
.../eslint/lib/rules/no-magic-numbers.d.ts | 3 +
.../rules/no-misleading-character-class.d.ts | 3 +
.../eslint/lib/rules/no-mixed-operators.d.ts | 3 +
.../eslint/lib/rules/no-mixed-requires.d.ts | 3 +
.../lib/rules/no-mixed-spaces-and-tabs.d.ts | 3 +
typings/eslint/lib/rules/no-multi-assign.d.ts | 3 +
typings/eslint/lib/rules/no-multi-spaces.d.ts | 3 +
typings/eslint/lib/rules/no-multi-str.d.ts | 3 +
.../lib/rules/no-multiple-empty-lines.d.ts | 3 +
.../eslint/lib/rules/no-native-reassign.d.ts | 3 +
.../lib/rules/no-negated-condition.d.ts | 3 +
.../eslint/lib/rules/no-negated-in-lhs.d.ts | 3 +
.../eslint/lib/rules/no-nested-ternary.d.ts | 3 +
typings/eslint/lib/rules/no-new-func.d.ts | 3 +
typings/eslint/lib/rules/no-new-object.d.ts | 3 +
typings/eslint/lib/rules/no-new-require.d.ts | 3 +
typings/eslint/lib/rules/no-new-symbol.d.ts | 3 +
typings/eslint/lib/rules/no-new-wrappers.d.ts | 3 +
typings/eslint/lib/rules/no-new.d.ts | 3 +
typings/eslint/lib/rules/no-obj-calls.d.ts | 3 +
typings/eslint/lib/rules/no-octal-escape.d.ts | 3 +
typings/eslint/lib/rules/no-octal.d.ts | 3 +
.../eslint/lib/rules/no-param-reassign.d.ts | 3 +
typings/eslint/lib/rules/no-path-concat.d.ts | 3 +
typings/eslint/lib/rules/no-plusplus.d.ts | 3 +
typings/eslint/lib/rules/no-process-env.d.ts | 3 +
typings/eslint/lib/rules/no-process-exit.d.ts | 3 +
.../lib/rules/no-promise-executor-return.d.ts | 3 +
typings/eslint/lib/rules/no-proto.d.ts | 3 +
.../lib/rules/no-prototype-builtins.d.ts | 3 +
typings/eslint/lib/rules/no-redeclare.d.ts | 3 +
typings/eslint/lib/rules/no-regex-spaces.d.ts | 3 +
.../lib/rules/no-restricted-exports.d.ts | 3 +
.../lib/rules/no-restricted-globals.d.ts | 3 +
.../lib/rules/no-restricted-imports.d.ts | 3 +
.../lib/rules/no-restricted-modules.d.ts | 3 +
.../lib/rules/no-restricted-properties.d.ts | 3 +
.../lib/rules/no-restricted-syntax.d.ts | 3 +
.../eslint/lib/rules/no-return-assign.d.ts | 3 +
typings/eslint/lib/rules/no-return-await.d.ts | 3 +
typings/eslint/lib/rules/no-script-url.d.ts | 3 +
typings/eslint/lib/rules/no-self-assign.d.ts | 3 +
typings/eslint/lib/rules/no-self-compare.d.ts | 3 +
typings/eslint/lib/rules/no-sequences.d.ts | 3 +
.../eslint/lib/rules/no-setter-return.d.ts | 3 +
.../lib/rules/no-shadow-restricted-names.d.ts | 3 +
typings/eslint/lib/rules/no-shadow.d.ts | 3 +
typings/eslint/lib/rules/no-spaced-func.d.ts | 3 +
.../eslint/lib/rules/no-sparse-arrays.d.ts | 3 +
typings/eslint/lib/rules/no-sync.d.ts | 3 +
typings/eslint/lib/rules/no-tabs.d.ts | 3 +
.../rules/no-template-curly-in-string.d.ts | 3 +
typings/eslint/lib/rules/no-ternary.d.ts | 3 +
.../lib/rules/no-this-before-super.d.ts | 3 +
.../eslint/lib/rules/no-throw-literal.d.ts | 3 +
.../eslint/lib/rules/no-trailing-spaces.d.ts | 3 +
typings/eslint/lib/rules/no-undef-init.d.ts | 3 +
typings/eslint/lib/rules/no-undef.d.ts | 3 +
typings/eslint/lib/rules/no-undefined.d.ts | 3 +
.../lib/rules/no-underscore-dangle.d.ts | 3 +
.../lib/rules/no-unexpected-multiline.d.ts | 3 +
.../rules/no-unmodified-loop-condition.d.ts | 3 +
.../eslint/lib/rules/no-unneeded-ternary.d.ts | 3 +
.../eslint/lib/rules/no-unreachable-loop.d.ts | 3 +
typings/eslint/lib/rules/no-unreachable.d.ts | 3 +
.../eslint/lib/rules/no-unsafe-finally.d.ts | 3 +
.../eslint/lib/rules/no-unsafe-negation.d.ts | 3 +
.../lib/rules/no-unused-expressions.d.ts | 3 +
.../eslint/lib/rules/no-unused-labels.d.ts | 3 +
typings/eslint/lib/rules/no-unused-vars.d.ts | 3 +
.../lib/rules/no-use-before-define.d.ts | 3 +
.../lib/rules/no-useless-backreference.d.ts | 3 +
typings/eslint/lib/rules/no-useless-call.d.ts | 3 +
.../eslint/lib/rules/no-useless-catch.d.ts | 3 +
.../lib/rules/no-useless-computed-key.d.ts | 3 +
.../eslint/lib/rules/no-useless-concat.d.ts | 3 +
.../lib/rules/no-useless-constructor.d.ts | 3 +
.../eslint/lib/rules/no-useless-escape.d.ts | 3 +
.../eslint/lib/rules/no-useless-rename.d.ts | 3 +
.../eslint/lib/rules/no-useless-return.d.ts | 3 +
typings/eslint/lib/rules/no-var.d.ts | 3 +
typings/eslint/lib/rules/no-void.d.ts | 3 +
.../eslint/lib/rules/no-warning-comments.d.ts | 3 +
.../rules/no-whitespace-before-property.d.ts | 3 +
typings/eslint/lib/rules/no-with.d.ts | 3 +
.../nonblock-statement-body-position.d.ts | 3 +
.../lib/rules/object-curly-newline.d.ts | 3 +
.../lib/rules/object-curly-spacing.d.ts | 3 +
.../lib/rules/object-property-newline.d.ts | 3 +
.../eslint/lib/rules/object-shorthand.d.ts | 3 +
.../rules/one-var-declaration-per-line.d.ts | 3 +
typings/eslint/lib/rules/one-var.d.ts | 3 +
.../eslint/lib/rules/operator-assignment.d.ts | 3 +
.../eslint/lib/rules/operator-linebreak.d.ts | 3 +
typings/eslint/lib/rules/padded-blocks.d.ts | 3 +
.../padding-line-between-statements.d.ts | 3 +
.../lib/rules/prefer-arrow-callback.d.ts | 3 +
typings/eslint/lib/rules/prefer-const.d.ts | 3 +
.../lib/rules/prefer-destructuring.d.ts | 3 +
.../rules/prefer-exponentiation-operator.d.ts | 3 +
.../lib/rules/prefer-named-capture-group.d.ts | 3 +
.../lib/rules/prefer-numeric-literals.d.ts | 3 +
.../lib/rules/prefer-object-spread.d.ts | 3 +
.../rules/prefer-promise-reject-errors.d.ts | 3 +
typings/eslint/lib/rules/prefer-reflect.d.ts | 3 +
.../lib/rules/prefer-regex-literals.d.ts | 3 +
.../eslint/lib/rules/prefer-rest-params.d.ts | 3 +
typings/eslint/lib/rules/prefer-spread.d.ts | 3 +
typings/eslint/lib/rules/prefer-template.d.ts | 3 +
typings/eslint/lib/rules/quote-props.d.ts | 3 +
typings/eslint/lib/rules/quotes.d.ts | 3 +
typings/eslint/lib/rules/radix.d.ts | 3 +
.../lib/rules/require-atomic-updates.d.ts | 3 +
typings/eslint/lib/rules/require-await.d.ts | 3 +
typings/eslint/lib/rules/require-jsdoc.d.ts | 3 +
.../lib/rules/require-unicode-regexp.d.ts | 3 +
typings/eslint/lib/rules/require-yield.d.ts | 3 +
.../eslint/lib/rules/rest-spread-spacing.d.ts | 3 +
typings/eslint/lib/rules/semi-spacing.d.ts | 3 +
typings/eslint/lib/rules/semi-style.d.ts | 3 +
typings/eslint/lib/rules/semi.d.ts | 3 +
typings/eslint/lib/rules/sort-imports.d.ts | 3 +
typings/eslint/lib/rules/sort-keys.d.ts | 3 +
typings/eslint/lib/rules/sort-vars.d.ts | 3 +
.../eslint/lib/rules/space-before-blocks.d.ts | 3 +
.../rules/space-before-function-paren.d.ts | 3 +
typings/eslint/lib/rules/space-in-parens.d.ts | 3 +
typings/eslint/lib/rules/space-infix-ops.d.ts | 3 +
typings/eslint/lib/rules/space-unary-ops.d.ts | 3 +
typings/eslint/lib/rules/spaced-comment.d.ts | 3 +
typings/eslint/lib/rules/strict.d.ts | 3 +
.../lib/rules/switch-colon-spacing.d.ts | 3 +
.../eslint/lib/rules/symbol-description.d.ts | 3 +
.../lib/rules/template-curly-spacing.d.ts | 3 +
.../lib/rules/template-tag-spacing.d.ts | 3 +
typings/eslint/lib/rules/unicode-bom.d.ts | 3 +
typings/eslint/lib/rules/use-isnan.d.ts | 3 +
typings/eslint/lib/rules/valid-jsdoc.d.ts | 3 +
typings/eslint/lib/rules/valid-typeof.d.ts | 3 +
typings/eslint/lib/rules/vars-on-top.d.ts | 3 +
typings/eslint/lib/rules/wrap-iife.d.ts | 3 +
typings/eslint/lib/rules/wrap-regex.d.ts | 3 +
.../eslint/lib/rules/yield-star-spacing.d.ts | 3 +
typings/eslint/lib/rules/yoda.d.ts | 3 +
typings/vue-eslint-parser/index.d.ts | 5 +
292 files changed, 4061 insertions(+), 2507 deletions(-)
delete mode 100644 src/eslint-plugins/utils/casing.js
create mode 100644 src/eslint-plugins/utils/casing.ts
delete mode 100644 src/eslint-plugins/utils/html-comments.js
create mode 100644 src/eslint-plugins/utils/html-comments.ts
create mode 100644 typings/eslint-utils/index.d.ts
create mode 100644 typings/eslint/index.d.ts
create mode 100644 typings/eslint/lib/rules/accessor-pairs.d.ts
create mode 100644 typings/eslint/lib/rules/array-bracket-newline.d.ts
create mode 100644 typings/eslint/lib/rules/array-bracket-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/array-callback-return.d.ts
create mode 100644 typings/eslint/lib/rules/array-element-newline.d.ts
create mode 100644 typings/eslint/lib/rules/arrow-body-style.d.ts
create mode 100644 typings/eslint/lib/rules/arrow-parens.d.ts
create mode 100644 typings/eslint/lib/rules/arrow-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/block-scoped-var.d.ts
create mode 100644 typings/eslint/lib/rules/block-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/brace-style.d.ts
create mode 100644 typings/eslint/lib/rules/callback-return.d.ts
create mode 100644 typings/eslint/lib/rules/camelcase.d.ts
create mode 100644 typings/eslint/lib/rules/capitalized-comments.d.ts
create mode 100644 typings/eslint/lib/rules/class-methods-use-this.d.ts
create mode 100644 typings/eslint/lib/rules/comma-dangle.d.ts
create mode 100644 typings/eslint/lib/rules/comma-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/comma-style.d.ts
create mode 100644 typings/eslint/lib/rules/complexity.d.ts
create mode 100644 typings/eslint/lib/rules/computed-property-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/consistent-return.d.ts
create mode 100644 typings/eslint/lib/rules/consistent-this.d.ts
create mode 100644 typings/eslint/lib/rules/constructor-super.d.ts
create mode 100644 typings/eslint/lib/rules/curly.d.ts
create mode 100644 typings/eslint/lib/rules/default-case-last.d.ts
create mode 100644 typings/eslint/lib/rules/default-case.d.ts
create mode 100644 typings/eslint/lib/rules/default-param-last.d.ts
create mode 100644 typings/eslint/lib/rules/dot-location.d.ts
create mode 100644 typings/eslint/lib/rules/dot-notation.d.ts
create mode 100644 typings/eslint/lib/rules/eol-last.d.ts
create mode 100644 typings/eslint/lib/rules/eqeqeq.d.ts
create mode 100644 typings/eslint/lib/rules/for-direction.d.ts
create mode 100644 typings/eslint/lib/rules/func-call-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/func-name-matching.d.ts
create mode 100644 typings/eslint/lib/rules/func-names.d.ts
create mode 100644 typings/eslint/lib/rules/func-style.d.ts
create mode 100644 typings/eslint/lib/rules/function-call-argument-newline.d.ts
create mode 100644 typings/eslint/lib/rules/function-paren-newline.d.ts
create mode 100644 typings/eslint/lib/rules/generator-star-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/getter-return.d.ts
create mode 100644 typings/eslint/lib/rules/global-require.d.ts
create mode 100644 typings/eslint/lib/rules/grouped-accessor-pairs.d.ts
create mode 100644 typings/eslint/lib/rules/guard-for-in.d.ts
create mode 100644 typings/eslint/lib/rules/handle-callback-err.d.ts
create mode 100644 typings/eslint/lib/rules/id-blacklist.d.ts
create mode 100644 typings/eslint/lib/rules/id-length.d.ts
create mode 100644 typings/eslint/lib/rules/id-match.d.ts
create mode 100644 typings/eslint/lib/rules/implicit-arrow-linebreak.d.ts
create mode 100644 typings/eslint/lib/rules/indent-legacy.d.ts
create mode 100644 typings/eslint/lib/rules/indent.d.ts
create mode 100644 typings/eslint/lib/rules/init-declarations.d.ts
create mode 100644 typings/eslint/lib/rules/jsx-quotes.d.ts
create mode 100644 typings/eslint/lib/rules/key-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/keyword-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/line-comment-position.d.ts
create mode 100644 typings/eslint/lib/rules/linebreak-style.d.ts
create mode 100644 typings/eslint/lib/rules/lines-around-comment.d.ts
create mode 100644 typings/eslint/lib/rules/lines-around-directive.d.ts
create mode 100644 typings/eslint/lib/rules/lines-between-class-members.d.ts
create mode 100644 typings/eslint/lib/rules/max-classes-per-file.d.ts
create mode 100644 typings/eslint/lib/rules/max-depth.d.ts
create mode 100644 typings/eslint/lib/rules/max-len.d.ts
create mode 100644 typings/eslint/lib/rules/max-lines-per-function.d.ts
create mode 100644 typings/eslint/lib/rules/max-lines.d.ts
create mode 100644 typings/eslint/lib/rules/max-nested-callbacks.d.ts
create mode 100644 typings/eslint/lib/rules/max-params.d.ts
create mode 100644 typings/eslint/lib/rules/max-statements-per-line.d.ts
create mode 100644 typings/eslint/lib/rules/max-statements.d.ts
create mode 100644 typings/eslint/lib/rules/multiline-comment-style.d.ts
create mode 100644 typings/eslint/lib/rules/multiline-ternary.d.ts
create mode 100644 typings/eslint/lib/rules/new-cap.d.ts
create mode 100644 typings/eslint/lib/rules/new-parens.d.ts
create mode 100644 typings/eslint/lib/rules/newline-after-var.d.ts
create mode 100644 typings/eslint/lib/rules/newline-before-return.d.ts
create mode 100644 typings/eslint/lib/rules/newline-per-chained-call.d.ts
create mode 100644 typings/eslint/lib/rules/no-alert.d.ts
create mode 100644 typings/eslint/lib/rules/no-array-constructor.d.ts
create mode 100644 typings/eslint/lib/rules/no-async-promise-executor.d.ts
create mode 100644 typings/eslint/lib/rules/no-await-in-loop.d.ts
create mode 100644 typings/eslint/lib/rules/no-bitwise.d.ts
create mode 100644 typings/eslint/lib/rules/no-buffer-constructor.d.ts
create mode 100644 typings/eslint/lib/rules/no-caller.d.ts
create mode 100644 typings/eslint/lib/rules/no-case-declarations.d.ts
create mode 100644 typings/eslint/lib/rules/no-catch-shadow.d.ts
create mode 100644 typings/eslint/lib/rules/no-class-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-compare-neg-zero.d.ts
create mode 100644 typings/eslint/lib/rules/no-cond-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-confusing-arrow.d.ts
create mode 100644 typings/eslint/lib/rules/no-console.d.ts
create mode 100644 typings/eslint/lib/rules/no-const-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-constant-condition.d.ts
create mode 100644 typings/eslint/lib/rules/no-constructor-return.d.ts
create mode 100644 typings/eslint/lib/rules/no-continue.d.ts
create mode 100644 typings/eslint/lib/rules/no-control-regex.d.ts
create mode 100644 typings/eslint/lib/rules/no-debugger.d.ts
create mode 100644 typings/eslint/lib/rules/no-delete-var.d.ts
create mode 100644 typings/eslint/lib/rules/no-div-regex.d.ts
create mode 100644 typings/eslint/lib/rules/no-dupe-args.d.ts
create mode 100644 typings/eslint/lib/rules/no-dupe-class-members.d.ts
create mode 100644 typings/eslint/lib/rules/no-dupe-else-if.d.ts
create mode 100644 typings/eslint/lib/rules/no-dupe-keys.d.ts
create mode 100644 typings/eslint/lib/rules/no-duplicate-case.d.ts
create mode 100644 typings/eslint/lib/rules/no-duplicate-imports.d.ts
create mode 100644 typings/eslint/lib/rules/no-else-return.d.ts
create mode 100644 typings/eslint/lib/rules/no-empty-character-class.d.ts
create mode 100644 typings/eslint/lib/rules/no-empty-function.d.ts
create mode 100644 typings/eslint/lib/rules/no-empty-pattern.d.ts
create mode 100644 typings/eslint/lib/rules/no-empty.d.ts
create mode 100644 typings/eslint/lib/rules/no-eq-null.d.ts
create mode 100644 typings/eslint/lib/rules/no-eval.d.ts
create mode 100644 typings/eslint/lib/rules/no-ex-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-extend-native.d.ts
create mode 100644 typings/eslint/lib/rules/no-extra-bind.d.ts
create mode 100644 typings/eslint/lib/rules/no-extra-boolean-cast.d.ts
create mode 100644 typings/eslint/lib/rules/no-extra-label.d.ts
create mode 100644 typings/eslint/lib/rules/no-extra-parens.d.ts
create mode 100644 typings/eslint/lib/rules/no-extra-semi.d.ts
create mode 100644 typings/eslint/lib/rules/no-fallthrough.d.ts
create mode 100644 typings/eslint/lib/rules/no-floating-decimal.d.ts
create mode 100644 typings/eslint/lib/rules/no-func-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-global-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-implicit-coercion.d.ts
create mode 100644 typings/eslint/lib/rules/no-implicit-globals.d.ts
create mode 100644 typings/eslint/lib/rules/no-implied-eval.d.ts
create mode 100644 typings/eslint/lib/rules/no-import-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-inline-comments.d.ts
create mode 100644 typings/eslint/lib/rules/no-inner-declarations.d.ts
create mode 100644 typings/eslint/lib/rules/no-invalid-regexp.d.ts
create mode 100644 typings/eslint/lib/rules/no-invalid-this.d.ts
create mode 100644 typings/eslint/lib/rules/no-irregular-whitespace.d.ts
create mode 100644 typings/eslint/lib/rules/no-iterator.d.ts
create mode 100644 typings/eslint/lib/rules/no-label-var.d.ts
create mode 100644 typings/eslint/lib/rules/no-labels.d.ts
create mode 100644 typings/eslint/lib/rules/no-lone-blocks.d.ts
create mode 100644 typings/eslint/lib/rules/no-lonely-if.d.ts
create mode 100644 typings/eslint/lib/rules/no-loop-func.d.ts
create mode 100644 typings/eslint/lib/rules/no-loss-of-precision.d.ts
create mode 100644 typings/eslint/lib/rules/no-magic-numbers.d.ts
create mode 100644 typings/eslint/lib/rules/no-misleading-character-class.d.ts
create mode 100644 typings/eslint/lib/rules/no-mixed-operators.d.ts
create mode 100644 typings/eslint/lib/rules/no-mixed-requires.d.ts
create mode 100644 typings/eslint/lib/rules/no-mixed-spaces-and-tabs.d.ts
create mode 100644 typings/eslint/lib/rules/no-multi-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-multi-spaces.d.ts
create mode 100644 typings/eslint/lib/rules/no-multi-str.d.ts
create mode 100644 typings/eslint/lib/rules/no-multiple-empty-lines.d.ts
create mode 100644 typings/eslint/lib/rules/no-native-reassign.d.ts
create mode 100644 typings/eslint/lib/rules/no-negated-condition.d.ts
create mode 100644 typings/eslint/lib/rules/no-negated-in-lhs.d.ts
create mode 100644 typings/eslint/lib/rules/no-nested-ternary.d.ts
create mode 100644 typings/eslint/lib/rules/no-new-func.d.ts
create mode 100644 typings/eslint/lib/rules/no-new-object.d.ts
create mode 100644 typings/eslint/lib/rules/no-new-require.d.ts
create mode 100644 typings/eslint/lib/rules/no-new-symbol.d.ts
create mode 100644 typings/eslint/lib/rules/no-new-wrappers.d.ts
create mode 100644 typings/eslint/lib/rules/no-new.d.ts
create mode 100644 typings/eslint/lib/rules/no-obj-calls.d.ts
create mode 100644 typings/eslint/lib/rules/no-octal-escape.d.ts
create mode 100644 typings/eslint/lib/rules/no-octal.d.ts
create mode 100644 typings/eslint/lib/rules/no-param-reassign.d.ts
create mode 100644 typings/eslint/lib/rules/no-path-concat.d.ts
create mode 100644 typings/eslint/lib/rules/no-plusplus.d.ts
create mode 100644 typings/eslint/lib/rules/no-process-env.d.ts
create mode 100644 typings/eslint/lib/rules/no-process-exit.d.ts
create mode 100644 typings/eslint/lib/rules/no-promise-executor-return.d.ts
create mode 100644 typings/eslint/lib/rules/no-proto.d.ts
create mode 100644 typings/eslint/lib/rules/no-prototype-builtins.d.ts
create mode 100644 typings/eslint/lib/rules/no-redeclare.d.ts
create mode 100644 typings/eslint/lib/rules/no-regex-spaces.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-exports.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-globals.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-imports.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-modules.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-properties.d.ts
create mode 100644 typings/eslint/lib/rules/no-restricted-syntax.d.ts
create mode 100644 typings/eslint/lib/rules/no-return-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-return-await.d.ts
create mode 100644 typings/eslint/lib/rules/no-script-url.d.ts
create mode 100644 typings/eslint/lib/rules/no-self-assign.d.ts
create mode 100644 typings/eslint/lib/rules/no-self-compare.d.ts
create mode 100644 typings/eslint/lib/rules/no-sequences.d.ts
create mode 100644 typings/eslint/lib/rules/no-setter-return.d.ts
create mode 100644 typings/eslint/lib/rules/no-shadow-restricted-names.d.ts
create mode 100644 typings/eslint/lib/rules/no-shadow.d.ts
create mode 100644 typings/eslint/lib/rules/no-spaced-func.d.ts
create mode 100644 typings/eslint/lib/rules/no-sparse-arrays.d.ts
create mode 100644 typings/eslint/lib/rules/no-sync.d.ts
create mode 100644 typings/eslint/lib/rules/no-tabs.d.ts
create mode 100644 typings/eslint/lib/rules/no-template-curly-in-string.d.ts
create mode 100644 typings/eslint/lib/rules/no-ternary.d.ts
create mode 100644 typings/eslint/lib/rules/no-this-before-super.d.ts
create mode 100644 typings/eslint/lib/rules/no-throw-literal.d.ts
create mode 100644 typings/eslint/lib/rules/no-trailing-spaces.d.ts
create mode 100644 typings/eslint/lib/rules/no-undef-init.d.ts
create mode 100644 typings/eslint/lib/rules/no-undef.d.ts
create mode 100644 typings/eslint/lib/rules/no-undefined.d.ts
create mode 100644 typings/eslint/lib/rules/no-underscore-dangle.d.ts
create mode 100644 typings/eslint/lib/rules/no-unexpected-multiline.d.ts
create mode 100644 typings/eslint/lib/rules/no-unmodified-loop-condition.d.ts
create mode 100644 typings/eslint/lib/rules/no-unneeded-ternary.d.ts
create mode 100644 typings/eslint/lib/rules/no-unreachable-loop.d.ts
create mode 100644 typings/eslint/lib/rules/no-unreachable.d.ts
create mode 100644 typings/eslint/lib/rules/no-unsafe-finally.d.ts
create mode 100644 typings/eslint/lib/rules/no-unsafe-negation.d.ts
create mode 100644 typings/eslint/lib/rules/no-unused-expressions.d.ts
create mode 100644 typings/eslint/lib/rules/no-unused-labels.d.ts
create mode 100644 typings/eslint/lib/rules/no-unused-vars.d.ts
create mode 100644 typings/eslint/lib/rules/no-use-before-define.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-backreference.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-call.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-catch.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-computed-key.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-concat.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-constructor.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-escape.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-rename.d.ts
create mode 100644 typings/eslint/lib/rules/no-useless-return.d.ts
create mode 100644 typings/eslint/lib/rules/no-var.d.ts
create mode 100644 typings/eslint/lib/rules/no-void.d.ts
create mode 100644 typings/eslint/lib/rules/no-warning-comments.d.ts
create mode 100644 typings/eslint/lib/rules/no-whitespace-before-property.d.ts
create mode 100644 typings/eslint/lib/rules/no-with.d.ts
create mode 100644 typings/eslint/lib/rules/nonblock-statement-body-position.d.ts
create mode 100644 typings/eslint/lib/rules/object-curly-newline.d.ts
create mode 100644 typings/eslint/lib/rules/object-curly-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/object-property-newline.d.ts
create mode 100644 typings/eslint/lib/rules/object-shorthand.d.ts
create mode 100644 typings/eslint/lib/rules/one-var-declaration-per-line.d.ts
create mode 100644 typings/eslint/lib/rules/one-var.d.ts
create mode 100644 typings/eslint/lib/rules/operator-assignment.d.ts
create mode 100644 typings/eslint/lib/rules/operator-linebreak.d.ts
create mode 100644 typings/eslint/lib/rules/padded-blocks.d.ts
create mode 100644 typings/eslint/lib/rules/padding-line-between-statements.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-arrow-callback.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-const.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-destructuring.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-exponentiation-operator.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-named-capture-group.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-numeric-literals.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-object-spread.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-promise-reject-errors.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-reflect.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-regex-literals.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-rest-params.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-spread.d.ts
create mode 100644 typings/eslint/lib/rules/prefer-template.d.ts
create mode 100644 typings/eslint/lib/rules/quote-props.d.ts
create mode 100644 typings/eslint/lib/rules/quotes.d.ts
create mode 100644 typings/eslint/lib/rules/radix.d.ts
create mode 100644 typings/eslint/lib/rules/require-atomic-updates.d.ts
create mode 100644 typings/eslint/lib/rules/require-await.d.ts
create mode 100644 typings/eslint/lib/rules/require-jsdoc.d.ts
create mode 100644 typings/eslint/lib/rules/require-unicode-regexp.d.ts
create mode 100644 typings/eslint/lib/rules/require-yield.d.ts
create mode 100644 typings/eslint/lib/rules/rest-spread-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/semi-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/semi-style.d.ts
create mode 100644 typings/eslint/lib/rules/semi.d.ts
create mode 100644 typings/eslint/lib/rules/sort-imports.d.ts
create mode 100644 typings/eslint/lib/rules/sort-keys.d.ts
create mode 100644 typings/eslint/lib/rules/sort-vars.d.ts
create mode 100644 typings/eslint/lib/rules/space-before-blocks.d.ts
create mode 100644 typings/eslint/lib/rules/space-before-function-paren.d.ts
create mode 100644 typings/eslint/lib/rules/space-in-parens.d.ts
create mode 100644 typings/eslint/lib/rules/space-infix-ops.d.ts
create mode 100644 typings/eslint/lib/rules/space-unary-ops.d.ts
create mode 100644 typings/eslint/lib/rules/spaced-comment.d.ts
create mode 100644 typings/eslint/lib/rules/strict.d.ts
create mode 100644 typings/eslint/lib/rules/switch-colon-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/symbol-description.d.ts
create mode 100644 typings/eslint/lib/rules/template-curly-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/template-tag-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/unicode-bom.d.ts
create mode 100644 typings/eslint/lib/rules/use-isnan.d.ts
create mode 100644 typings/eslint/lib/rules/valid-jsdoc.d.ts
create mode 100644 typings/eslint/lib/rules/valid-typeof.d.ts
create mode 100644 typings/eslint/lib/rules/vars-on-top.d.ts
create mode 100644 typings/eslint/lib/rules/wrap-iife.d.ts
create mode 100644 typings/eslint/lib/rules/wrap-regex.d.ts
create mode 100644 typings/eslint/lib/rules/yield-star-spacing.d.ts
create mode 100644 typings/eslint/lib/rules/yoda.d.ts
create mode 100644 typings/vue-eslint-parser/index.d.ts
diff --git a/src/eslint-plugins/utils/casing.js b/src/eslint-plugins/utils/casing.js
deleted file mode 100644
index b2f2e89b..00000000
--- a/src/eslint-plugins/utils/casing.js
+++ /dev/null
@@ -1,203 +0,0 @@
-// ------------------------------------------------------------------------------
-// Helpers
-// ------------------------------------------------------------------------------
-
-/**
- * Capitalize a string.
- * @param {string} str
- */
-function capitalize(str) {
- return str.charAt(0).toUpperCase() + str.slice(1)
-}
-/**
- * Checks whether the given string has symbols.
- * @param {string} str
- */
-function hasSymbols(str) {
- return /[!"#%&'()*+,./:;<=>?@[\\\]^`{|}]/u.exec(str) // without " ", "$", "-" and "_"
-}
-/**
- * Checks whether the given string has upper.
- * @param {string} str
- */
-function hasUpper(str) {
- return /[A-Z]/u.exec(str)
-}
-
-/**
- * Convert text to kebab-case
- * @param {string} str Text to be converted
- * @return {string}
- */
-function kebabCase(str) {
- return str
- .replace(/_/gu, '-')
- .replace(/\B([A-Z])/gu, '-$1')
- .toLowerCase()
-}
-
-/**
- * Checks whether the given string is kebab-case.
- * @param {string} str
- */
-function isKebabCase(str) {
- 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 {string} str Text to be converted
- * @return {string}
- */
-function snakeCase(str) {
- return str
- .replace(/\B([A-Z])/gu, '_$1')
- .replace(/-/gu, '_')
- .toLowerCase()
-}
-
-/**
- * Checks whether the given string is snake_case.
- * @param {string} str
- */
-function isSnakeCase(str) {
- if (hasUpper(str) || hasSymbols(str) || /-|__|\s/u.exec(str)) {
- return false
- }
- return true
-}
-
-/**
- * Convert text to camelCase
- * @param {string} str Text to be converted
- * @return {string} Converted string
- */
-function camelCase(str) {
- 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.
- * @param {string} str
- */
-function isCamelCase(str) {
- 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 {string} str Text to be converted
- * @return {string} Converted string
- */
-function pascalCase(str) {
- return capitalize(camelCase(str))
-}
-
-/**
- * Checks whether the given string is PascalCase.
- * @param {string} str
- */
-function isPascalCase(str) {
- 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,
- snake_case: snakeCase,
- camelCase,
- PascalCase: pascalCase
-}
-
-const checkersMap = {
- 'kebab-case': isKebabCase,
- snake_case: isSnakeCase,
- camelCase: isCamelCase,
- PascalCase: isPascalCase
-}
-/**
- * Return case checker
- * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of checker to return ('camelCase', 'kebab-case', 'PascalCase')
- * @return {isKebabCase|isCamelCase|isPascalCase|isSnakeCase}
- */
-function getChecker(name) {
- return checkersMap[name] || isPascalCase
-}
-
-/**
- * Return case converter
- * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
- * @return {kebabCase|camelCase|pascalCase|snakeCase}
- */
-function getConverter(name) {
- return convertersMap[name] || pascalCase
-}
-
-module.exports = {
- allowedCaseOptions: ['camelCase', 'kebab-case', 'PascalCase'],
-
- /**
- * Return case converter
- * @param {string} name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
- * @return {kebabCase|camelCase|pascalCase|snakeCase}
- */
- getConverter,
-
- /**
- * Return case checker
- * @param {string} name type of checker to return ('camelCase', 'kebab-case', 'PascalCase')
- * @return {isKebabCase|isCamelCase|isPascalCase|isSnakeCase}
- */
- getChecker,
-
- /**
- * Return case exact converter.
- * If the converted result is not the correct case, the original value is returned.
- * @param { 'camelCase' | 'kebab-case' | 'PascalCase' | 'snake_case' } name type of converter to return ('camelCase', 'kebab-case', 'PascalCase')
- * @return {kebabCase|camelCase|pascalCase|snakeCase}
- */
- getExactConverter(name) {
- const converter = getConverter(name)
- const checker = getChecker(name)
- return (str) => {
- const result = converter(str)
- return checker(result) ? result : str /* cannot convert */
- }
- },
-
- camelCase,
- pascalCase,
- kebabCase,
- snakeCase,
-
- isCamelCase,
- isPascalCase,
- isKebabCase,
- isSnakeCase,
-
- capitalize
-}
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/html-comments.js b/src/eslint-plugins/utils/html-comments.js
deleted file mode 100644
index aced46e7..00000000
--- a/src/eslint-plugins/utils/html-comments.js
+++ /dev/null
@@ -1,259 +0,0 @@
-/**
- * @typedef { { exceptions?: string[] } } CommentParserConfig
- * @typedef { (comment: ParsedHTMLComment) => void } HTMLCommentVisitor
- * @typedef { { includeDirectives?: boolean } } CommentVisitorOption
- *
- * @typedef { Token & { type: 'HTMLCommentOpen' } } HTMLCommentOpen
- * @typedef { Token & { type: 'HTMLCommentOpenDecoration' } } HTMLCommentOpenDecoration
- * @typedef { Token & { type: 'HTMLCommentValue' } } HTMLCommentValue
- * @typedef { Token & { type: 'HTMLCommentClose' } } HTMLCommentClose
- * @typedef { Token & { type: 'HTMLCommentCloseDecoration' } } HTMLCommentCloseDecoration
- * @typedef { { open: HTMLCommentOpen, openDecoration: HTMLCommentOpenDecoration | null, value: HTMLCommentValue | null, closeDecoration: HTMLCommentCloseDecoration | null, close: HTMLCommentClose } } ParsedHTMLComment
- */
-// -----------------------------------------------------------------------------
-// Requirements
-// -----------------------------------------------------------------------------
-
-const utils = require('./')
-
-// ------------------------------------------------------------------------------
-// Helpers
-// ------------------------------------------------------------------------------
-
-const COMMENT_DIRECTIVE = /^\s*eslint-(?:en|dis)able/
-const IE_CONDITIONAL_IF = /^\[if\s+/
-const IE_CONDITIONAL_ENDIF = /\[endif\]$/
-
-/** @type { 'HTMLCommentOpen' } */
-const TYPE_HTML_COMMENT_OPEN = 'HTMLCommentOpen'
-/** @type { 'HTMLCommentOpenDecoration' } */
-const TYPE_HTML_COMMENT_OPEN_DECORATION = 'HTMLCommentOpenDecoration'
-/** @type { 'HTMLCommentValue' } */
-const TYPE_HTML_COMMENT_VALUE = 'HTMLCommentValue'
-/** @type { 'HTMLCommentClose' } */
-const TYPE_HTML_COMMENT_CLOSE = 'HTMLCommentClose'
-/** @type { 'HTMLCommentCloseDecoration' } */
-const TYPE_HTML_COMMENT_CLOSE_DECORATION = 'HTMLCommentCloseDecoration'
-
-/**
- * @param {HTMLComment} comment
- * @returns {boolean}
- */
-function isCommentDirective(comment) {
- return COMMENT_DIRECTIVE.test(comment.value)
-}
-
-/**
- * @param {HTMLComment} comment
- * @returns {boolean}
- */
-function isIEConditionalComment(comment) {
- return (
- IE_CONDITIONAL_IF.test(comment.value) ||
- IE_CONDITIONAL_ENDIF.test(comment.value)
- )
-}
-
-/**
- * Define HTML comment parser
- *
- * @param {SourceCode} sourceCode The source code instance.
- * @param {CommentParserConfig | null} config The config.
- * @returns { (node: Token) => (ParsedHTMLComment | null) } HTML comment parser.
- */
-function defineParser(sourceCode, config) {
- config = config || {}
-
- const exceptions = config.exceptions || []
-
- /**
- * Get a open decoration string from comment contents.
- * @param {string} contents comment contents
- * @returns {string} decoration string
- */
- function getOpenDecoration(contents) {
- 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 {string} contents comment contents
- * @returns {string} decoration string
- */
- function getCloseDecoration(contents) {
- 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) {
- 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)
- 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)
- }
- 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 {string} type
- * @param {string} value
- * @returns {any}
- */
- const createToken = (type, value) => {
- /** @type {Range} */
- const range = [tokenIndex, tokenIndex + value.length]
- tokenIndex = range[1]
- /** @type {SourceLocation} */
- let loc
- return {
- type,
- value,
- range,
- get loc() {
- if (loc) {
- return loc
- }
- return (loc = {
- start: sourceCode.getLocFromIndex(range[0]),
- end: sourceCode.getLocFromIndex(range[1])
- })
- }
- }
- }
-
- /** @type {HTMLCommentOpen} */
- const open = createToken(TYPE_HTML_COMMENT_OPEN, '<!--')
- /** @type {HTMLCommentOpenDecoration | null} */
- const openDecoration = openDecorationText
- ? createToken(TYPE_HTML_COMMENT_OPEN_DECORATION, openDecorationText)
- : null
- tokenIndex += beforeSpace.length
- /** @type {HTMLCommentValue | null} */
- const value = valueText
- ? createToken(TYPE_HTML_COMMENT_VALUE, valueText)
- : null
- tokenIndex += afterSpace.length
- /** @type {HTMLCommentCloseDecoration | null} */
- const closeDecoration = closeDecorationText
- ? createToken(TYPE_HTML_COMMENT_CLOSE_DECORATION, closeDecorationText)
- : null
- /** @type {HTMLCommentClose} */
- const close = 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 {RuleContext} context The rule context.
- * @param {CommentParserConfig | null} config The config.
- * @param {HTMLCommentVisitor} visitHTMLComment The HTML comment visitor.
- * @param {CommentVisitorOption} [visitorOption] The option for visitor.
- * @returns {RuleListener} HTML comment visitor.
- */
-function defineVisitor(context, config, visitHTMLComment, visitorOption) {
- return {
- Program(node) {
- 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)
- }
- }
- }
- }
-}
-
-module.exports = {
- defineVisitor
-}
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/indent-common.ts b/src/eslint-plugins/utils/indent-common.ts
index 8ef9fc61..e9a0b158 100644
--- a/src/eslint-plugins/utils/indent-common.ts
+++ b/src/eslint-plugins/utils/indent-common.ts
@@ -2,7 +2,6 @@
* @author Toru Nagashima <https://github.com/mysticatea>
* See LICENSE file in root directory for full license.
*/
-'use strict'
// ------------------------------------------------------------------------------
// Requirements
@@ -12,2074 +11,2178 @@
// Helpers
// ------------------------------------------------------------------------------
-
-const KNOWN_NODES = new Set([
- '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 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'
+ "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
+ includeComments: true,
+ filter: isNotWhitespace,
})
-const PREFORMATTED_ELEMENT_NAMES = ['pre', 'textarea']
-
-/**
- * @typedef {object} IndentOptions
- * @property { " " | "\t" } IndentOptions.indentChar
- * @property {number} IndentOptions.indentSize
- * @property {number} IndentOptions.baseIndent
- * @property {number} IndentOptions.attribute
- * @property {object} IndentOptions.closeBracket
- * @property {number} IndentOptions.closeBracket.startTag
- * @property {number} IndentOptions.closeBracket.endTag
- * @property {number} IndentOptions.closeBracket.selfClosingTag
- * @property {number} IndentOptions.switchCase
- * @property {boolean} IndentOptions.alignAttributesVertically
- * @property {string[]} IndentOptions.ignores
- */
-/**
- * @typedef {object} IndentUserOptions
- * @property { " " | "\t" } [IndentUserOptions.indentChar]
- * @property {number} [IndentUserOptions.indentSize]
- * @property {number} [IndentUserOptions.baseIndent]
- * @property {number} [IndentUserOptions.attribute]
- * @property {IndentOptions['closeBracket'] | number} [IndentUserOptions.closeBracket]
- * @property {number} [IndentUserOptions.switchCase]
- * @property {boolean} [IndentUserOptions.alignAttributesVertically]
- * @property {string[]} [IndentUserOptions.ignores]
- */
-/**
- * Normalize options.
- * @param {number|"tab"|undefined} type The type of indentation.
- * @param {IndentUserOptions} options Other options.
- * @param {Partial<IndentOptions>} defaultOptions The default value of options.
- * @returns {IndentOptions} Normalized options.
- */
-function parseOptions(type, options, defaultOptions) {
- /** @type {IndentOptions} */
- const ret = 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
+const PREFORMATTED_ELEMENT_NAMES = ["pre", "textarea"]
+
+type IndentOptions = {
+ indentChar: " " | "\t"
+ indentSize: number
+ baseIndent: number
+ attribute: number
+ closeBracket: {
+ startTag: number
+ endTag: number
+ selfClosingTag: number
}
- } else if (options.closeBracket) {
- ret.closeBracket = Object.assign(
- {
- startTag: 0,
- endTag: 0,
- selfClosingTag: 0
- },
- options.closeBracket
+ 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(options.switchCase)) {
- ret.switchCase = options.switchCase
- }
-
- if (options.alignAttributesVertically != null) {
- ret.alignAttributesVertically = options.alignAttributesVertically
- }
- if (options.ignores != null) {
- ret.ignores = options.ignores
- }
-
- return ret
+
+ 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.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is an arrow.
*/
-function isArrow(token) {
- return token != null && token.type === 'Punctuator' && token.value === '=>'
+function isArrow(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "=>"
}
/**
* Check whether the given token is a left parenthesis.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a left parenthesis.
*/
-function isLeftParen(token) {
- return token != null && token.type === 'Punctuator' && token.value === '('
+function isLeftParen(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "("
}
/**
* Check whether the given token is a left parenthesis.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `false` if the token is a left parenthesis.
*/
-function isNotLeftParen(token) {
- return token != null && (token.type !== 'Punctuator' || token.value !== '(')
+function isNotLeftParen(token: Token | undefined | null) {
+ return token != null && (token.type !== "Punctuator" || token.value !== "(")
}
/**
* Check whether the given token is a right parenthesis.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a right parenthesis.
*/
-function isRightParen(token) {
- return token != null && token.type === 'Punctuator' && token.value === ')'
+function isRightParen(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === ")"
}
/**
* Check whether the given token is a right parenthesis.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `false` if the token is a right parenthesis.
*/
-function isNotRightParen(token) {
- return token != null && (token.type !== 'Punctuator' || token.value !== ')')
+function isNotRightParen(token: Token | undefined | null) {
+ return token != null && (token.type !== "Punctuator" || token.value !== ")")
}
/**
* Check whether the given token is a left brace.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a left brace.
*/
-function isLeftBrace(token) {
- return token != null && token.type === 'Punctuator' && token.value === '{'
+function isLeftBrace(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "{"
}
/**
* Check whether the given token is a right brace.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a right brace.
*/
-function isRightBrace(token) {
- return token != null && token.type === 'Punctuator' && token.value === '}'
+function isRightBrace(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "}"
}
/**
* Check whether the given token is a left bracket.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a left bracket.
*/
-function isLeftBracket(token) {
- return token != null && token.type === 'Punctuator' && token.value === '['
+function isLeftBracket(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "["
}
/**
* Check whether the given token is a right bracket.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a right bracket.
*/
-function isRightBracket(token) {
- return token != null && token.type === 'Punctuator' && token.value === ']'
+function isRightBracket(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "]"
}
/**
* Check whether the given token is a semicolon.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a semicolon.
*/
-function isSemicolon(token) {
- return token != null && token.type === 'Punctuator' && token.value === ';'
+function isSemicolon(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === ";"
}
/**
* Check whether the given token is a comma.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a comma.
*/
-function isComma(token) {
- return token != null && token.type === 'Punctuator' && token.value === ','
+function isComma(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === ","
}
+
/**
* Check whether the given token is a wildcard.
- * @param {Token} token The token to check.
- * @returns {boolean} `true` if the token is a wildcard.
*/
-function isWildcard(token) {
- return token != null && token.type === 'Punctuator' && token.value === '*'
+function isWildcard(token: Token) {
+ return token != null && token.type === "Punctuator" && token.value === "*"
}
/**
* Check whether the given token is a whitespace.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a whitespace.
*/
-function isNotWhitespace(token) {
- return token != null && token.type !== 'HTMLWhitespace'
+function isNotWhitespace(token: Token | undefined | null) {
+ return token != null && token.type !== "HTMLWhitespace"
}
/**
* Check whether the given token is a comment.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a comment.
*/
-function isComment(token) {
- 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')))
- )
+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.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `false` if the token is a comment.
*/
-function isNotComment(token) {
- 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')
+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.
- * @param {ASTNode} node The node to check.
- * @returns {boolean} `false` if the token is empty text node.
*/
-function isNotEmptyTextNode(node) {
- return !(node.type === 'VText' && node.value.trim() === '')
+function isNotEmptyTextNode(node: ASTNode) {
+ return !(node.type === "VText" && node.value.trim() === "")
}
/**
* Check whether the given token is a pipe operator.
- * @param {Token|undefined|null} token The token to check.
- * @returns {boolean} `true` if the token is a pipe operator.
*/
-function isPipeOperator(token) {
- return token != null && token.type === 'Punctuator' && token.value === '|'
+function isPipeOperator(token: Token | undefined | null) {
+ return token != null && token.type === "Punctuator" && token.value === "|"
}
/**
* Get the last element.
- * @template T
- * @param {T[]} xs The array to get the last element.
- * @returns {T | undefined} The last element or undefined.
*/
-function last(xs) {
- return xs.length === 0 ? undefined : xs[xs.length - 1]
+function last<T>(xs: T[]) {
+ return xs.length === 0 ? undefined : xs[xs.length - 1]
}
/**
* Check whether the node is at the beginning of line.
- * @param {ASTNode|null} node The node to check.
- * @param {number} index The index of the node in the nodes.
- * @param {(ASTNode|null)[]} nodes The array of nodes.
- * @returns {boolean} `true` if the node is at the beginning of line.
*/
-function isBeginningOfLine(node, index, nodes) {
- 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
+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
+ return false
}
/**
* Check whether a given token is a closing token which triggers unindent.
- * @param {Token} token The token to check.
- * @returns {boolean} `true` if the token is a closing token.
*/
-function isClosingToken(token) {
- return (
- token != null &&
- (token.type === 'HTMLEndTagOpen' ||
- token.type === 'VExpressionEnd' ||
- (token.type === 'Punctuator' &&
- (token.value === ')' || token.value === '}' || token.value === ']')))
- )
+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 {RuleContext} context The rule context.
- * @param {ParserServices.TokenStore | SourceCode} tokenStore The token store object to get tokens.
- * @param {Partial<IndentOptions>} defaultOptions The default value of options.
+ * @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,
- tokenStore,
- defaultOptions
-) {
- 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.
- * @param {Token|Token[]|null|(Token|null)[]} token The token to set.
- * @param {number} offset The offset of the tokens.
- * @param {Token} baseToken The token of the base offset.
- * @returns {void}
- */
- function setOffset(token, offset, baseToken) {
- 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.
- * @param {Token} token The token to set.
- * @returns {void}
- */
- function setBaseline(token) {
- const offsetInfo = offsets.get(token)
- if (offsetInfo != null) {
- offsetInfo.baseline = true
- }
- }
-
- /**
- * Sets preformatted tokens to the given element node.
- * @param {VElement} node The node to set.
- * @returns {void}
- */
- function setPreformattedTokens(node) {
- const endToken =
- (node.endTag && tokenStore.getFirstToken(node.endTag)) ||
- tokenStore.getTokenAfter(node)
-
- /** @type {SourceCode.CursorWithSkipOptions} */
- const option = {
- 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 {ASTNode} node The node to get.
- * @param {number} [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 {{firstToken:Token,lastToken:Token}} The gotten tokens.
- */
- function getFirstAndLastTokens(node, borderOffset = 0) {
- 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
+ context: RuleContext,
+ tokenStore: ParserServices.TokenStore | SourceCode,
+ defaultOptions: Partial<IndentOptions>,
+): NodeListener {
+ if (!context.getFilename().endsWith(".vue")) {
+ return {}
}
- 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 {(ASTNode|null)[]} nodeList The node to process.
- * @param {ASTNode|Token|null} left The left parenthesis token.
- * @param {ASTNode|Token|null} right The right parenthesis token.
- * @param {number} offset The offset to set.
- * @param {boolean} [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}
- */
- function processNodeList(nodeList, left, right, offset, alignVertically) {
- 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 (let i = 0; i < nodeList.length; ++i) {
- const node = nodeList[i]
- if (node == null) {
- // Holes of an array.
- continue
+ 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
}
- 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 (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,
+ })
}
+ }
- if (baseToken == null) {
- baseToken = elementTokens.firstToken
- } else {
- alignTokens.push(elementTokens.firstToken)
+ /**
+ * Set baseline flag to the given token.
+ */
+ function setBaseline(token: Token) {
+ const offsetInfo = offsets.get(token)
+ if (offsetInfo != null) {
+ offsetInfo.baseline = true
}
+ }
- // Save the last token to find tokens between this node and the next node.
- lastToken = elementTokens.lastToken
- }
+ /**
+ * 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)
+ }
- // Check trailing commas and comments.
- if (rightToken != null && lastToken != null) {
- t = lastToken
+ /**
+ * 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.getTokenAfter(t, ITERATION_OPTS)) != null &&
- t.range[1] <= rightToken.range[0]
+ (t = tokenStore.getTokenBefore(firstToken)) != null &&
+ (u = tokenStore.getTokenAfter(lastToken)) != null &&
+ isLeftParen(t) &&
+ isRightParen(u) &&
+ t.range[0] >= borderOffset
) {
- 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)
+ firstToken = t
+ lastToken = u
}
- // Set baseline.
- if (nodeList.some(isBeginningOfLine)) {
- setBaseline(baseToken)
+ 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 (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)
}
- }
}
- 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 {ASTNode} node The body node to process.
- * @param {Token} baseToken The base token.
- * @returns {void}
- */
- function processMaybeBlock(node, baseToken) {
- 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 {Property|MethodDefinition} node The property node to collect prefix tokens.
- */
- function getPrefixTokens(node) {
- 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()
+ /**
+ * 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)
}
- return prefixes
- }
-
- /**
- * Find the head of chaining nodes.
- * @param {ASTNode} node The start node to find the head.
- * @returns {Token} The head token of the chain.
- */
- function getChainHeadToken(node) {
- 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
- }
- 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} token The token to check.
- * @param {ASTNode} 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, belongingNode) {
- 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
+ /**
+ * 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)
}
- const prevToken = tokenStore.getTokenBefore(belongingNode)
- if (isLeftParen(prevToken)) {
- // It is not the first token because it is enclosed in parentheses.
- return false
+ while (isLeftParen(last(prefixes)) || isLeftBracket(last(prefixes))) {
+ prefixes.pop()
}
- return true
- }
- if (parent.type === 'CallExpression' || parent.type === 'NewExpression') {
- const openParen = /** @type {Token} */ (tokenStore.getTokenAfter(
- parent.callee,
- isNotRightParen
- ))
- 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 prefixes
}
- return false
- }
-
- /**
- * Set the base indentation to a given top-level AST node.
- * @param {ASTNode} node The node to set.
- * @param {number} expectedIndent The number of expected indent.
- * @returns {void}
- */
- function processTopLevelNode(node, expectedIndent) {
- 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 {ASTNode} node The node to ignore.
- * @returns {void}
- */
- function ignore(node) {
- for (const token of tokenStore.getTokens(node)) {
- offsets.delete(token)
- ignoreTokens.add(token)
- }
- }
-
- /**
- * Define functions to ignore nodes into the given visitor.
- * @param {NodeListener} visitor The visitor to define functions to ignore nodes.
- * @returns {NodeListener} The visitor.
- */
- function processIgnores(visitor) {
- for (const ignorePattern of options.ignores) {
- const key = `${ignorePattern}:exit`
-
- 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
+ /**
+ * 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
}
- } else {
- visitor[key] = ignore
- }
+ return tokenStore.getFirstToken(node)
}
- return visitor
- }
+ /**
+ * 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],
+ )
+ }
- /**
- * Calculate correct indentation of the line of the given tokens.
- * @param {Token[]} tokens Tokens which are on the same line.
- * @returns { { expectedIndent: number, expectedBaseIndent: number } |null } Correct indentation. If it failed to calculate then `null`.
- */
- function getExpectedIndents(tokens) {
- const expectedIndents = []
+ node = parent
+ }
- for (let i = 0; i < tokens.length; ++i) {
- const token = tokens[i]
- const offsetInfo = offsets.get(token)
+ return false
+ }
- if (offsetInfo != null) {
- if (offsetInfo.expectedIndent != null) {
- expectedIndents.push(offsetInfo.expectedIndent)
+ /**
+ * 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 {
- const baseOffsetInfo = offsets.get(offsetInfo.baseToken)
- if (
- baseOffsetInfo != null &&
- baseOffsetInfo.expectedIndent != null &&
- (i === 0 || !baseOffsetInfo.baseline)
- ) {
- expectedIndents.push(
- baseOffsetInfo.expectedIndent +
- offsetInfo.offset * options.indentSize
- )
- if (baseOffsetInfo.baseline) {
- break
- }
- }
+ offsets.set(token, {
+ baseToken: null,
+ offset: 0,
+ baseline: false,
+ expectedIndent,
+ })
}
- }
- }
- 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 {Token} firstToken The first token on a line.
- * @returns {string} The text of indentation part.
- */
- function getIndentText(firstToken) {
- const text = sourceCode.text
- let i = firstToken.range[0] - 1
-
- while (i >= 0 && !LT_CHAR.test(text[i])) {
- i -= 1
+ /**
+ * 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)
+ }
}
- return text.slice(i + 1, firstToken.range[0])
- }
-
- /**
- * Define the function which fixes the problem.
- * @param {Token} token The token to fix.
- * @param {number} actualIndent The number of actual indentation.
- * @param {number} expectedIndent The number of expected indentation.
- * @returns { (fixer: RuleFixer) => Fix } The defined function.
- */
- function defineFix(token, actualIndent, expectedIndent) {
- 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) => {
- /** @type {Range} */
- const 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('')}`
- )
+ /**
+ * 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
}
- return (fixer) => {
- /** @type {Range} */
- const range = [token.range[0] - actualIndent, token.range[0]]
- const indent = options.indentChar.repeat(expectedIndent)
- return fixer.replaceTextRange(range, indent)
+ /**
+ * 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),
+ ),
+ }
}
- }
-
- /**
- * Validate the given token with the pre-calculated expected indentation.
- * @param {Token} token The token to validate.
- * @param {number} expectedIndent The expected indentation.
- * @param {number[]} [optionalExpectedIndents] The optional expected indentation.
- * @returns {void}
- */
- function validateCore(token, expectedIndent, optionalExpectedIndents) {
- 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
+
+ /**
+ * 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])
}
- 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
- }
+ /**
+ * 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)
+ }
}
- if (
- actualIndent !== expectedIndent &&
- (optionalExpectedIndents == null ||
- !optionalExpectedIndents.includes(actualIndent))
+ /**
+ * 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[],
) {
- 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)
- })
+ 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 {Token} nextToken The next token of comments.
- * @param {number} nextExpectedIndent The expected indent of the next token.
- * @param {number} lastExpectedIndent The expected indent of the last token.
- * @returns {number[]}
- */
- function getCommentExpectedIndents(
- nextToken,
- nextExpectedIndent,
- lastExpectedIndent
- ) {
- if (typeof lastExpectedIndent === 'number' && isClosingToken(nextToken)) {
- if (nextExpectedIndent === lastExpectedIndent) {
- // For solo comment. E.g.,
+
+ /**
+ * 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 + options.indentSize, nextExpectedIndent]
- }
-
- // For last comment. E.g.,
- // <div>
- // <div></div>
- // <!-- comment -->
- // </div>
- return [lastExpectedIndent, nextExpectedIndent]
+ return [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 {Token[]} tokens The tokens on the same line to validate.
- * @param {Token[]} comments The comments which are on the immediately previous lines of the tokens.
- * @param {Token|null} lastToken The last validated token. Comments can adjust to the token.
- * @returns {void}
- */
- function validate(tokens, comments, lastToken) {
- // Calculate and save expected indentation.
- const firstToken = tokens[0]
- const actualIndent = firstToken.loc.start.column
- const expectedIndents = getExpectedIndents(tokens)
- if (!expectedIndents) {
- return
- }
+ /**
+ * 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,
+ )
- 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
+ // Validate.
+ for (const comment of comments) {
+ const commentExpectedIndents = getExpectedIndents([comment])
+ const commentExpectedIndent = commentExpectedIndents
+ ? commentExpectedIndents.expectedIndent
+ : commentOptionalExpectedIndents[0]
+
+ validateCore(
+ comment,
+ commentExpectedIndent,
+ commentOptionalExpectedIndents,
)
- } 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
}
- }
+ validateCore(firstToken, expectedIndent)
}
- // It does not validate ignore tokens.
- if (ignoreTokens.has(firstToken)) {
- return
- }
+ // ------------------------------------------------------------------------------
+ // 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)
+ }
+ }
+ },
- // 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
- )
+ 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)
+ }
+ },
- // Validate.
- for (const comment of comments) {
- const commentExpectedIndents = getExpectedIndents([comment])
- const commentExpectedIndent = commentExpectedIndents
- ? commentExpectedIndents.expectedIndent
- : commentOptionalExpectedIndents[0]
-
- validateCore(
- comment,
- commentExpectedIndent,
- commentOptionalExpectedIndents
- )
- }
- validateCore(firstToken, expectedIndent)
- }
+ 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,
+ )
+ }
+ },
- // ------------------------------------------------------------------------------
- // Main
- // ------------------------------------------------------------------------------
+ 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)
+ }
+ },
- return processIgnores({
- /** @param {VAttribute} node */
- VAttribute(node) {
- const keyToken = tokenStore.getFirstToken(node)
- const eqToken = tokenStore.getTokenAfter(node.key)
+ 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)
+ }
+ },
- if (eqToken != null && eqToken.range[1] <= node.range[1]) {
- setOffset(eqToken, 1, keyToken)
+ VFilterSequenceExpression(node: VFilterSequenceExpression) {
+ if (node.filters.length === 0) {
+ return
+ }
- const valueToken = tokenStore.getTokenAfter(eqToken)
- if (valueToken != null && valueToken.range[1] <= node.range[1]) {
- setOffset(valueToken, 1, keyToken)
- }
- }
- },
- /** @param {VElement} node */
- VElement(node) {
- 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)
- }
- },
- /** @param {VEndTag} node */
- VEndTag(node) {
- 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)
- }
- },
- /** @param {VExpressionContainer} node */
- VExpressionContainer(node) {
- 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)
- }
- },
- /** @param {VFilter} node */
- VFilter(node) {
- 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)
- }
- },
- /** @param {VFilterSequenceExpression} node */
- VFilterSequenceExpression(node) {
- 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)
- },
- /** @param {VForExpression} node */
- VForExpression(node) {
- const firstToken = tokenStore.getFirstToken(node)
- const lastOfLeft = last(node.left) || firstToken
- const inToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- lastOfLeft,
- isNotRightParen
- ))
- const rightToken = tokenStore.getFirstToken(node.right)
-
- if (isLeftParen(firstToken)) {
- const rightToken = tokenStore.getTokenAfter(lastOfLeft, isRightParen)
- processNodeList(node.left, firstToken, rightToken, 1)
- }
- setOffset(inToken, 1, firstToken)
- setOffset(rightToken, 1, inToken)
- },
- /** @param {VOnExpression} node */
- VOnExpression(node) {
- processNodeList(node.body, null, null, 0)
- },
- /** @param {VStartTag} node */
- VStartTag(node) {
- 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)
- }
- },
- /** @param {VText} node */
- VText(node) {
- const tokens = tokenStore.getTokens(node, isNotWhitespace)
- const firstTokenInfo = offsets.get(tokenStore.getFirstToken(node))
-
- for (const token of tokens) {
- offsets.set(token, Object.assign({}, firstTokenInfo))
- }
- },
- /** @param {ArrayExpression | ArrayPattern} node */
- 'ArrayExpression, ArrayPattern'(node) {
- processNodeList(
- node.elements,
- tokenStore.getFirstToken(node),
- tokenStore.getLastToken(node),
- 1
- )
- },
- /** @param {ArrowFunctionExpression} node */
- ArrowFunctionExpression(node) {
- 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)
- },
- /** @param {AssignmentExpression | AssignmentPattern | BinaryExpression | LogicalExpression} node */
- 'AssignmentExpression, AssignmentPattern, BinaryExpression, LogicalExpression'(
- node
- ) {
- const leftToken = getChainHeadToken(node)
- const opToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.left,
- isNotRightParen
- ))
- 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)
- },
- /** @param {AwaitExpression | RestElement | SpreadElement | UnaryExpression} node */
- 'AwaitExpression, RestElement, SpreadElement, UnaryExpression'(node) {
- const firstToken = tokenStore.getFirstToken(node)
- const nextToken = tokenStore.getTokenAfter(firstToken)
-
- setOffset(nextToken, 1, firstToken)
- },
- /** @param {BlockStatement | ClassBody} node */
- 'BlockStatement, ClassBody'(node) {
- processNodeList(
- node.body,
- tokenStore.getFirstToken(node),
- tokenStore.getLastToken(node),
- 1
- )
- },
- /** @param {BreakStatement | ContinueStatement | ReturnStatement | ThrowStatement} node */
- 'BreakStatement, ContinueStatement, ReturnStatement, ThrowStatement'(node) {
- 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)
- }
- },
- /** @param {CallExpression} node */
- CallExpression(node) {
- 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)
- },
- /** @param {ImportExpression} node */
- ImportExpression(node) {
- 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)
- },
- /** @param {CatchClause} node */
- CatchClause(node) {
- 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)
- },
- /** @param {ClassDeclaration | ClassExpression} node */
- 'ClassDeclaration, ClassExpression'(node) {
- 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)
- },
- /** @param {ConditionalExpression} node */
- ConditionalExpression(node) {
- const prevToken = tokenStore.getTokenBefore(node)
- const firstToken = tokenStore.getFirstToken(node)
- const questionToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.test,
- isNotRightParen
- ))
- const consequentToken = tokenStore.getTokenAfter(questionToken)
- const colonToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.consequent,
- isNotRightParen
- ))
- 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)
- }
- },
- /** @param {DoWhileStatement} node */
- DoWhileStatement(node) {
- const doToken = tokenStore.getFirstToken(node)
- const whileToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.body,
- isNotRightParen
- ))
- 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)
- },
- /** @param {ExportAllDeclaration} node */
- ExportAllDeclaration(node) {
- const tokens = tokenStore.getTokens(node)
- const firstToken = /** @type {Token} */ (tokens.shift())
- if (isSemicolon(last(tokens))) {
- tokens.pop()
- }
- if (!node.exported) {
- setOffset(tokens, 1, firstToken)
- } else {
- // export * as foo from "mod"
- const starToken = /** @type {Token} */ (tokens.find(isWildcard))
- 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)
- }
- },
- /** @param {ExportDefaultDeclaration} node */
- ExportDefaultDeclaration(node) {
- const exportToken = tokenStore.getFirstToken(node)
- const defaultToken = tokenStore.getFirstToken(node, 1)
- const declarationToken = getFirstAndLastTokens(node.declaration)
- .firstToken
- setOffset([defaultToken, declarationToken], 1, exportToken)
- },
- /** @param {ExportNamedDeclaration} node */
- ExportNamedDeclaration(node) {
- 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 = /** @type {Token} */ (tokenStore.getLastToken(
- node,
- isRightBrace
- ))
- 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
- }
- }
- },
- /** @param {ExportSpecifier} node */
- ExportSpecifier(node) {
- const tokens = tokenStore.getTokens(node)
- const firstToken = /** @type {Token} */ (tokens.shift())
- setOffset(tokens, 1, firstToken)
- },
- /** @param {ForInStatement | ForOfStatement} node */
- 'ForInStatement, ForOfStatement'(node) {
- 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 = /** @type {Token} */ (tokenStore.getTokenAfter(
- leftToken,
- isNotRightParen
- ))
- 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)
- },
- /** @param {ForStatement} node */
- ForStatement(node) {
- 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)
- },
- /** @param {FunctionDeclaration | FunctionExpression} node */
- 'FunctionDeclaration, FunctionExpression'(node) {
- 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)
+ const firstToken = tokenStore.getFirstToken(node)
+ /** @type {(Token|null)[]} */
+ const tokens = []
- 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)
- }
- },
- /** @param {IfStatement} node */
- IfStatement(node) {
- 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 = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.consequent,
- isNotRightParen
- ))
-
- setOffset(elseToken, 0, ifToken)
- processMaybeBlock(node.alternate, elseToken)
- }
- },
- /** @param {ImportDeclaration} node */
- ImportDeclaration(node) {
- const firstSpecifier = node.specifiers[0]
- const secondSpecifier = node.specifiers[1]
- const importToken = tokenStore.getFirstToken(node)
- const hasSemi = tokenStore.getLastToken(node).value === ';'
- /** @type {Token[]} */
- const tokens = [] // 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'
+ 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,
) {
- // 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"
+ 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,
)
- } else {
- tokens.push(
- idToken,
- nextToken, // from
- tokenStore.getTokenAfter(nextToken) // "foo"
+ 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,
)
- }
- }
- } 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)
- },
- /** @param {ImportSpecifier} node */
- ImportSpecifier(node) {
- if (node.local.range[0] !== node.imported.range[0]) {
- const tokens = tokenStore.getTokens(node)
- const firstToken = /** @type {Token} */ (tokens.shift())
- setOffset(tokens, 1, firstToken)
- }
- },
- /** @param {ImportNamespaceSpecifier} node */
- ImportNamespaceSpecifier(node) {
- const tokens = tokenStore.getTokens(node)
- const firstToken = /** @type {Token} */ (tokens.shift())
- setOffset(tokens, 1, firstToken)
- },
- /** @param {LabeledStatement} node */
- LabeledStatement(node) {
- const labelToken = tokenStore.getFirstToken(node)
- const colonToken = tokenStore.getTokenAfter(labelToken)
- const bodyToken = tokenStore.getTokenAfter(colonToken)
-
- setOffset([colonToken, bodyToken], 1, labelToken)
- },
- /** @param {MemberExpression | MetaProperty} node */
- 'MemberExpression, MetaProperty'(node) {
- const objectToken = tokenStore.getFirstToken(node)
- if (node.type === 'MemberExpression' && node.computed) {
- const leftBracketToken = /** @type {Token} */ (tokenStore.getTokenBefore(
- node.property,
- isLeftBracket
- ))
- 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)
- }
- },
- /** @param {MethodDefinition | Property} node */
- 'MethodDefinition, Property'(node) {
- 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])
- }
-
- /** @type {Token} */
- let lastKeyToken
- if (node.computed) {
- const keyLeftToken = /** @type {Token} */ (tokenStore.getFirstToken(
- node,
- isLeftBracket
- ))
- const keyToken = tokenStore.getTokenAfter(keyLeftToken)
- const keyRightToken = (lastKeyToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.key,
- isRightBracket
- )))
-
- if (hasPrefix) {
- setOffset(keyLeftToken, 0, /** @type {Token} */ (last(prefixTokens)))
- }
- setOffset(keyToken, 1, keyLeftToken)
- setOffset(keyRightToken, 0, keyLeftToken)
- } else {
- const idToken = (lastKeyToken = tokenStore.getFirstToken(node.key))
+ 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)
+ },
- if (hasPrefix) {
- setOffset(idToken, 0, /** @type {Token} */ (last(prefixTokens)))
- }
- }
-
- 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)
- }
- },
- /** @param {NewExpression} node */
- NewExpression(node) {
- 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)
- }
- },
- /** @param {ObjectExpression | ObjectPattern} node */
- 'ObjectExpression, ObjectPattern'(node) {
- processNodeList(
- node.properties,
- tokenStore.getFirstToken(node),
- tokenStore.getLastToken(node),
- 1
- )
- },
- /** @param {SequenceExpression} node */
- SequenceExpression(node) {
- processNodeList(node.expressions, null, null, 0)
- },
- /** @param {SwitchCase} node */
- SwitchCase(node) {
- 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)
- }
- },
- /** @param {SwitchStatement} node */
- SwitchStatement(node) {
- const switchToken = tokenStore.getFirstToken(node)
- const leftParenToken = tokenStore.getTokenAfter(switchToken)
- const discriminantToken = tokenStore.getTokenAfter(leftParenToken)
- const leftBraceToken = /** @type {Token} */ (tokenStore.getTokenAfter(
- node.discriminant,
- isLeftBrace
- ))
- 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
- )
- },
- /** @param {TaggedTemplateExpression} node */
- TaggedTemplateExpression(node) {
- const tagTokens = getFirstAndLastTokens(node.tag, node.range[0])
- const quasiToken = tokenStore.getTokenAfter(tagTokens.lastToken)
-
- setOffset(quasiToken, 1, tagTokens.firstToken)
- },
- /** @param {TemplateLiteral} node */
- TemplateLiteral(node) {
- 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)
- },
- /** @param {TryStatement} node */
- TryStatement(node) {
- 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)
- }
- },
- /** @param {UpdateExpression} node */
- UpdateExpression(node) {
- const firstToken = tokenStore.getFirstToken(node)
- const nextToken = tokenStore.getTokenAfter(firstToken)
-
- setOffset(nextToken, 1, firstToken)
- },
- /** @param {VariableDeclaration} node */
- VariableDeclaration(node) {
- processNodeList(
- node.declarations,
- tokenStore.getFirstToken(node),
- null,
- 1
- )
- },
- /** @param {VariableDeclarator} node */
- VariableDeclarator(node) {
- 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)
- }
- },
- /** @param {WhileStatement | WithStatement} node */
- 'WhileStatement, WithStatement'(node) {
- 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)
- },
- /** @param {YieldExpression} node */
- YieldExpression(node) {
- 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)
- }
- }
- },
- /** @param {Statement} node */
- // Process semicolons.
- ':statement'(node) {
- 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)
- }
- },
- /** @param {Expression | MetaProperty | TemplateLiteral} node */
- // Process parentheses.
- // `:expression` does not match with MetaProperty and TemplateLiteral as a bug: https://github.com/estools/esquery/pull/59
- ':expression, MetaProperty, TemplateLiteral'(node) {
- 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)
- }
- },
- /** @param {ASTNode} node */
- // Ignore tokens of unknown nodes.
- '*:exit'(node) {
- if (
- !KNOWN_NODES.has(node.type) &&
- !NON_STANDARD_KNOWN_NODES.has(node.type)
- ) {
- ignore(node)
- }
- },
- /** @param {Program} node */
- // Top-level process.
- Program(node) {
- 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)
- }
- },
- /** @param {VElement} node */
- "VElement[parent.type!='VElement']"(node) {
- processTopLevelNode(node, 0)
- },
- /** @param {Program | VElement} node */
- // Do validation.
- ":matches(Program, VElement[parent.type!='VElement']):exit"(node) {
- let comments = []
- /** @type {Token[]} */
- let tokensOnSameLine = []
- 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
+ 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,
) {
- // 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 =
- /** @type {Token} */ (last(tokensOnSameLine)).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 =
- /** @type {Token} */ (last(tokensOnSameLine)).loc.end.line ===
- token.loc.start.line
- tokensOnSameLine = [token]
- comments = []
- }
- }
- if (tokensOnSameLine.length >= 1 && tokensOnSameLine.some(isNotComment)) {
- validate(tokensOnSameLine, comments, lastValidatedToken)
- }
- }
- })
+ 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
index 6f77ab61..ed97222d 100644
--- a/src/eslint-plugins/utils/index.ts
+++ b/src/eslint-plugins/utils/index.ts
@@ -3,80 +3,190 @@
* @copyright 2017 Toru Nagashima. All rights reserved.
* See LICENSE file in root directory for full license.
*/
- 'use strict'
+'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;
- import * as ESLint from "eslint";
- import * as ESTree from "estree";
/**
- * @typedef {import('eslint').Rule.RuleModule} RuleModule
- * @typedef {import('estree').Position} Position
- * @typedef {import('eslint').Rule.CodePath} CodePath
- * @typedef {import('eslint').Rule.CodePathSegment} CodePathSegment
+ // * @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} 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 {object} ComponentArrayPropUnknownName
+ // * @property {'array'} type
+ // * @property {null} key
+ // * @property {null} propName
+ // * @property {null} value
+ // * @property {Expression | SpreadElement} node
*
- * @typedef {ComponentArrayPropDetectName | ComponentArrayPropUnknownName} ComponentArrayProp
+ // * @typedef {ComponentArrayPropDetectName | ComponentArrayPropUnknownName} ComponentArrayProp
*
- * @typedef {object} ComponentObjectPropDetectName
- * @property {'object'} type
- * @property {Expression} key
- * @property {string} propName
- * @property {Expression} value
- * @property {Property} node
+ // * @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 {object} ComponentObjectPropUnknownName
+ // * @property {'object'} type
+ // * @property {null} key
+ // * @property {null} propName
+ // * @property {Expression} value
+ // * @property {Property} node
*
- * @typedef {ComponentObjectPropDetectName | ComponentObjectPropUnknownName} ComponentObjectProp
+ // * @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} 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 {object} ComponentArrayEmitUnknownName
+ // * @property {'array'} type
+ // * @property {null} key
+ // * @property {null} emitName
+ // * @property {null} value
+ // * @property {Expression | SpreadElement} node
*
- * @typedef {ComponentArrayEmitDetectName | ComponentArrayEmitUnknownName} ComponentArrayEmit
+ // * @typedef {ComponentArrayEmitDetectName | ComponentArrayEmitUnknownName} ComponentArrayEmit
*
- * @typedef {object} ComponentObjectEmitDetectName
- * @property {'object'} type
- * @property {Expression} key
- * @property {string} emitName
- * @property {Expression} value
- * @property {Property} node
+ // * @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 {object} ComponentObjectEmitUnknownName
+ // * @property {'object'} type
+ // * @property {null} key
+ // * @property {null} emitName
+ // * @property {Expression} value
+ // * @property {Property} node
*
* @typedef {ComponentObjectEmitDetectName | ComponentObjectEmitUnknownName} ComponentObjectEmit
*/
@@ -102,10 +212,13 @@
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'))
- const path = require('path')
- const vueEslintParser = require('vue-eslint-parser')
- const { findVariable } = require('eslint-utils')
-
+ import path from "path";
+ import vueEslintParser from "vue-eslint-parser";
+ import {findVariable} from "eslint-utils";
+
+
+
+
/**
* @type { WeakMap<RuleContext, Token[]> }
*/
diff --git a/src/eslint-plugins/utils/keycode-to-key.ts b/src/eslint-plugins/utils/keycode-to-key.ts
index 3defe3bf..9adbe049 100644
--- a/src/eslint-plugins/utils/keycode-to-key.ts
+++ b/src/eslint-plugins/utils/keycode-to-key.ts
@@ -1,98 +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',
+ 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',
+ // 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',
+ 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'
+ // 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'
+ // 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
index 2b71bc2f..3cc99aab 100644
--- a/src/eslint-plugins/utils/regexp.ts
+++ b/src/eslint-plugins/utils/regexp.ts
@@ -8,9 +8,9 @@ const RE_REGEXP_STR = /^\/(.+)\/(.*)$/u
* "?", "(", ")", "[", "]", "{", "}", and "|" in `string`.
*/
export function escape(string: string) {
- return string && RE_HAS_REGEXP_CHAR.test(string)
- ? string.replace(RE_REGEXP_CHAR, '\\$&')
- : string
+ return string && RE_HAS_REGEXP_CHAR.test(string)
+ ? string.replace(RE_REGEXP_CHAR, "\\$&")
+ : string
}
/**
@@ -19,17 +19,16 @@ export function escape(string: string) {
* 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])
- }
- return new RegExp(`^${escape(string)}$`)
+ const parts = RE_REGEXP_STR.exec(string)
+ if (parts) {
+ return new RegExp(parts[1], parts[2])
+ }
+ return new RegExp(`^${escape(string)}$`)
}
/**
* Checks whether given string is regexp string
*/
export function isRegExp(string: string) {
- return Boolean(RE_REGEXP_STR.exec(string))
+ return Boolean(RE_REGEXP_STR.exec(string))
}
-
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
+}
From 8c544edfd980fba0043d4a30a2c245210de6a975 Mon Sep 17 00:00:00 2001
From: tyankatsu <frips.ryilsufupe+dev@gmail.com>
Date: Sat, 8 May 2021 11:27:47 +0900
Subject: [PATCH 4/4] style: ignore eslint
---
src/eslint-plugins/utils/regexp.ts | 2 ++
1 file changed, 2 insertions(+)
diff --git a/src/eslint-plugins/utils/regexp.ts b/src/eslint-plugins/utils/regexp.ts
index 3cc99aab..096f135c 100644
--- a/src/eslint-plugins/utils/regexp.ts
+++ b/src/eslint-plugins/utils/regexp.ts
@@ -1,4 +1,5 @@
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
@@ -23,6 +24,7 @@ export function toRegExp(string: string) {
if (parts) {
return new RegExp(parts[1], parts[2])
}
+ // eslint-disable-next-line require-unicode-regexp
return new RegExp(`^${escape(string)}$`)
}