Merge pull request babel/babel-eslint#109 from hzoo/i-108

visit flow types - fixes babel/babel-eslint#108
This commit is contained in:
Henry Zhu 2015-06-01 21:16:02 -04:00
parent 866a77a8cc
commit a4f6edab85
4 changed files with 963 additions and 36 deletions

View File

@ -117,7 +117,7 @@ function convertTemplateType(tokens) {
// create Template token
function replaceWithTemplateType(start, end) {
var templateToken = {
type: 'Template',
type: "Template",
value: createTemplateValue(start, end),
range: [tokens[start].start, tokens[end].end],
loc: {
@ -183,18 +183,37 @@ var astTransformVisitor = {
delete node.argument;
}
if (this.isTypeCastExpression()) {
return node.expression;
}
if (this.isFlow()) {
return this.remove();
}
if (this.isRestElement()) {
return node.argument;
}
// prevent "no-undef"
// for "Component" in: "let x: React.Component"
if (this.isQualifiedTypeIdentifier()) {
delete node.id;
}
// for "b" in: "var a: { b: Foo }"
if (this.isObjectTypeProperty()) {
delete node.key;
}
// for "indexer" in: "var a: {[indexer: string]: number}"
if (this.isObjectTypeIndexer()) {
delete node.id;
}
// for "param" in: "var a: { func(param: Foo): Bar };"
if (this.isFunctionTypeParam()) {
delete node.name;
}
// flow
if (this.isDeclareModule() ||
this.isDeclareClass() ||
this.isDeclareFunction() ||
this.isDeclareVariable()) {
return this.remove();
}
// modules
if (this.isImportDeclaration()) {

View File

@ -1,6 +1,7 @@
var acornToEsprima = require("./acorn-to-esprima");
var traverse = require("babel-core").traverse;
var assign = require("lodash.assign");
var pick = require("lodash.pick");
var Module = require("module");
var parse = require("babel-core").parse;
var path = require("path");
@ -46,12 +47,7 @@ function monkeypatch() {
escope.analyze = function (ast, opts) {
opts.ecmaVersion = 6;
opts.sourceType = "module";
// Don't visit TypeAlias when analyzing scope, but retain them for other
// eslint rules.
var TypeAliasKeys = estraverse.VisitorKeys.TypeAlias;
estraverse.VisitorKeys.TypeAlias = [];
var results = analyze.call(this, ast, opts);
estraverse.VisitorKeys.TypeAlias = TypeAliasKeys;
return results;
};
@ -62,8 +58,18 @@ function monkeypatch() {
} catch (err) {
throw new ReferenceError("couldn't resolve escope/referencer");
}
var referencerMod = createModule(referencerLoc);
var referencer = require(referencerLoc);
// reference Definition
var definitionLoc;
try {
var definitionLoc = Module._resolveFilename("./definition", referencerMod);
} catch (err) {
throw new ReferenceError("couldn't resolve escope/definition");
}
var Definition = require(definitionLoc).Definition;
// if there are decotators, then visit each
function visitDecorators(node) {
if (!node.decorators) {
@ -76,18 +82,182 @@ function monkeypatch() {
}
}
// monkeypatch referencer methods to visit decorators
var visitClass = referencer.prototype.visitClass;
referencer.prototype.visitClass = function (node) {
// visit decorators that are in: Class Declaration
visitDecorators.call(this, node);
visitClass.call(this, node);
// iterate through part of t.VISITOR_KEYS
var visitorKeysMap = pick(t.VISITOR_KEYS, function(k) {
return t.FLIPPED_ALIAS_KEYS.Flow.concat([
"ArrayPattern",
"ClassDeclaration",
"ClassExpression",
"FunctionDeclaration",
"FunctionExpression",
"Identifier",
"ObjectPattern",
"RestElement"
]).indexOf(k) === -1;
});
var propertyTypes = {
// loops
callProperties: { type: "loop", values: ["value"] },
indexers: { type: "loop", values: ["key", "value"] },
properties: { type: "loop", values: ["value"] },
types: { type: "loop" },
params: { type: "loop" },
// single property
argument: { type: "single" },
elementType: { type: "single" },
qualification: { type: "single" },
rest: { type: "single" },
returnType: { type: "single" },
// others
typeAnnotation: { type: "typeAnnotation" },
typeParameters: { type: "typeParameters" },
id: { type: "id" }
};
function visitTypeAnnotation(node) {
// get property to check (params, id, etc...)
var visitorValues = visitorKeysMap[node.type];
if (!visitorValues) {
return;
}
// can have multiple properties
for (var i = 0; i < visitorValues.length; i++) {
var visitorValue = visitorValues[i];
var propertyType = propertyTypes[visitorValue];
var nodeProperty = node[visitorValue];
// check if property or type is defined
if (propertyType == null || nodeProperty == null) {
continue;
}
if (propertyType.type === "loop") {
for (var j = 0; j < nodeProperty.length; j++) {
if (Array.isArray(propertyType.values)) {
for (var k = 0; k < propertyType.values.length; k++) {
checkIdentifierOrVisit.call(this, nodeProperty[j][propertyType.values[k]]);
}
} else {
checkIdentifierOrVisit.call(this, nodeProperty[j]);
}
}
} else if (propertyType.type === "single") {
checkIdentifierOrVisit.call(this, nodeProperty);
} else if (propertyType.type === "typeAnnotation") {
visitTypeAnnotation.call(this, node.typeAnnotation);
} else if (propertyType.type === "typeParameters") {
for (var j = 0; j < node.typeParameters.params.length; j++) {
checkIdentifierOrVisit.call(this, node.typeParameters.params[j]);
}
} else if (propertyType.type === "id") {
if (node.id.type === "Identifier") {
checkIdentifierOrVisit.call(this, node.id);
} else {
visitTypeAnnotation.call(this, node.id);
}
}
}
}
function checkIdentifierOrVisit(node) {
if (node.typeAnnotation) {
visitTypeAnnotation.call(this, node.typeAnnotation);
} else if (node.type === "Identifier") {
this.visit(node);
} else {
visitTypeAnnotation.call(this, node);
}
}
// visit decorators that are in: ClassDeclaration / ClassExpression
var visitClass = referencer.prototype.visitClass;
referencer.prototype.visitClass = function(node) {
visitDecorators.call(this, node);
// visit class
if (node.id) {
this.visit(node.id);
}
// visit flow type: ClassImplements
if (node.implements) {
for (var i = 0; i < node.implements.length; i++) {
checkIdentifierOrVisit.call(this, node.implements[i]);
}
}
if (node.typeParameters) {
for (var i = 0; i < node.typeParameters.params.length; i++) {
checkIdentifierOrVisit.call(this, node.typeParameters.params[i]);
}
}
if (node.superTypeParameters) {
for (var i = 0; i < node.superTypeParameters.params.length; i++) {
checkIdentifierOrVisit.call(this, node.superTypeParameters.params[i]);
}
}
visitClass.call(this, node);
};
// visit decorators that are in: Property / MethodDefinition
var visitProperty = referencer.prototype.visitProperty;
referencer.prototype.visitProperty = function (node) {
// visit decorators that are in: Visit Property / MethodDefinition
referencer.prototype.visitProperty = function(node) {
if (node.value.type === 'TypeCastExpression') {
visitTypeAnnotation.call(this, node.value);
}
visitDecorators.call(this, node);
visitProperty.call(this, node);
};
// visit flow type in FunctionDeclaration, FunctionExpression, ArrowFunctionExpression
var visitFunction = referencer.prototype.visitFunction;
referencer.prototype.visitFunction = function(node) {
if (node.returnType) {
checkIdentifierOrVisit.call(this, node.returnType);
}
// only visit if function parameters have types
if (node.params) {
for (var i = 0; i < node.params.length; i++) {
if (node.params[i].typeAnnotation) {
checkIdentifierOrVisit.call(this, node.params[i]);
}
}
}
if (node.typeParameters) {
for (var i = 0; i < node.typeParameters.params.length; i++) {
checkIdentifierOrVisit.call(this, node.typeParameters.params[i]);
}
}
visitFunction.call(this, node);
};
// visit flow type in VariableDeclaration
var variableDeclaration = referencer.prototype.VariableDeclaration;
referencer.prototype.VariableDeclaration = function(node) {
if (node.declarations) {
for (var i = 0; i < node.declarations.length; i++) {
checkIdentifierOrVisit.call(this, node.declarations[i].id);
}
}
variableDeclaration.call(this, node);
};
referencer.prototype.TypeAlias = function(node) {
this.currentScope().__define(
node.id,
new Definition(
"Variable",
node.id,
node,
null,
null,
null
)
);
if (node.right) {
visitTypeAnnotation.call(this, node.right);
}
if (node.typeParameters) {
for (var i = 0; i < node.typeParameters.params.length; i++) {
checkIdentifierOrVisit.call(this, node.typeParameters.params[i]);
}
}
}
}

View File

@ -9,7 +9,8 @@
},
"dependencies": {
"babel-core": "^5.1.8",
"lodash.assign": "^3.0.0"
"lodash.assign": "^3.0.0",
"lodash.pick": "^3.1.0"
},
"scripts": {
"test": "mocha"

View File

@ -124,20 +124,757 @@ describe("verify", function () {
);
});
it("flow type", function () {
verifyAndAssertMessages(
"type SomeNewType = any;",
{},
[]
);
});
describe("flow", function () {
it("check regular function", function () {
verifyAndAssertMessages([
"function a(b, c) { b += 1; c += 1; } a;",
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("type cast expression #102", function () {
verifyAndAssertMessages(
"for (let a of (a: Array)) {}",
{},
[]
);
it("type alias", function () {
verifyAndAssertMessages(
"type SomeNewType = any;",
{ "no-undef": 1 },
[]
);
});
it("type cast expression #102", function () {
verifyAndAssertMessages(
"for (let a of (a: Array)) {}",
{},
[]
);
});
it("multiple nullable type annotations and return #108", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"function log(foo: ?Foo, foo2: ?Foo2): ?Foo3 {",
"console.log(foo, foo2);",
"}",
"log(1, 2);"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("type parameters", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"function log<Foo, Foo2>() {}",
"log();"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("nested type annotations", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"function foo(callback: () => Foo) {",
"return callback();",
"}",
"foo();"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("type in var declaration", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"var x: Foo = 1;",
"x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("object type annotation", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"var a: {numVal: Foo};",
"a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("object property types", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var a = {",
"circle: (null : ?{ setNativeProps(props: Foo): Foo2 })",
"};",
"a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("namespaced types", function () {
verifyAndAssertMessages([
"var React = require('react-native');",
"var b = {",
"openExternalExample: (null: ?React.Component)",
"};",
"var c = {",
"render(): React.Component {}",
"};",
"b;",
"c;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("ArrayTypeAnnotation", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"var x: Foo[]; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("ClassImplements", function () {
verifyAndAssertMessages([
"import type Foo from 'foo';",
"import type Bar from 'foo';",
"class Foo implements Bar {}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("type alias creates declaration + usage", function () {
verifyAndAssertMessages([
"type Foo = any;",
"var x : Foo = 1; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("type alias with type parameters", function () {
verifyAndAssertMessages([
"import type Bar from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"type Foo<Foo2> = Bar<Foo3>",
"var x : Foo = 1; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("export type alias", function () {
verifyAndAssertMessages([
"import type Foo2 from 'foo';",
"export type Foo = Foo2;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("1", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"export default function(a: Foo, b: ?Foo2, c){ a; b; c; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("2", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"export default function(a: () => Foo){ a; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("3", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"export default function(a: (_:Foo) => Foo2){ a; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("4", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"export default function(a: (_1:Foo, _2:Foo2) => Foo3){ a; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("5", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"export default function(a: (_1:Foo, ...foo:Array<Foo2>) => number){ a; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("6", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"export default function(): Foo {}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("7", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"export default function():() => Foo {}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("8", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"export default function():(_?:Foo) => Foo2{}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("9", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"export default function <Foo, Foo2>() {}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
})
it("10", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var a=function<Foo,Foo2>() {}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("11", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a={*id<Foo>(x: Foo2): Foo3 { x; }}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("12", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a={async id<Foo>(x: Foo2): Foo3 { x; }}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("13", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a={123<Foo>(x: Foo2): Foo3 { x; }}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("14", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"class Bar {set fooProp(value:Foo):Foo2{ value; }}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("15", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"class Foo {get fooProp():Foo{}}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("16", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var numVal:Foo; numVal;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("17", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: {numVal: Foo;}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("18", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a: ?{numVal: Foo; [indexer: Foo2]: Foo3}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("19", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var a: {numVal: Foo; subObj?: ?{strVal: Foo2}}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("20", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"import type Foo4 from 'foo';",
"var a: { [a: Foo]: Foo2; [b: Foo3]: Foo4; }; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("21", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a: {add(x:Foo, ...y:Array<Foo2>): Foo3}; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("22", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a: { id<Foo>(x: Foo2): Foo3; }; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("23", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a:Array<Foo> = [1, 2, 3]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("24", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import Baz from 'foo';",
"class Bar<Foo> extends Baz<Foo2> { };"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("25", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"class Bar<Foo> { bar<Foo2>():Foo3 { return 42; }}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("26", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"class Bar { static prop1:Foo; prop2:Foo2; }"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("27", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var x : Foo | Foo2 = 4; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("28", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var x : () => Foo | () => Foo2; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("29", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var x: typeof Foo | number = Foo2; x;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("30", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
'var {x}: {x: Foo; } = { x: "hello" }; x;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("31", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
'var [x]: Array<Foo> = [ "hello" ]; x;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("32", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"export default function({x}: { x: Foo; }) {}"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("33", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"function foo([x]: Array<Foo>) { x; } foo();"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("34", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var a: Map<Foo, Array<Foo2> >; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("35", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: ?Promise<Foo>[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("36", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"var a:(...rest:Array<Foo>) => Foo2; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("37", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"import type Foo4 from 'foo';",
"var a: <Foo>(x: Foo2, ...y:Foo3[]) => Foo4; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("38", function () {
verifyAndAssertMessages(
[
'import type {foo, bar} from "baz";',
'foo; bar;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("39", function () {
verifyAndAssertMessages(
[
'import type {foo as bar} from "baz";',
'bar;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("40", function () {
verifyAndAssertMessages(
[
'import type from "foo";',
'type;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("41", function () {
verifyAndAssertMessages(
[
'import type, {foo} from "bar";',
'type; foo;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("42", function () {
verifyAndAssertMessages(
[
'import type * as namespace from "bar";',
'namespace;'
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("43", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: Foo[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("44", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: ?Foo[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("45", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: (?Foo)[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("46", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: () => Foo[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("47", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: (() => Foo)[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("48", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"var a: typeof Foo[]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
it("49", function () {
verifyAndAssertMessages(
[
"import type Foo from 'foo';",
"import type Foo2 from 'foo';",
"import type Foo3 from 'foo';",
"var a : [Foo, Foo2<Foo3>,] = [123, 'duck',]; a;"
].join("\n"),
{ "no-unused-vars": 1, "no-undef": 1 },
[]
);
});
});
it("class usage", function () {