Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on Jan 19, 2019. It is now read-only.

Commit eb23b26

Browse filesBrowse files
authored
Update: add proper scope analysis (fixes #535) (#540)
* Update: add proper scope analysis (fixes #535) * add computed-properties-in-type fixture * add computed-properties-in-interface fixture * add function-overload fixture * add method-overload fixture * add class-properties fixture * add decorators fixture * update visitor-keys * add declare-global fixture * fix typo * add test for typeof in array destructuring * add namespace fixture * add declare-module fixture * fix crash * add declare-function.ts fixture * add abstract-class fixture * add typeof-in-call-signature fixture * add test for #416 * add test for #435 * add test for #437 * add test for #443 * add test for #459 * add test for #466 * add test for #471 * add test for #487 * add test for #535 * add test for #536 * add test for #476 * fix test to use `expect()`
1 parent 150ffe8 commit eb23b26
Copy full SHA for eb23b26
Expand file treeCollapse file tree

30 files changed

+6647
-28
lines changed

‎analyze-scope.js

Copy file name to clipboardExpand all lines: analyze-scope.js
+598Lines changed: 598 additions & 0 deletions
Large diffs are not rendered by default.

‎package.json

Copy file name to clipboardExpand all lines: package.json
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"version": "20.1.1",
88
"files": [
99
"parser.js",
10+
"analyze-scope.js",
1011
"visitor-keys.js"
1112
],
1213
"engines": {
@@ -43,7 +44,9 @@
4344
"typescript": "*"
4445
},
4546
"dependencies": {
47+
"eslint-scope": "^4.0.0",
4648
"eslint-visitor-keys": "^1.0.0",
49+
"lodash": "^4.17.11",
4750
"typescript-estree": "5.0.0"
4851
},
4952
"devDependencies": {

‎parser.js

Copy file name to clipboardExpand all lines: parser.js
+35-5Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
const parse = require("typescript-estree").parse;
1212
const astNodeTypes = require("typescript-estree").AST_NODE_TYPES;
1313
const traverser = require("eslint/lib/util/traverser");
14+
const analyzeScope = require("./analyze-scope");
1415
const visitorKeys = require("./visitor-keys");
1516

1617
//------------------------------------------------------------------------------
@@ -33,16 +34,45 @@ exports.parseForESLint = function parseForESLint(code, options) {
3334
}
3435

3536
const ast = parse(code, options);
37+
const extraOptions = {
38+
sourceType: ast.sourceType
39+
};
40+
3641
traverser.traverse(ast, {
3742
enter: node => {
38-
if (node.type === "DeclareFunction" || node.type === "FunctionExpression" || node.type === "FunctionDeclaration") {
39-
if (!node.body) {
40-
node.type = `TSEmptyBody${node.type}`;
41-
}
43+
switch (node.type) {
44+
// Just for backword compatibility.
45+
case "DeclareFunction":
46+
if (!node.body) {
47+
node.type = `TSEmptyBody${node.type}`;
48+
}
49+
break;
50+
51+
// Function#body cannot be null in ESTree spec.
52+
case "FunctionExpression":
53+
case "FunctionDeclaration":
54+
if (!node.body) {
55+
node.type = `TSEmptyBody${node.type}`;
56+
}
57+
break;
58+
59+
// Import/Export declarations cannot appear in script.
60+
// But if those appear only in namespace/module blocks, `ast.sourceType` was `"script"`.
61+
// This doesn't modify `ast.sourceType` directly for backrard compatibility.
62+
case "ImportDeclaration":
63+
case "ExportAllDeclaration":
64+
case "ExportDefaultDeclaration":
65+
case "ExportNamedDeclaration":
66+
extraOptions.sourceType = "module";
67+
break;
68+
69+
// no default
4270
}
4371
}
4472
});
45-
return { ast, visitorKeys };
73+
74+
const scopeManager = analyzeScope(ast, options, extraOptions);
75+
return { ast, scopeManager, visitorKeys };
4676
};
4777

4878
exports.parse = function(code, options) {

‎tests/fixtures/scope-analysis/535.ts

Copy file name to clipboard
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function foo({ bar }: { bar: string }) {
2+
bar;
3+
}
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
abstract class A {
2+
abstract a: string
3+
abstract f(): number
4+
}
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const s = Symbol()
2+
class A {
3+
a: typeof s
4+
[s]: number
5+
}
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const s1 = Symbol(), s2 = Symbol()
2+
interface A {
3+
[s1]: number
4+
[s2](s1: number, s2: number): number;
5+
}
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const s1 = Symbol(), s2 = Symbol()
2+
type A = {
3+
[s1]: number
4+
[s2](s1: number, s2: number): number;
5+
}
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
declare function f(a: number): number
2+
f
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
declare global {
2+
let C: number
3+
}
4+
5+
C = 1
6+
7+
export {}
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const a = 1
2+
declare module "foo" {
3+
export const a: number
4+
export const b: typeof a
5+
}
6+
a
+13Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
function dec(target: any) {
2+
}
3+
function gec() {
4+
return (target: any, propertyKey: string) => {}
5+
}
6+
7+
@dec
8+
class C {
9+
@gec() field: string
10+
@gec() method(): string {
11+
return ""
12+
}
13+
}

‎tests/fixtures/scope-analysis/enum.ts

Copy file name to clipboard
+6Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
const a: number = 1
2+
enum E {
3+
A = a,
4+
B = a + 1,
5+
C = A + B
6+
}
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
function f(): void
2+
function f(a: number): void
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
function f(): void
2+
function f(a: number): void
3+
function f(a?: number): void {
4+
// do something.
5+
}
+9Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
type A = number
2+
interface B {
3+
prop1: A
4+
}
5+
interface C extends B {
6+
method(a: { b: A }): { c: A }
7+
}
8+
9+
var a: C
+8Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
const s = Symbol()
2+
class A {
3+
f(): void
4+
f(a: typeof s): void
5+
f(a?: any): void {
6+
// do something.
7+
}
8+
}
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const a = 1
2+
namespace N {
3+
export const a = 2
4+
a
5+
}
6+
a
7+
N.a
+7Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
type A = number
2+
var a: { b: A }
3+
class C {
4+
f(a: { b: A }): { b: A } {
5+
return {b: 1}
6+
}
7+
}
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
type A = number;
2+
a = <A> b;
3+
a = b as A;
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
var obj = { value: 1 }
2+
a = <typeof obj>b;
3+
a = b as typeof obj;
+5Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
const obj = { value: 1 }
2+
interface A {
3+
<T extends typeof obj>(a: typeof obj, b: T): typeof obj
4+
new <T extends typeof obj>(a: typeof obj, b: T): typeof obj
5+
}
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function f(a: number): typeof a { // this `a` is the parameter `a`.
2+
return 1
3+
}
+3Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
function g<T extends typeof g>(g: T): number {
2+
return 1
3+
}
+4Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
var obj = { value: 1 }
2+
var obj2: typeof obj = { value: 2 }
3+
var { value }: typeof obj = { value: 2 }
4+
var [element]: (typeof obj)[] = [{ value: 2 }]
+2Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
var obj = { value: 1 }
2+
type B = typeof obj

0 commit comments

Comments
0 (0)
Morty Proxy This is a proxified and sanitized view of the page, visit original site.