Skip to content

Commit

Permalink
Fix the wrong location when using with `@typescript-eslint/scope-mana…
Browse files Browse the repository at this point in the history
…ger` (#87)

* Fix the wrong location when using with `@typescript-eslint/scope-manager`

* Update

* update
  • Loading branch information
ota-meshi authored Nov 18, 2020
1 parent bd916f5 commit 237eac4
Show file tree
Hide file tree
Showing 10 changed files with 92 additions and 26 deletions.
6 changes: 5 additions & 1 deletion .eslintrc.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
extends:
- plugin:@mysticatea/es2015
- plugin:@mysticatea/+node

globals: {
root: "off"
}
overrides:
- files: "**/*.ts"
parser: "@typescript-eslint/parser"
- files: "typings/**"
rules:
node/no-missing-import:
Expand Down
7 changes: 4 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@
"lodash": "^4.17.15"
},
"devDependencies": {
"@mysticatea/eslint-plugin": "^11.0.0",
"@mysticatea/eslint-plugin": "^13.0.0",
"@types/debug": "0.0.30",
"@types/estree": "0.0.38",
"@types/lodash": "^4.14.120",
"@types/mocha": "^5.2.4",
"@types/node": "^10.12.21",
"@typescript-eslint/parser": "^2.31.0",
"@typescript-eslint/parser": "^4.7.0",
"babel-eslint": "^10.0.1",
"chokidar": "^2.0.4",
"codecov": "^3.1.0",
Expand All @@ -44,7 +44,7 @@
"rollup-plugin-node-resolve": "^4.0.0",
"rollup-plugin-sourcemaps": "^0.4.2",
"ts-node": "^8.1.0",
"typescript": "~3.4.4",
"typescript": "~4.0.5",
"wait-on": "^3.2.0",
"warun": "^1.0.0"
},
Expand All @@ -59,6 +59,7 @@
"pretest": "run-s build lint",
"test": "npm run -s test:mocha",
"test:mocha": "nyc mocha \"test/*.js\" --reporter dot --timeout 10000",
"test:debug": "mocha --inspect --require ts-node/register \"test/*.js\" --reporter dot --timeout 10000",
"preupdate-fixtures": "npm run -s build",
"update-fixtures": "node scripts/update-fixtures-ast.js && node scripts/update-fixtures-document-fragment.js",
"preversion": "npm test",
Expand Down
9 changes: 6 additions & 3 deletions src/ast/nodes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -280,7 +280,8 @@ export interface ESLintImportDeclaration extends HasLocation, HasParent {
specifiers: (
| ESLintImportSpecifier
| ESLintImportDefaultSpecifier
| ESLintImportNamespaceSpecifier)[]
| ESLintImportNamespaceSpecifier
)[]
source: ESLintLiteral
}

Expand Down Expand Up @@ -375,7 +376,8 @@ export interface ESLintObjectExpression extends HasLocation, HasParent {
properties: (
| ESLintProperty
| ESLintSpreadElement
| ESLintLegacySpreadProperty)[]
| ESLintLegacySpreadProperty
)[]
}

export interface ESLintProperty extends HasLocation, HasParent {
Expand Down Expand Up @@ -570,7 +572,8 @@ export interface ESLintObjectPattern extends HasLocation, HasParent {
properties: (
| ESLintAssignmentProperty
| ESLintRestElement
| ESLintLegacyRestProperty)[]
| ESLintLegacyRestProperty
)[]
}

export interface ESLintAssignmentProperty extends ESLintProperty {
Expand Down
11 changes: 10 additions & 1 deletion src/common/location-calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export class LocationCalculator {
gapOffsets: number[],
ltOffsets: number[],
baseOffset?: number,
shiftOffset: number = 0,
shiftOffset = 0,
) {
this.gapOffsets = gapOffsets
this.ltOffsets = ltOffsets
Expand Down Expand Up @@ -76,6 +76,15 @@ export class LocationCalculator {
)
}

/**
* Calculate the location of the given index.
* @param index The index to calculate their location.
* @returns The location of the index.
*/
public getLocFromIndex(index: number): Location {
return this._getLocation(index)
}

/**
* Calculate the location of the given offset.
* @param offset The offset to calculate their location.
Expand Down
6 changes: 3 additions & 3 deletions src/external/token-store/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,9 @@ function getStartLocation(token: { range: number[] }): number {
*/
export function search(tokens: HasLocation[], location: number): number {
return sortedIndexBy(
tokens,
{range: [location]},
getStartLocation
tokens as { range: number[] }[],
{ range: [location] },
getStartLocation,
)
}

Expand Down
8 changes: 4 additions & 4 deletions src/html/tokenizer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -527,7 +527,7 @@ export class Tokenizer {
"Invalid state: the provisional token was not found.",
)

const token = this.provisionalToken as Token
const token = this.provisionalToken
this.provisionalToken = null

if (token.range[0] < token.range[1]) {
Expand All @@ -542,10 +542,10 @@ export class Tokenizer {
assert(this.currentToken != null)
assert(this.provisionalToken != null)

const token = this.currentToken as Token
const token = this.currentToken
debug("[html] rollback token: %d %s", token.range[0], token.type)

this.currentToken = this.provisionalToken as Token
this.currentToken = this.provisionalToken
this.provisionalToken = null
}

Expand Down Expand Up @@ -1808,7 +1808,7 @@ export class Tokenizer {

// The this.buffer.length is not new length since it includes surrogate pairs.
// Calculate new length.
const token = this.currentToken as Token
const token = this.currentToken
const len0 = token.value.length
for (const cp1 of this.buffer) {
this.appendTokenValue(cp1, null)
Expand Down
13 changes: 7 additions & 6 deletions src/script/espree.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,19 +15,20 @@ export interface ESLintCustomParser {
parseForESLint?(code: string, options: any): ESLintCustomParserResult
}

const createRequire: (filename: string) => (filename: string) => any =
const createRequire: (filename: string) => (modname: string) => any =
// Added in v12.2.0
(Module as any).createRequire ||
// Added in v10.12.0, but deprecated in v12.2.0.
// eslint-disable-next-line @mysticatea/node/no-deprecated-api
Module.createRequireFromPath ||
// Polyfill - This is not executed on the tests on node@>=10.
/* istanbul ignore next */
(filename => {
const mod = new Module(filename)
(modname => {
const mod = new Module(modname)

mod.filename = filename
mod.paths = (Module as any)._nodeModulePaths(path.dirname(filename))
;(mod as any)._compile("module.exports = require;", filename)
mod.filename = modname
mod.paths = (Module as any)._nodeModulePaths(path.dirname(modname))
;(mod as any)._compile("module.exports = require;", modname)
return mod.exports
})

Expand Down
24 changes: 19 additions & 5 deletions src/script/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ import {
VForExpression,
VOnExpression,
VSlotScopeExpression,
OffsetRange,
LocationRange,
} from "../ast"
import { debug } from "../common/debug"
import { LocationCalculator } from "../common/location-calculator"
Expand Down Expand Up @@ -66,7 +68,7 @@ function postprocess(
): void {
// There are cases which the same node instance appears twice in the tree.
// E.g. `let {a} = {}` // This `a` appears twice at `Property#key` and `Property#value`.
const traversed = new Set<Node | number[]>()
const traversed = new Set<Node | number[] | LocationRange>()

traverseNodes(result.ast, {
visitorKeys: result.visitorKeys,
Expand All @@ -78,9 +80,22 @@ function postprocess(

// `babel-eslint@8` has shared `Node#range` with multiple nodes.
// See also: https://github.com/vuejs/eslint-plugin-vue/issues/208
if (!traversed.has(node.range)) {
traversed.add(node.range)
if (traversed.has(node.range)) {
if (!traversed.has(node.loc)) {
// However, `Node#loc` may not be shared.
// See also: https://github.com/vuejs/vue-eslint-parser/issues/84
node.loc.start = locationCalculator.getLocFromIndex(
node.range[0],
)
node.loc.end = locationCalculator.getLocFromIndex(
node.range[1],
)
traversed.add(node.loc)
}
} else {
locationCalculator.fixLocation(node)
traversed.add(node.range)
traversed.add(node.loc)
}
}
},
Expand Down Expand Up @@ -139,7 +154,7 @@ function normalizeLeft(
*/
function getCommaTokenBeforeNode(tokens: Token[], node: Node): Token | null {
let tokenIndex = sortedIndexBy(
tokens,
tokens as { range: OffsetRange }[],
{ range: node.range },
t => t.range[0],
)
Expand Down Expand Up @@ -563,7 +578,6 @@ export function parseScript(
require(parserOptions.parser)
: getEspree()
const result: any =
// eslint-disable-next-line @mysticatea/ts/unbound-method
typeof parser.parseForESLint === "function"
? parser.parseForESLint(code, parserOptions)
: parser.parse(code, parserOptions)
Expand Down
11 changes: 11 additions & 0 deletions test/fixtures/ts-scope-manager.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
<template>
<p>Hello World!</p>
</template>

<script>
import Vue from 'vue';
// the error should be reported at line 8
import Button from './Button.vue';
export default Vue.extend({});
</script>
23 changes: 23 additions & 0 deletions test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,29 @@ describe("Basic tests", () => {
})
})

describe("About fixtures/ts-scope-manager.vue", () => {
it("should calculate the correct location with '@typescript-eslint/parser'", () => {
const cli = new CLIEngine({
cwd: FIXTURE_DIR,
envs: ["es6", "node"],
parser: PARSER_PATH,
parserOptions: {
parser: "@typescript-eslint/parser",
},
rules: { "no-unused-vars": ["error"] },
useEslintrc: false,
})
const report = cli.executeOnFiles(["ts-scope-manager.vue"])
const messages = report.results[0].messages

assert.strictEqual(messages.length, 1)
assert.deepStrictEqual(messages[0].line, 8)
assert.deepStrictEqual(messages[0].column, 8)
assert.deepStrictEqual(messages[0].endLine, 8)
assert.deepStrictEqual(messages[0].endColumn, 14)
})
})

describe("About fixtures/svg-attrs.vue", () => {
it("parses attributes with colons", () => {
const cli = new CLIEngine({
Expand Down

0 comments on commit 237eac4

Please sign in to comment.