diff --git a/.eslintrc.yml b/.eslintrc.yml index 28a03e19..0f676d30 100644 --- a/.eslintrc.yml +++ b/.eslintrc.yml @@ -6,7 +6,13 @@ globals: { } overrides: - files: "**/*.ts" + plugins: + - "@typescript-eslint" parser: "@typescript-eslint/parser" + rules: + "@typescript-eslint/consistent-type-imports": error + no-duplicate-imports: off + "@typescript-eslint/no-duplicate-imports": error - files: "typings/**" rules: node/no-missing-import: diff --git a/package.json b/package.json index d922ce67..c301114f 100644 --- a/package.json +++ b/package.json @@ -28,6 +28,7 @@ "@types/lodash": "^4.14.120", "@types/mocha": "^5.2.4", "@types/node": "^10.12.21", + "@typescript-eslint/eslint-plugin": "^4.9.1", "@typescript-eslint/parser": "^4.7.0", "babel-eslint": "^10.0.1", "chokidar": "^2.0.4", @@ -41,6 +42,7 @@ "npm-run-all": "^4.1.5", "nyc": "^14.0.0", "opener": "^1.5.1", + "prettier": "^2.2.1", "rimraf": "^2.6.3", "rollup": "^1.1.2", "rollup-plugin-node-resolve": "^4.0.0", diff --git a/src/ast/errors.ts b/src/ast/errors.ts index 2a32cf85..3b0e90d6 100644 --- a/src/ast/errors.ts +++ b/src/ast/errors.ts @@ -3,7 +3,7 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ -import { Location } from "./locations" +import type { Location } from "./locations" /** * Check whether the given value has acorn style location information. diff --git a/src/ast/nodes.ts b/src/ast/nodes.ts index eca0b327..18ca044a 100644 --- a/src/ast/nodes.ts +++ b/src/ast/nodes.ts @@ -3,10 +3,10 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ -import { ScopeManager } from "eslint-scope" -import { ParseError } from "./errors" -import { HasLocation } from "./locations" -import { Token } from "./tokens" +import type { ScopeManager } from "eslint-scope" +import type { ParseError } from "./errors" +import type { HasLocation } from "./locations" +import type { Token } from "./tokens" //------------------------------------------------------------------------------ // Common diff --git a/src/ast/tokens.ts b/src/ast/tokens.ts index b75bc54f..1a7e3bbb 100644 --- a/src/ast/tokens.ts +++ b/src/ast/tokens.ts @@ -3,7 +3,7 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ -import { HasLocation } from "./locations" +import type { HasLocation } from "./locations" /** * Tokens. diff --git a/src/ast/traverse.ts b/src/ast/traverse.ts index 3ebfe1b2..ecccfc22 100644 --- a/src/ast/traverse.ts +++ b/src/ast/traverse.ts @@ -3,8 +3,9 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ -import Evk, { VisitorKeys } from "eslint-visitor-keys" -import { Node } from "./nodes" +import type { VisitorKeys } from "eslint-visitor-keys" +import Evk from "eslint-visitor-keys" +import type { Node } from "./nodes" //------------------------------------------------------------------------------ // Helpers diff --git a/src/common/fix-locations.ts b/src/common/fix-locations.ts index 64778af2..2d691d22 100644 --- a/src/common/fix-locations.ts +++ b/src/common/fix-locations.ts @@ -1,10 +1,6 @@ -import { - ESLintExtendedProgram, - LocationRange, - Node, - traverseNodes, -} from "../ast" -import { LocationCalculator } from "./location-calculator" +import type { ESLintExtendedProgram, LocationRange, Node } from "../ast" +import { traverseNodes } from "../ast" +import type { LocationCalculator } from "./location-calculator" /** * Do post-process of parsing an expression. diff --git a/src/common/location-calculator.ts b/src/common/location-calculator.ts index 497bd194..6b3d6ba1 100644 --- a/src/common/location-calculator.ts +++ b/src/common/location-calculator.ts @@ -4,7 +4,7 @@ * See LICENSE file in root directory for full license. */ import sortedLastIndex from "lodash/sortedLastIndex" -import { HasLocation, Location, ParseError } from "../ast" +import type { HasLocation, Location, ParseError } from "../ast" /** * Location calculators. diff --git a/src/html/intermediate-tokenizer.ts b/src/html/intermediate-tokenizer.ts index 5d072517..9ba22236 100644 --- a/src/html/intermediate-tokenizer.ts +++ b/src/html/intermediate-tokenizer.ts @@ -5,16 +5,16 @@ */ import assert from "assert" import last from "lodash/last" -import { +import type { ErrorCode, HasLocation, Namespace, - ParseError, Token, VAttribute, } from "../ast" +import { ParseError } from "../ast" import { debug } from "../common/debug" -import { Tokenizer, TokenizerState, TokenType } from "./tokenizer" +import type { Tokenizer, TokenizerState, TokenType } from "./tokenizer" const DUMMY_PARENT: any = Object.freeze({}) diff --git a/src/html/parser.ts b/src/html/parser.ts index 7a834053..73c6371a 100644 --- a/src/html/parser.ts +++ b/src/html/parser.ts @@ -6,18 +6,17 @@ import assert from "assert" import last from "lodash/last" import findLastIndex from "lodash/findLastIndex" -import { +import type { ErrorCode, HasLocation, Namespace, - NS, - ParseError, Token, VAttribute, VDocumentFragment, VElement, VExpressionContainer, } from "../ast" +import { NS, ParseError } from "../ast" import { debug } from "../common/debug" import { LocationCalculator } from "../common/location-calculator" import { @@ -37,16 +36,17 @@ import { HTML_VOID_ELEMENT_TAGS, SVG_ELEMENT_NAME_MAP, } from "./util/tag-names" -import { +import type { IntermediateToken, - IntermediateTokenizer, EndTag, Mustache, StartTag, Text, } from "./intermediate-tokenizer" -import { Tokenizer } from "./tokenizer" -import { isSFCFile, ParserOptions } from "../common/parser-options" +import { IntermediateTokenizer } from "./intermediate-tokenizer" +import type { Tokenizer } from "./tokenizer" +import type { ParserOptions } from "../common/parser-options" +import { isSFCFile } from "../common/parser-options" const DIRECTIVE_NAME = /^(?:v-|[.:@#]).*[^.:@#]$/u const DT_DD = /^d[dt]$/u @@ -83,7 +83,7 @@ function isHTMLIntegrationPoint(element: VElement): boolean { return ( element.name === "annotation-xml" && element.startTag.attributes.some( - a => + (a) => a.directive === false && a.key.name === "encoding" && a.value != null && @@ -358,7 +358,7 @@ export class Parser { } if (name === "template") { - const xmlns = token.attributes.find(a => a.key.name === "xmlns") + const xmlns = token.attributes.find((a) => a.key.name === "xmlns") const value = xmlns && xmlns.value && xmlns.value.value if (value === NS.HTML || value === NS.MathML || value === NS.SVG) { @@ -462,7 +462,7 @@ export class Parser { } const hasVPre = !this.isInVPreElement && - token.attributes.some(a => a.key.name === "v-pre") + token.attributes.some((a) => a.key.name === "v-pre") // Disable expression if v-pre if (hasVPre) { @@ -520,7 +520,7 @@ export class Parser { if (namespace === NS.HTML) { if (element.parent.type === "VDocumentFragment") { const langAttr = element.startTag.attributes.find( - a => !a.directive && a.key.name === "lang", + (a) => !a.directive && a.key.name === "lang", ) as VAttribute | undefined const lang = langAttr?.value?.value @@ -565,7 +565,7 @@ export class Parser { const i = findLastIndex( this.elementStack, - el => el.name.toLowerCase() === token.name, + (el) => el.name.toLowerCase() === token.name, ) if (i === -1) { this.reportParseError(token, "x-invalid-end-tag") diff --git a/src/html/tokenizer.ts b/src/html/tokenizer.ts index 74b1cf68..5d83610f 100644 --- a/src/html/tokenizer.ts +++ b/src/html/tokenizer.ts @@ -8,7 +8,8 @@ import assert from "assert" import { debug } from "../common/debug" -import { ErrorCode, Namespace, NS, ParseError, Token } from "../ast" +import type { ErrorCode, Namespace, Token } from "../ast" +import { NS, ParseError } from "../ast" import { alternativeCR } from "./util/alternative-cr" import { entitySets } from "./util/entities" import { @@ -50,7 +51,7 @@ import { SOLIDUS, toLowerCodePoint, } from "./util/unicode" -import { ParserOptions } from "../common/parser-options" +import type { ParserOptions } from "../common/parser-options" /** * Enumeration of token types. diff --git a/src/index.ts b/src/index.ts index 7cb7c937..92ff7408 100644 --- a/src/index.ts +++ b/src/index.ts @@ -9,7 +9,7 @@ import { LocationCalculator } from "./common/location-calculator" import { HTMLParser, HTMLTokenizer } from "./html" import { parseScript, parseScriptElement } from "./script" import * as services from "./parser-services" -import { ParserOptions } from "./common/parser-options" +import type { ParserOptions } from "./common/parser-options" const STARTS_WITH_LT = /^\s* { + scriptVisitor["Program:exit"] = (node) => { try { if (typeof programExitHandler === "function") { programExitHandler(node) @@ -195,7 +198,7 @@ export function define( } parserOptions = { ...parserOptions } //eslint-disable-line no-param-reassign const customBlocks = getCustomBlocks(document).filter( - block => + (block) => block.endTag && !block.startTag.attributes.some( (attr): attr is VAttribute => @@ -214,7 +217,7 @@ export function define( const visitorFactories = factories const programExitHandler = scriptVisitor["Program:exit"] - scriptVisitor["Program:exit"] = node => { + scriptVisitor["Program:exit"] = (node) => { try { if (typeof programExitHandler === "function") { programExitHandler(node) @@ -223,7 +226,7 @@ export function define( const lang = getLang(customBlock) const activeVisitorFactories = visitorFactories.filter( - f => f.test(lang, customBlock), + (f) => f.test(lang, customBlock), ) if (!activeVisitorFactories.length) { continue diff --git a/src/script/espree.ts b/src/script/espree.ts index 3765ff0a..3ca8e63f 100644 --- a/src/script/espree.ts +++ b/src/script/espree.ts @@ -1,6 +1,6 @@ import Module from "module" import path from "path" -import { ESLintExtendedProgram, ESLintProgram } from "../ast" +import type { ESLintExtendedProgram, ESLintProgram } from "../ast" /** * The interface of a result of ESLint custom parser. @@ -23,7 +23,7 @@ const createRequire: (filename: string) => (modname: string) => any = Module.createRequireFromPath || // Polyfill - This is not executed on the tests on node@>=10. /* istanbul ignore next */ - (modname => { + ((modname) => { const mod = new Module(modname) mod.filename = modname diff --git a/src/script/index.ts b/src/script/index.ts index 4ca62918..ef29ca03 100644 --- a/src/script/index.ts +++ b/src/script/index.ts @@ -6,7 +6,7 @@ import first from "lodash/first" import last from "lodash/last" import sortedIndexBy from "lodash/sortedIndexBy" -import { +import type { ESLintArrayPattern, ESLintCallExpression, ESLintExpression, @@ -20,7 +20,6 @@ import { ESLintUnaryExpression, HasLocation, Node, - ParseError, Reference, Token, Variable, @@ -32,14 +31,16 @@ import { VSlotScopeExpression, OffsetRange, } from "../ast" +import { ParseError } from "../ast" import { debug } from "../common/debug" -import { LocationCalculator } from "../common/location-calculator" +import type { LocationCalculator } from "../common/location-calculator" import { analyzeExternalReferences, analyzeVariablesAndExternalReferences, } from "./scope-analyzer" -import { ESLintCustomParser, getEspree } from "./espree" -import { ParserOptions } from "../common/parser-options" +import type { ESLintCustomParser } from "./espree" +import { getEspree } from "./espree" +import type { ParserOptions } from "../common/parser-options" import { fixLocations } from "../common/fix-locations" // [1] = spacing before the aliases. @@ -96,7 +97,7 @@ function getCommaTokenBeforeNode(tokens: Token[], node: Node): Token | null { let tokenIndex = sortedIndexBy( tokens as { range: OffsetRange }[], { range: node.range }, - t => t.range[0], + (t) => t.range[0], ) while (tokenIndex >= 0) { @@ -615,9 +616,7 @@ export function parseExpression( if (!retB.expression) { return retB } - const ret = (retB as unknown) as ExpressionParseResult< - VFilterSequenceExpression - > + const ret = (retB as unknown) as ExpressionParseResult ret.expression = { type: "VFilterSequenceExpression", @@ -735,7 +734,7 @@ export function parseVForExpression( if (replaced) { const closeOffset = statement.left.range[1] - 1 const open = tokens[0] - const close = tokens.find(t => t.range[0] === closeOffset) + const close = tokens.find((t) => t.range[0] === closeOffset) if (open != null) { open.value = "(" diff --git a/src/script/scope-analyzer.ts b/src/script/scope-analyzer.ts index 30d4554d..9e537672 100644 --- a/src/script/scope-analyzer.ts +++ b/src/script/scope-analyzer.ts @@ -3,15 +3,16 @@ * @copyright 2017 Toru Nagashima. All rights reserved. * See LICENSE file in root directory for full license. */ -import escope, * as escopeTypes from "eslint-scope" -import { ParserOptions } from "../common/parser-options" -import { +import type * as escopeTypes from "eslint-scope" +import escope from "eslint-scope" +import type { ParserOptions } from "../common/parser-options" +import type { ESLintIdentifier, ESLintProgram, Reference, Variable, - getFallbackKeys, } from "../ast" +import { getFallbackKeys } from "../ast" /** * Check whether the given reference is unique in the belonging array. diff --git a/src/sfc/custom-block/index.ts b/src/sfc/custom-block/index.ts index f64edc66..d0adefbf 100644 --- a/src/sfc/custom-block/index.ts +++ b/src/sfc/custom-block/index.ts @@ -1,20 +1,20 @@ -import { Rule, SourceCode } from "eslint" -import escope, { ScopeManager, Scope } from "eslint-scope" -import { +import type { Rule, SourceCode } from "eslint" +import type { ScopeManager, Scope } from "eslint-scope" +import escope from "eslint-scope" +import type { ESLintExtendedProgram, - getFallbackKeys, Node, OffsetRange, - ParseError, VAttribute, VDocumentFragment, VElement, VExpressionContainer, VText, } from "../../ast" +import { getFallbackKeys, ParseError } from "../../ast" import { fixLocations } from "../../common/fix-locations" -import { LocationCalculator } from "../../common/location-calculator" -import { ParserOptions } from "../../common/parser-options" +import type { LocationCalculator } from "../../common/location-calculator" +import type { ParserOptions } from "../../common/parser-options" export interface ESLintCustomBlockParser { parse(code: string, options: any): any @@ -59,7 +59,7 @@ export function getCustomBlocks( ? document.children .filter(isVElement) .filter( - block => + (block) => block.name !== "script" && block.name !== "template" && block.name !== "style", @@ -369,7 +369,7 @@ function markVariableAsUsed( for (let scope: Scope | null = initialScope; scope; scope = scope.upper) { const variable = scope.variables.find( - scopeVar => scopeVar.name === name, + (scopeVar) => scopeVar.name === name, ) if (variable) { diff --git a/src/template/index.ts b/src/template/index.ts index 1e118dcf..65e4ec34 100644 --- a/src/template/index.ts +++ b/src/template/index.ts @@ -5,10 +5,9 @@ */ import sortedIndexBy from "lodash/sortedIndexBy" import sortedLastIndexBy from "lodash/sortedLastIndexBy" -import { ParserOptions } from "../common/parser-options" -import { +import type { ParserOptions } from "../common/parser-options" +import type { ESLintExpression, - ParseError, Reference, Token, VAttribute, @@ -25,10 +24,11 @@ import { VOnExpression, VSlotScopeExpression, } from "../ast" +import { ParseError } from "../ast" import { debug } from "../common/debug" -import { LocationCalculator } from "../common/location-calculator" +import type { LocationCalculator } from "../common/location-calculator" +import type { ExpressionParseResult } from "../script" import { - ExpressionParseResult, parseExpression, parseVForExpression, parseVOnExpression, @@ -150,7 +150,7 @@ function parseDirectiveKeyStatically( const modifiers = text .slice(i) .split(".") - .map(modifierName => { + .map((modifierName) => { const modifier = createIdentifier(i, i + modifierName.length) if (modifierName === "" && i < text.length) { insertError( diff --git a/test/ast.js b/test/ast.js index d2bd017e..1496ddf4 100644 --- a/test/ast.js +++ b/test/ast.js @@ -42,7 +42,7 @@ function replacer(key, value) { return undefined } if (key === "errors" && Array.isArray(value)) { - return value.map(e => ({ + return value.map((e) => ({ message: e.message, index: e.index, lineNumber: e.lineNumber, @@ -78,7 +78,7 @@ function getTree(source, parserOptions) { let current = root linter.defineParser(PARSER, require(PARSER)) - linter.defineRule("maketree", ruleContext => + linter.defineRule("maketree", (ruleContext) => ruleContext.parserServices.defineTemplateBodyVisitor({ "*"(node) { stack.push(current) @@ -130,7 +130,7 @@ function validateParent(source, parserOptions) { const stack = [] linter.defineParser(PARSER, require(PARSER)) - linter.defineRule("validateparent", ruleContext => + linter.defineRule("validateparent", (ruleContext) => ruleContext.parserServices.defineTemplateBodyVisitor({ "*"(node) { if (stack.length >= 1) { @@ -198,7 +198,7 @@ describe("Template AST", () => { it("should have correct range.", () => { const resultPath = path.join(ROOT, `${name}/token-ranges.json`) const expectedText = fs.readFileSync(resultPath, "utf8") - const tokens = getAllTokens(actual.ast).map(t => + const tokens = getAllTokens(actual.ast).map((t) => source.slice(t.range[0], t.range[1]) ) const actualText = JSON.stringify(tokens, null, 4) @@ -215,7 +215,7 @@ describe("Template AST", () => { const resultPath = path.join(ROOT, `${name}/token-ranges.json`) const expectedText = fs.readFileSync(resultPath, "utf8") - const tokens = getAllTokens(actualForWin.ast).map(t => + const tokens = getAllTokens(actualForWin.ast).map((t) => sourceForWin .slice(t.range[0], t.range[1]) .replace(/\r?\n/gu, "\n") diff --git a/test/core-rules.js b/test/core-rules.js index afd28040..8a2b2b51 100644 --- a/test/core-rules.js +++ b/test/core-rules.js @@ -177,10 +177,10 @@ function modifyPattern(ruleId, pattern) { function overrideRun(ruleId, impl, patterns) { return originalRun.call(this, ruleId, impl, { valid: patterns.valid - .map(pattern => modifyPattern(ruleId, pattern)) + .map((pattern) => modifyPattern(ruleId, pattern)) .filter(Boolean), invalid: patterns.invalid - .map(pattern => modifyPattern(ruleId, pattern)) + .map((pattern) => modifyPattern(ruleId, pattern)) .filter(Boolean), }) } diff --git a/test/define-custom-blocks-visitor.js b/test/define-custom-blocks-visitor.js index 27134357..6d9ea10a 100644 --- a/test/define-custom-blocks-visitor.js +++ b/test/define-custom-blocks-visitor.js @@ -101,31 +101,31 @@ function createLinter(target = "json") { const linter = new Linter() linter.defineParser(PARSER_PATH, require(PARSER_PATH)) - linter.defineRule("test-no-number-literal", context => + linter.defineRule("test-no-number-literal", (context) => context.parserServices.defineCustomBlocksVisitor(context, jsonParser, { target, ...noNumberLiteralRule, }) ) - linter.defineRule("test-no-forbidden-key", context => + linter.defineRule("test-no-forbidden-key", (context) => context.parserServices.defineCustomBlocksVisitor(context, jsonParser, { target, ...noNoForbiddenKeyRule, }) ) - linter.defineRule("test-no-parsing-error", context => + linter.defineRule("test-no-parsing-error", (context) => context.parserServices.defineCustomBlocksVisitor(context, jsonParser, { target, ...noParsingErrorRule, }) ) - linter.defineRule("test-no-parsing-error", context => + linter.defineRule("test-no-parsing-error", (context) => context.parserServices.defineCustomBlocksVisitor(context, jsonParser, { target, ...noParsingErrorRule, }) ) - linter.defineRule("test-no-program-exit", context => + linter.defineRule("test-no-program-exit", (context) => context.parserServices.defineCustomBlocksVisitor( context, jsonParser, @@ -310,7 +310,7 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => { ` const linter = createLinter() - linter.defineRule("test-no-yml-parsing-error", context => + linter.defineRule("test-no-yml-parsing-error", (context) => context.parserServices.defineCustomBlocksVisitor( context, { @@ -374,7 +374,7 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => { ` const linter = createLinter() - linter.defineRule("test-for-parse-custom-block-element", context => + linter.defineRule("test-for-parse-custom-block-element", (context) => context.parserServices.defineCustomBlocksVisitor( context, jsonParser, @@ -425,7 +425,7 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => { ` const linter = createLinter() - linter.defineRule("test", context => + linter.defineRule("test", (context) => context.parserServices.defineCustomBlocksVisitor( context, jsonParser, @@ -439,7 +439,7 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => { message: JSON.stringify( customBlockContext .getAncestors() - .map(n => n.type) + .map((n) => n.type) ), }) }, @@ -470,7 +470,7 @@ describe("parserServices.defineCustomBlocksVisitor tests", () => { ` const linter = createLinter() - linter.defineRule("test", context => + linter.defineRule("test", (context) => context.parserServices.defineCustomBlocksVisitor( context, jsonParser, diff --git a/test/document-fragment.js b/test/document-fragment.js index 8b2be093..5f80facf 100644 --- a/test/document-fragment.js +++ b/test/document-fragment.js @@ -35,7 +35,7 @@ function replacer(key, value) { return undefined } if (key === "errors" && Array.isArray(value)) { - return value.map(e => ({ + return value.map((e) => ({ message: e.message, index: e.index, lineNumber: e.lineNumber, @@ -53,7 +53,7 @@ describe("services.getDocumentFragment", () => { for (const name of TARGETS) { const sourceFileName = fs .readdirSync(path.join(ROOT, name)) - .find(f => f.startsWith("source.")) + .find((f) => f.startsWith("source.")) const sourcePath = path.join(ROOT, `${name}/${sourceFileName}`) const source = fs.readFileSync(sourcePath, "utf8") const result = parser.parseForESLint( @@ -79,7 +79,7 @@ describe("services.getDocumentFragment", () => { it("should have correct range.", () => { const resultPath = path.join(ROOT, `${name}/token-ranges.json`) const expectedText = fs.readFileSync(resultPath, "utf8") - const tokens = getAllTokens(actual).map(t => + const tokens = getAllTokens(actual).map((t) => source.slice(t.range[0], t.range[1]) ) const actualText = JSON.stringify(tokens, null, 4) diff --git a/test/espree.js b/test/espree.js index 284da5dd..637942d8 100644 --- a/test/espree.js +++ b/test/espree.js @@ -9,12 +9,12 @@ function parentMain() { const { spawn } = require("child_process") describe("Loading espree from ESLint", () => { - it("should load espree from the ESLint location.", done => { + it("should load espree from the ESLint location.", (done) => { spawn(process.execPath, [__filename, "--child"], { stdio: "inherit", }) .on("error", done) - .on("exit", code => + .on("exit", (code) => code ? done(new Error(`Exited with non-zero: ${code}`)) : done() diff --git a/test/index.js b/test/index.js index 1e6e1e55..4c82264a 100644 --- a/test/index.js +++ b/test/index.js @@ -589,7 +589,7 @@ describe("Basic tests", () => { const linter = new Linter() linter.defineParser(PARSER_PATH, require(PARSER_PATH)) - linter.defineRule("test-rule", context => + linter.defineRule("test-rule", (context) => context.parserServices.defineTemplateBodyVisitor({ "VElement[name='div']"(node) { context.report({ node, message: "OK" })