Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Check exported bindings are defined #9589

Merged
merged 4 commits into from
Feb 26, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"strictMode": false
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ declare export * from 'asd';
declare export { a, b };
declare export {};
declare export { c, d } from 'bar';
var a, b;

declare module B {
declare export type B = {};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ declare export * from 'asd';
declare export { a, b };
declare export {};
declare export { c, d } from 'bar';
var a, b;
declare module B {
declare export type B = {};
declare export interface Moon {}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,7 @@ import { type Foo12 } from "bar";
import { typeof Foo13 } from "bar";
import { type Foo as Bar1 } from "bar";
import { typeof Foo as Bar2 } from "bar";
export type { foo };
export type { foo1 };
export type { bar } from "bar";
export interface baz { p: number }
export interface qux<T> { p: T }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ import { type Foo12 } from "bar";
import { typeof Foo13 } from "bar";
import { type Foo as Bar1 } from "bar";
import { typeof Foo as Bar2 } from "bar";
export type { foo };
export type { foo1 };
export type { bar } from "bar";
export interface baz {
p: number
Expand Down Expand Up @@ -293,4 +293,4 @@ function foo27(numVal: number = 2) {}

function foo28(numVal?: number = 2) {}

export type * from "foo";
export type * from "foo";
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var a, c;
export * from "OK"
export { name } from "OK"
export { a as b, c as d } from "hello"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
var a, c;
export * from "OK";
export { name } from "OK";
export { a as b, c as d } from "hello";
Expand Down
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo };
export { foo };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo, bar };
var foo, bar;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo, bar };
export { foo, bar };
var foo, bar;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as bar };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as bar };
export { foo as bar };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as default };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as default };
export { foo as default };
var foo;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as default, bar };
var foo, bar;
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
export { foo as default, bar };
export { foo as default, bar };
var foo, bar;
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"strictMode": false
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"strictMode": false
}
2 changes: 1 addition & 1 deletion packages/babel-generator/test/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -489,7 +489,7 @@ suites.forEach(function(testSuite) {
const actualAst = parse(actualCode, {
filename: actual.loc,
plugins: task.options.plugins || [],
strictMode: false,
Copy link
Member Author

@danez danez Feb 26, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was not really correct as sourceType:"module" should always be in strict mode, but it is needed for some of the tests.

strictMode: task.options.strictMode === false ? false : true,
sourceType: "module",
sourceMaps: !!task.sourceMap,
});
Expand Down
18 changes: 16 additions & 2 deletions packages/babel-parser/src/parser/statement.js
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,14 @@ export default class StatementParser extends ExpressionParser {

this.parseBlockBody(program, true, true, tt.eof);

if (this.inModule && this.scope.undefinedExports.size > 0) {
for (const [name] of Array.from(this.scope.undefinedExports)) {
const pos = this.scope.undefinedExports.get(name);
// $FlowIssue
this.raise(pos, `Export '${name}' is not defined`);
}
}

file.program = this.finishNode(program, "Program");
file.comments = this.state.comments;

Expand Down Expand Up @@ -1634,7 +1642,7 @@ export default class StatementParser extends ExpressionParser {
}

if (isFromRequired || hasSpecifiers || hasDeclaration) {
this.checkExport(node, true);
this.checkExport(node, true, false, !!node.source);
return this.finishNode(node, "ExportNamedDeclaration");
}

Expand Down Expand Up @@ -1849,8 +1857,9 @@ export default class StatementParser extends ExpressionParser {

checkExport(
node: N.ExportNamedDeclaration,
checkNames: ?boolean,
checkNames?: boolean,
isDefault?: boolean,
isFrom?: boolean,
): void {
if (checkNames) {
// Check for duplicate exports
Expand All @@ -1861,6 +1870,11 @@ export default class StatementParser extends ExpressionParser {
// Named exports
for (const specifier of node.specifiers) {
this.checkDuplicateExports(specifier, specifier.exported.name);
// check if export is defined
// $FlowIgnore
if (!isFrom && specifier.local) {
this.scope.checkLocalExport(specifier.local);
}
}
} else if (node.declaration) {
// Exported declarations
Expand Down
1 change: 1 addition & 0 deletions packages/babel-parser/src/types.js
Original file line number Diff line number Diff line change
Expand Up @@ -831,6 +831,7 @@ export type ExportNamedDeclaration = NodeBase & {
export type ExportSpecifier = NodeBase & {
type: "ExportSpecifier",
exported: Identifier,
local: Identifier,
};

export type ExportDefaultSpecifier = NodeBase & {
Expand Down
19 changes: 19 additions & 0 deletions packages/babel-parser/src/util/scope.js
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import {
type BindingTypes,
SCOPE_CLASS,
} from "./scopeflags";
import * as N from "../types";

// Start an AST node, attaching a start offset.
class Scope {
Expand All @@ -40,6 +41,7 @@ export default class ScopeHandler {
scopeStack: Array<Scope> = [];
raise: raiseFunction;
inModule: boolean;
undefinedExports: Map<string, number> = new Map();

constructor(raise: raiseFunction, inModule: boolean) {
this.raise = raise;
Expand Down Expand Up @@ -95,6 +97,9 @@ export default class ScopeHandler {
scope.functions.indexOf(name) > -1 ||
scope.var.indexOf(name) > -1;
scope.lexical.push(name);
if (this.inModule && scope.flags & SCOPE_PROGRAM) {
this.undefinedExports.delete(name);
}
} else if (bindingType === BIND_SIMPLE_CATCH) {
const scope = this.currentScope();
scope.lexical.push(name);
Expand Down Expand Up @@ -122,6 +127,10 @@ export default class ScopeHandler {
}
scope.var.push(name);

if (this.inModule && scope.flags & SCOPE_PROGRAM) {
this.undefinedExports.delete(name);
}

if (scope.flags & SCOPE_VAR) break;
}
}
Expand All @@ -130,6 +139,16 @@ export default class ScopeHandler {
}
}

checkLocalExport(id: N.Identifier) {
// scope.functions must be empty as Module code is always strict.
if (
this.scopeStack[0].lexical.indexOf(id.name) === -1 &&
this.scopeStack[0].var.indexOf(id.name) === -1
) {
this.undefinedExports.set(id.name, id.start);
}
}

currentScope(): Scope {
return this.scopeStack[this.scopeStack.length - 1];
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { encrypt as default };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "Export 'encrypt' is not defined (1:9)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { encrypt as decrypt };
function decrypt() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "Export 'encrypt' is not defined (1:9)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
function encrypt() {}
}
export { encrypt }
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "Export 'encrypt' is not defined (4:9)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Object as Obj };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "Export 'Object' is not defined (1:9)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
export { Object };
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "Export 'Object' is not defined (1:9)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export { encrypt };
if (true) function encrypt() {}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
"sourceType": "module",
"throws": "In strict mode code, functions can only be declared at top level or inside a block (2:10)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{
var encrypt
}
export { encrypt }
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"sourceType": "module"
}