diff --git a/src/babel/messages.js b/src/babel/messages.js index aa2e76fa13..8d0583bd55 100644 --- a/src/babel/messages.js +++ b/src/babel/messages.js @@ -7,8 +7,6 @@ export const MESSAGES = { classesIllegalSuperCall: "Direct super call is illegal in non-constructor, use super.$1() instead", classesIllegalConstructorKind: "Illegal kind for constructor method", scopeDuplicateDeclaration: "Duplicate declaration $1", - undeclaredVariable: "Reference to undeclared variable $1", - undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?", settersInvalidParamLength: "Setters must have exactly one parameter", settersNoRest: "Setters aren't allowed to have a rest", noAssignmentsInForHead: "No assignments allowed in for-in/of head", @@ -24,6 +22,10 @@ export const MESSAGES = { illegalMethodName: "Illegal method name $1", lostTrackNodePath: "We lost track of this nodes position, likely because the AST was directly manipulated", + undeclaredVariable: "Reference to undeclared variable $1", + undeclaredVariableType: "Referencing a type alias outside of a type annotation", + undeclaredVariableSuggestion: "Reference to undeclared variable $1 - did you mean $2?", + traverseNeedsParent: "Must pass a scope and parentPath unless traversing a Program/File got a $1 node", traverseVerifyRootFunction: "You passed `traverse()` a function when it expected a visitor object, are you sure you didn't mean `{ enter: Function }`?", traverseVerifyVisitorProperty: "You passed `traverse()` a visitor object with the property $1 that has the invalid property $2", diff --git a/src/babel/transformation/transformers/validation/undeclared-variable-check.js b/src/babel/transformation/transformers/validation/undeclared-variable-check.js index acb6ad1087..3311dd4d2e 100644 --- a/src/babel/transformation/transformers/validation/undeclared-variable-check.js +++ b/src/babel/transformation/transformers/validation/undeclared-variable-check.js @@ -6,6 +6,11 @@ export var metadata = { }; export function ReferencedIdentifier(node, parent, scope, file) { + var binding = scope.getBinding(node.name); + if (binding && binding.kind === "type" && !this.parentPath.isFlow()) { + throw this.errorWithNode(messages.get("undeclaredVariableType", node.name), ReferenceError); + } + if (scope.hasBinding(node.name)) return; // get the closest declaration to offer as a suggestion @@ -34,5 +39,5 @@ export function ReferencedIdentifier(node, parent, scope, file) { // - throw file.errorWithNode(node, msg, ReferenceError); + throw this.errorWithNode(msg, ReferenceError); } diff --git a/src/babel/traversal/scope/index.js b/src/babel/traversal/scope/index.js index 486aa952b5..daf42b7186 100644 --- a/src/babel/traversal/scope/index.js +++ b/src/babel/traversal/scope/index.js @@ -447,6 +447,8 @@ export default class Scope { this.registerBinding("let", path); } else if (t.isImportDeclaration(node) || t.isExportDeclaration(node)) { this.registerBinding("module", path); + } else if (t.isFlowDeclaration()) { + this.registerBinding("type", path); } else { this.registerBinding("unknown", path); } @@ -494,7 +496,13 @@ export default class Scope { var local = this.getOwnBindingInfo(name); if (local) { + // don't ever let a type alias shadow a local binding + if (kind === "type") continue; + + // same identifier so continue safely as we're likely trying to register it + // multiple times if (local.identifier === id) continue; + this.checkBlockScopedCollisions(local, kind, name, id); } diff --git a/src/babel/types/alias-keys.json b/src/babel/types/alias-keys.json index 9d917a303c..89e2a9b52c 100644 --- a/src/babel/types/alias-keys.json +++ b/src/babel/types/alias-keys.json @@ -83,15 +83,15 @@ "ArrayTypeAnnotation": ["Flow"], "BooleanTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "ClassImplements": ["Flow"], - "DeclareClass": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], - "DeclareFunction": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], - "DeclareModule": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], - "DeclareVariable": ["Flow", "FlowStatement", "Statement", "FlowDeclaration"], + "DeclareClass": ["Flow", "FlowDeclaration", "Statement", "Declaration"], + "DeclareFunction": ["Flow", "FlowDeclaration", "Statement", "Declaration"], + "DeclareModule": ["Flow", "FlowDeclaration", "Statement"], + "DeclareVariable": ["Flow", "FlowDeclaration", "Statement", "Declaration"], "FunctionTypeAnnotation": ["Flow"], "FunctionTypeParam": ["Flow"], "GenericTypeAnnotation": ["Flow"], "InterfaceExtends": ["Flow"], - "InterfaceDeclaration": ["Flow", "FlowStatement", "Statement", "Declaration"], + "InterfaceDeclaration": ["Flow", "FlowDeclaration", "Statement", "Declaration"], "IntersectionTypeAnnotation": ["Flow"], "MixedTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "NullableTypeAnnotation": ["Flow"], @@ -100,7 +100,7 @@ "StringTypeAnnotation": ["Flow", "FlowBaseAnnotation"], "TupleTypeAnnotation": ["Flow"], "TypeofTypeAnnotation": ["Flow"], - "TypeAlias": ["Flow", "FlowStatement", "Statement"], + "TypeAlias": ["Flow", "FlowDeclaration", "Statement", "Declaration"], "TypeAnnotation": ["Flow"], "TypeCastExpression": ["Flow"], "TypeParameterDeclaration": ["Flow"], diff --git a/src/babel/types/retrievers.js b/src/babel/types/retrievers.js index 4a7fa6f86d..dc53e06bf8 100644 --- a/src/babel/types/retrievers.js +++ b/src/babel/types/retrievers.js @@ -30,6 +30,13 @@ export function getBindingIdentifiers(node: Object): Object { } getBindingIdentifiers.keys = { + DeclareClass: "id", + DeclareFunction: "id", + DeclareModule: "id", + DeclareVariable: "id", + InterfaceDeclaration: "id", + TypeAlias: "id", + ComprehensionExpression: "blocks", ComprehensionBlock: "left",