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

Properly deduplicate reexported default exports #2866

Merged
merged 4 commits into from May 19, 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
30 changes: 15 additions & 15 deletions src/Chunk.ts
@@ -1,10 +1,9 @@
import sha256 from 'hash.js/lib/hash/sha/256';
import MagicString, { Bundle as MagicStringBundle, SourceMap } from 'magic-string';
import * as NodeType from './ast/nodes/NodeType';
import ExportDefaultDeclaration from './ast/nodes/ExportDefaultDeclaration';
import FunctionDeclaration from './ast/nodes/FunctionDeclaration';
import { UNDEFINED_EXPRESSION } from './ast/values';
import ExportDefaultVariable, {
isExportDefaultVariable
} from './ast/variables/ExportDefaultVariable';
import ExportDefaultVariable from './ast/variables/ExportDefaultVariable';
import ExportShimVariable from './ast/variables/ExportShimVariable';
import GlobalVariable from './ast/variables/GlobalVariable';
import LocalVariable from './ast/variables/LocalVariable';
Expand Down Expand Up @@ -706,7 +705,7 @@ export default class Chunk {
this.facadeModule = facadedModule;
facadedModule.facadeChunk = this;
for (const exportName of facadedModule.getAllExports()) {
const tracedVariable = facadedModule.getVariableForExportName(exportName) as Variable;
const tracedVariable = facadedModule.getVariableForExportName(exportName);
this.exports.add(tracedVariable);
this.exportNames[exportName] = tracedVariable;
}
Expand Down Expand Up @@ -878,9 +877,7 @@ export default class Chunk {
const imports: ImportSpecifier[] = [];
for (const variable of this.imports) {
const renderedVariable =
variable instanceof ExportDefaultVariable && variable.referencesOriginal()
? (variable.getOriginalVariable() as Variable)
: variable;
variable instanceof ExportDefaultVariable ? variable.getOriginalVariable() : variable;
if (
(variable.module instanceof Module
? variable.module.chunk === dep
Expand Down Expand Up @@ -955,13 +952,16 @@ export default class Chunk {
if (variable.init === UNDEFINED_EXPRESSION) {
uninitialized = true;
}
variable.declarations.forEach(decl => {
if (decl.type === NodeType.ExportDefaultDeclaration) {
if (decl.declaration.type === NodeType.FunctionDeclaration) hoisted = true;
} else if (decl.parent.type === NodeType.FunctionDeclaration) {
for (const declaration of variable.declarations) {
if (
declaration.parent instanceof FunctionDeclaration ||
(declaration instanceof ExportDefaultDeclaration &&
declaration.declaration instanceof FunctionDeclaration)
) {
hoisted = true;
break;
}
});
}
} else if (variable instanceof GlobalVariable) {
hoisted = true;
}
Expand Down Expand Up @@ -1052,7 +1052,7 @@ export default class Chunk {
options.format !== 'system' &&
exportVariable.isReassigned &&
!exportVariable.isId &&
(!isExportDefaultVariable(exportVariable) || !exportVariable.hasId)
!(exportVariable instanceof ExportDefaultVariable && exportVariable.hasId)
) {
exportVariable.setRenderNames('exports', exportName);
} else {
Expand Down Expand Up @@ -1089,7 +1089,7 @@ export default class Chunk {
if (module.getOrCreateNamespace().included) {
for (const reexportName of Object.keys(module.reexports)) {
const reexport = module.reexports[reexportName];
const variable = reexport.module.getVariableForExportName(reexport.localName) as Variable;
const variable = reexport.module.getVariableForExportName(reexport.localName);
if ((variable.module as Module).chunk !== this) {
this.imports.add(variable);
if (variable.module instanceof Module) {
Expand Down
2 changes: 1 addition & 1 deletion src/Graph.ts
Expand Up @@ -164,7 +164,7 @@ export default class Graph {
this.getModuleContext = () => this.context;
}

this.onwarn = options.onwarn || makeOnwarn();
this.onwarn = (options.onwarn as WarningHandler) || makeOnwarn();
this.acornOptions = options.acorn || {};
const acornPluginsToInject = [];

Expand Down
27 changes: 13 additions & 14 deletions src/Module.ts
Expand Up @@ -5,22 +5,20 @@ import MagicString from 'magic-string';
import extractAssignedNames from 'rollup-pluginutils/src/extractAssignedNames';
import ClassDeclaration from './ast/nodes/ClassDeclaration';
import ExportAllDeclaration from './ast/nodes/ExportAllDeclaration';
import ExportDefaultDeclaration, {
isExportDefaultDeclaration
} from './ast/nodes/ExportDefaultDeclaration';
import ExportDefaultDeclaration from './ast/nodes/ExportDefaultDeclaration';
import ExportNamedDeclaration from './ast/nodes/ExportNamedDeclaration';
import FunctionDeclaration from './ast/nodes/FunctionDeclaration';
import Identifier from './ast/nodes/Identifier';
import Import from './ast/nodes/Import';
import ImportDeclaration from './ast/nodes/ImportDeclaration';
import ImportSpecifier from './ast/nodes/ImportSpecifier';
import { nodeConstructors } from './ast/nodes/index';
import { isLiteral } from './ast/nodes/Literal';
import Literal from './ast/nodes/Literal';
import MetaProperty from './ast/nodes/MetaProperty';
import * as NodeType from './ast/nodes/NodeType';
import Program from './ast/nodes/Program';
import { Node, NodeBase } from './ast/nodes/shared/Node';
import { isTemplateLiteral } from './ast/nodes/TemplateLiteral';
import TemplateLiteral from './ast/nodes/TemplateLiteral';
import VariableDeclaration from './ast/nodes/VariableDeclaration';
import ModuleScope from './ast/scopes/ModuleScope';
import { EntityPathTracker } from './ast/utils/EntityPathTracker';
Expand Down Expand Up @@ -69,7 +67,7 @@ export interface ImportDescription {
}

export interface ExportDescription {
identifier?: string;
identifier: string | null;
localName: string;
}

Expand Down Expand Up @@ -163,6 +161,7 @@ function handleMissingExport(
}

const MISSING_EXPORT_SHIM_DESCRIPTION: ExportDescription = {
identifier: null,
localName: MISSING_EXPORT_SHIM_VARIABLE
};

Expand Down Expand Up @@ -292,11 +291,11 @@ export default class Module {
getDynamicImportExpressions(): (string | Node)[] {
return this.dynamicImports.map(({ node }) => {
const importArgument = node.parent.arguments[0];
if (isTemplateLiteral(importArgument)) {
if (importArgument instanceof TemplateLiteral) {
if (importArgument.expressions.length === 0 && importArgument.quasis.length === 1) {
return importArgument.quasis[0].value.cooked;
}
} else if (isLiteral(importArgument)) {
} else if (importArgument instanceof Literal) {
if (typeof importArgument.value === 'string') {
return importArgument.value;
}
Expand Down Expand Up @@ -354,7 +353,7 @@ export default class Module {
getTransitiveDependencies() {
return this.dependencies.concat(
this.getReexports().map(
exportName => (this.getVariableForExportName(exportName)).module as Module
exportName => this.getVariableForExportName(exportName).module as Module
)
);
}
Expand Down Expand Up @@ -671,7 +670,7 @@ export default class Module {
};
}
}
} else if (isExportDefaultDeclaration(node)) {
} else if (node instanceof ExportDefaultDeclaration) {
// export default function foo () {}
// export default foo;
// export default 42;
Expand All @@ -686,7 +685,7 @@ export default class Module {
}

this.exports.default = {
identifier: node.variable.getOriginalVariableName() as string | undefined,
identifier: node.variable.getAssignedVariableName(),
localName: 'default'
};
} else if ((node as ExportNamedDeclaration).declaration) {
Expand All @@ -702,13 +701,13 @@ export default class Module {
if (declaration.type === NodeType.VariableDeclaration) {
for (const decl of declaration.declarations) {
for (const localName of extractAssignedNames(decl.id)) {
this.exports[localName] = { localName };
this.exports[localName] = { identifier: null, localName };
}
}
} else {
// export function foo () {}
const localName = (declaration.id as Identifier).name;
this.exports[localName] = { localName };
this.exports[localName] = { identifier: null, localName };
}
} else {
// export { foo, bar, baz }
Expand All @@ -726,7 +725,7 @@ export default class Module {
);
}

this.exports[exportedName] = { localName };
this.exports[exportedName] = { identifier: null, localName };
}
}
}
Expand Down
4 changes: 0 additions & 4 deletions src/ast/nodes/BlockStatement.ts
Expand Up @@ -8,10 +8,6 @@ import { UNKNOWN_EXPRESSION } from '../values';
import * as NodeType from './NodeType';
import { Node, StatementBase, StatementNode } from './shared/Node';

export function isBlockStatement(node: Node): node is BlockStatement {
return node.type === NodeType.BlockStatement;
}

export default class BlockStatement extends StatementBase {
body: StatementNode[];
type: NodeType.tBlockStatement;
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/BreakStatement.ts
Expand Up @@ -11,7 +11,7 @@ export default class BreakStatement extends StatementBase {
return (
super.hasEffects(options) ||
!options.ignoreBreakStatements() ||
((this.label && !options.ignoreLabel(this.label.name)) as boolean)
(this.label !== null && !options.ignoreLabel(this.label.name))
);
}
}
12 changes: 4 additions & 8 deletions src/ast/nodes/ClassDeclaration.ts
@@ -1,17 +1,13 @@
import MagicString from 'magic-string';
import { RenderOptions } from '../../utils/renderHelpers';
import ChildScope from '../scopes/ChildScope';
import Identifier from './Identifier';
import { IdentifierWithVariable } from './Identifier';
import * as NodeType from './NodeType';
import ClassNode from './shared/ClassNode';
import { GenericEsTreeNode, Node } from './shared/Node';

export function isClassDeclaration(node: Node): node is ClassDeclaration {
return node.type === NodeType.ClassDeclaration;
}
import { GenericEsTreeNode } from './shared/Node';

export default class ClassDeclaration extends ClassNode {
id: Identifier;
id: IdentifierWithVariable | null;
type: NodeType.tClassDeclaration;

initialise() {
Expand All @@ -24,7 +20,7 @@ export default class ClassDeclaration extends ClassNode {
parseNode(esTreeNode: GenericEsTreeNode) {
if (esTreeNode.id !== null) {
this.id = new this.context.nodeConstructors.Identifier(esTreeNode.id, this, this.scope
.parent as ChildScope) as Identifier;
.parent as ChildScope) as IdentifierWithVariable;
}
super.parseNode(esTreeNode);
}
Expand Down
18 changes: 7 additions & 11 deletions src/ast/nodes/ExportDefaultDeclaration.ts
Expand Up @@ -8,11 +8,11 @@ import {
import { treeshakeNode } from '../../utils/treeshakeNode';
import ModuleScope from '../scopes/ModuleScope';
import ExportDefaultVariable from '../variables/ExportDefaultVariable';
import ClassDeclaration, { isClassDeclaration } from './ClassDeclaration';
import FunctionDeclaration, { isFunctionDeclaration } from './FunctionDeclaration';
import ClassDeclaration from './ClassDeclaration';
import FunctionDeclaration from './FunctionDeclaration';
import Identifier from './Identifier';
import * as NodeType from './NodeType';
import { ExpressionNode, Node, NodeBase } from './shared/Node';
import { ExpressionNode, NodeBase } from './shared/Node';

const WHITESPACE = /\s/;

Expand All @@ -34,10 +34,6 @@ function getIdInsertPosition(code: string, declarationKeyword: string, start = 0
return declarationEnd + generatorStarPos + 1;
}

export function isExportDefaultDeclaration(node: Node): node is ExportDefaultDeclaration {
return node.type === NodeType.ExportDefaultDeclaration;
}

export default class ExportDefaultDeclaration extends NodeBase {
declaration: FunctionDeclaration | ClassDeclaration | ExpressionNode;
needsBoundaries: true;
Expand Down Expand Up @@ -70,23 +66,23 @@ export default class ExportDefaultDeclaration extends NodeBase {
render(code: MagicString, options: RenderOptions, { start, end }: NodeRenderOptions = BLANK) {
const declarationStart = getDeclarationStart(code.original, this.start);

if (isFunctionDeclaration(this.declaration)) {
if (this.declaration instanceof FunctionDeclaration) {
this.renderNamedDeclaration(
code,
declarationStart,
'function',
this.declaration.id === null,
options
);
} else if (isClassDeclaration(this.declaration)) {
} else if (this.declaration instanceof ClassDeclaration) {
this.renderNamedDeclaration(
code,
declarationStart,
'class',
this.declaration.id === null,
options
);
} else if (this.variable.referencesOriginal()) {
} else if (this.variable.getOriginalVariable() !== this.variable) {
// Remove altogether to prevent re-declaring the same variable
if (options.format === 'system' && this.variable.exportName) {
code.overwrite(
Expand Down Expand Up @@ -133,7 +129,7 @@ export default class ExportDefaultDeclaration extends NodeBase {
}
if (
options.format === 'system' &&
isClassDeclaration(this.declaration) &&
this.declaration instanceof ClassDeclaration &&
this.variable.exportName
) {
code.appendLeft(this.end, ` exports('${this.variable.exportName}', ${name});`);
Expand Down
2 changes: 1 addition & 1 deletion src/ast/nodes/ExportNamedDeclaration.ts
Expand Up @@ -23,7 +23,7 @@ export default class ExportNamedDeclaration extends NodeBase {
}

hasEffects(options: ExecutionPathOptions) {
return (this.declaration && this.declaration.hasEffects(options)) as boolean;
return this.declaration !== null && this.declaration.hasEffects(options);
}

initialise() {
Expand Down
6 changes: 1 addition & 5 deletions src/ast/nodes/ForInStatement.ts
Expand Up @@ -5,14 +5,10 @@ import BlockScope from '../scopes/BlockScope';
import Scope from '../scopes/Scope';
import { EMPTY_PATH } from '../values';
import * as NodeType from './NodeType';
import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node';
import { ExpressionNode, StatementBase, StatementNode } from './shared/Node';
import { PatternNode } from './shared/Pattern';
import VariableDeclaration from './VariableDeclaration';

export function isForInStatement(node: Node): node is ForInStatement {
return node.type === NodeType.ForInStatement;
}

export default class ForInStatement extends StatementBase {
body: StatementNode;
left: VariableDeclaration | PatternNode;
Expand Down
6 changes: 1 addition & 5 deletions src/ast/nodes/ForOfStatement.ts
Expand Up @@ -5,14 +5,10 @@ import BlockScope from '../scopes/BlockScope';
import Scope from '../scopes/Scope';
import { EMPTY_PATH } from '../values';
import * as NodeType from './NodeType';
import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node';
import { ExpressionNode, StatementBase, StatementNode } from './shared/Node';
import { PatternNode } from './shared/Pattern';
import VariableDeclaration from './VariableDeclaration';

export function isForOfStatement(node: Node): node is ForOfStatement {
return node.type === NodeType.ForOfStatement;
}

export default class ForOfStatement extends StatementBase {
await: boolean;
body: StatementNode;
Expand Down
6 changes: 1 addition & 5 deletions src/ast/nodes/ForStatement.ts
Expand Up @@ -4,13 +4,9 @@ import { ExecutionPathOptions } from '../ExecutionPathOptions';
import BlockScope from '../scopes/BlockScope';
import Scope from '../scopes/Scope';
import * as NodeType from './NodeType';
import { ExpressionNode, Node, StatementBase, StatementNode } from './shared/Node';
import { ExpressionNode, StatementBase, StatementNode } from './shared/Node';
import VariableDeclaration from './VariableDeclaration';

export function isForStatement(node: Node): node is ForStatement {
return node.type === NodeType.ForStatement;
}

export default class ForStatement extends StatementBase {
body: StatementNode;
init: VariableDeclaration | ExpressionNode | null;
Expand Down
10 changes: 3 additions & 7 deletions src/ast/nodes/FunctionDeclaration.ts
@@ -1,12 +1,8 @@
import ChildScope from '../scopes/ChildScope';
import Identifier from './Identifier';
import { IdentifierWithVariable } from './Identifier';
import * as NodeType from './NodeType';
import FunctionNode from './shared/FunctionNode';
import { GenericEsTreeNode, Node } from './shared/Node';

export function isFunctionDeclaration(node: Node): node is FunctionDeclaration {
return node.type === NodeType.FunctionDeclaration;
}
import { GenericEsTreeNode } from './shared/Node';

export default class FunctionDeclaration extends FunctionNode {
type: NodeType.tFunctionDeclaration;
Expand All @@ -21,7 +17,7 @@ export default class FunctionDeclaration extends FunctionNode {
parseNode(esTreeNode: GenericEsTreeNode) {
if (esTreeNode.id !== null) {
this.id = new this.context.nodeConstructors.Identifier(esTreeNode.id, this, this.scope
.parent as ChildScope) as Identifier;
.parent as ChildScope) as IdentifierWithVariable;
}
super.parseNode(esTreeNode);
}
Expand Down