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