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

Refine SystemJS export rendering #4199

Merged
merged 2 commits into from Aug 5, 2021
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
9 changes: 1 addition & 8 deletions src/Chunk.ts
Expand Up @@ -5,7 +5,6 @@ import Module from './Module';
import ExportDefaultDeclaration from './ast/nodes/ExportDefaultDeclaration';
import FunctionDeclaration from './ast/nodes/FunctionDeclaration';
import ChildScope from './ast/scopes/ChildScope';
import { UNDEFINED_EXPRESSION } from './ast/values';
import ExportDefaultVariable from './ast/variables/ExportDefaultVariable';
import ExportShimVariable from './ast/variables/ExportShimVariable';
import LocalVariable from './ast/variables/LocalVariable';
Expand Down Expand Up @@ -83,7 +82,6 @@ export type ChunkExports = {
expression: string | null;
hoisted: boolean;
local: string;
uninitialized: boolean;
}[];

export interface ReexportSpecifier {
Expand Down Expand Up @@ -997,12 +995,8 @@ export default class Chunk {
}
let expression = null;
let hoisted = false;
let uninitialized = false;
let local = variable.getName();
if (variable instanceof LocalVariable) {
if (variable.init === UNDEFINED_EXPRESSION) {
uninitialized = true;
}
for (const declaration of variable.declarations) {
if (
declaration.parent instanceof FunctionDeclaration ||
Expand All @@ -1024,8 +1018,7 @@ export default class Chunk {
exported: exportName,
expression,
hoisted,
local,
uninitialized
local
});
}
return exports;
Expand Down
58 changes: 31 additions & 27 deletions src/ast/nodes/AssignmentExpression.ts
Expand Up @@ -7,10 +7,15 @@ import {
removeLineBreaks,
RenderOptions
} from '../../utils/renderHelpers';
import { getSystemExportFunctionLeft } from '../../utils/systemJsRendering';
import {
renderSystemExportExpression,
renderSystemExportFunction,
renderSystemExportSequenceAfterExpression
} from '../../utils/systemJsRendering';
import { createHasEffectsContext, HasEffectsContext, InclusionContext } from '../ExecutionContext';
import { EMPTY_PATH, ObjectPath, UNKNOWN_PATH } from '../utils/PathTracker';
import Variable from '../variables/Variable';
import Identifier from './Identifier';
import * as NodeType from './NodeType';
import { ExpressionNode, IncludeChildren, NodeBase } from './shared/Node';
import { PatternNode } from './shared/Pattern';
Expand Down Expand Up @@ -68,7 +73,7 @@ export default class AssignmentExpression extends NodeBase {
render(
code: MagicString,
options: RenderOptions,
{ preventASI, renderedParentType }: NodeRenderOptions = BLANK
{ preventASI, renderedParentType, renderedSurroundingElement }: NodeRenderOptions = BLANK
): void {
if (this.left.included) {
this.left.render(code, options);
Expand All @@ -83,40 +88,39 @@ export default class AssignmentExpression extends NodeBase {
removeLineBreaks(code, inclusionStart, this.right.start);
}
this.right.render(code, options, {
renderedParentType: renderedParentType || this.parent.type
renderedParentType: renderedParentType || renderedSurroundingElement || this.parent.type
});
}
if (options.format === 'system') {
const exportNames =
this.left.variable && options.exportNamesByVariable.get(this.left.variable);
if (this.left.type === 'Identifier' && exportNames) {
const _ = options.compact ? '' : ' ';
const operatorPos = findFirstOccurrenceOutsideComment(
code.original,
this.operator,
this.left.end
);
const operation =
this.operator.length > 1 ? `${exportNames[0]}${_}${this.operator.slice(0, -1)}${_}` : '';
code.overwrite(
operatorPos,
findNonWhiteSpace(code.original, operatorPos + this.operator.length),
`=${_}${
exportNames.length === 1
? `exports('${exportNames[0]}',${_}`
: getSystemExportFunctionLeft([this.left.variable!], false, options)
}${operation}`
);
code.appendLeft(this.right.end, ')');
if (this.left instanceof Identifier) {
const variable = this.left.variable!;
const exportNames = options.exportNamesByVariable.get(variable);
if (exportNames) {
if (exportNames.length === 1) {
renderSystemExportExpression(variable, this.start, this.end, code, options);
} else {
renderSystemExportSequenceAfterExpression(
variable,
this.start,
this.end,
this.parent.type !== NodeType.ExpressionStatement,
code,
options
);
}
}
} else {
const systemPatternExports: Variable[] = [];
this.left.addExportedVariables(systemPatternExports, options.exportNamesByVariable);
if (systemPatternExports.length > 0) {
code.prependRight(
renderSystemExportFunction(
systemPatternExports,
this.start,
`(${getSystemExportFunctionLeft(systemPatternExports, true, options)}`
this.end,
(renderedParentType || renderedSurroundingElement) === NodeType.ExpressionStatement,
code,
options
);
code.appendLeft(this.end, '))');
}
}
}
Expand Down
8 changes: 5 additions & 3 deletions src/ast/nodes/ImportExpression.ts
Expand Up @@ -51,7 +51,8 @@ export default class ImportExpression extends NodeBase {
code.overwrite(
this.start,
this.end,
`Promise.resolve().then(function${_}()${_}{${_}return ${this.inlineNamespace.getName()}${s}${_}})`
`Promise.resolve().then(function${_}()${_}{${_}return ${this.inlineNamespace.getName()}${s}${_}})`,
{ contentOnly: true }
);
return;
}
Expand All @@ -60,9 +61,10 @@ export default class ImportExpression extends NodeBase {
code.overwrite(
this.start,
findFirstOccurrenceOutsideComment(code.original, '(', this.start + 6) + 1,
this.mechanism.left
this.mechanism.left,
{ contentOnly: true }
);
code.overwrite(this.end - 1, this.end, this.mechanism.right);
code.overwrite(this.end - 1, this.end, this.mechanism.right, { contentOnly: true });
}
this.source.render(code, options);
}
Expand Down
52 changes: 19 additions & 33 deletions src/ast/nodes/UpdateExpression.ts
@@ -1,8 +1,9 @@
import MagicString from 'magic-string';
import { RenderOptions } from '../../utils/renderHelpers';
import {
getSystemExportFunctionLeft,
getSystemExportStatement
renderSystemExportExpression,
renderSystemExportSequenceAfterExpression,
renderSystemExportSequenceBeforeExpression
} from '../../utils/systemJsRendering';
import { HasEffectsContext } from '../ExecutionContext';
import { EMPTY_PATH, ObjectPath } from '../utils/PathTracker';
Expand Down Expand Up @@ -32,48 +33,33 @@ export default class UpdateExpression extends NodeBase {
render(code: MagicString, options: RenderOptions): void {
this.argument.render(code, options);
if (options.format === 'system') {
const variable = this.argument.variable;
const exportNames = options.exportNamesByVariable.get(variable!);
if (exportNames && exportNames.length) {
const variable = this.argument.variable!;
const exportNames = options.exportNamesByVariable.get(variable);
if (exportNames) {
const _ = options.compact ? '' : ' ';
const name = variable!.getName();
if (this.prefix) {
if (exportNames.length === 1) {
code.overwrite(
this.start,
this.end,
`exports('${exportNames[0]}',${_}${this.operator}${name})`
);
renderSystemExportExpression(variable, this.start, this.end, code, options);
} else {
code.overwrite(
renderSystemExportSequenceAfterExpression(
variable,
this.start,
this.end,
`(${this.operator}${name},${_}${getSystemExportStatement(
[variable!],
options
)},${_}${name})`
this.parent.type !== NodeType.ExpressionStatement,
code,
options
);
}
} else if (exportNames.length > 1) {
code.overwrite(
this.start,
this.end,
`(${getSystemExportFunctionLeft([variable!], false, options)}${this.operator}${name}))`
);
} else {
let op;
switch (this.operator) {
case '++':
op = `${name}${_}+${_}1`;
break;
case '--':
op = `${name}${_}-${_}1`;
break;
}
code.overwrite(
const operator = this.operator[0];
renderSystemExportSequenceBeforeExpression(
variable,
this.start,
this.end,
`(exports('${exportNames[0]}',${_}${op}),${_}${name}${this.operator})`
this.parent.type !== NodeType.ExpressionStatement,
code,
options,
`${_}${operator}${_}1`
);
}
}
Expand Down
74 changes: 49 additions & 25 deletions src/ast/nodes/VariableDeclaration.ts
Expand Up @@ -9,8 +9,8 @@ import {
RenderOptions
} from '../../utils/renderHelpers';
import {
getSystemExportFunctionLeft,
getSystemExportStatement
getSystemExportStatement,
renderSystemExportExpression
} from '../../utils/systemJsRendering';
import { InclusionContext } from '../ExecutionContext';
import { EMPTY_PATH } from '../utils/PathTracker';
Expand Down Expand Up @@ -165,7 +165,12 @@ export default class VariableDeclaration extends NodeBase {
let separatorString = '',
leadingString,
nextSeparatorString;
const systemPatternExports: Variable[] = [];
const aggregatedSystemExports: Variable[] = [];
const singleSystemExport = gatherSystemExportsAndGetSingleExport(
separatedNodes,
options,
aggregatedSystemExports
);
for (const { node, start, separator, contentEnd, end } of separatedNodes) {
if (!node.included) {
code.remove(start, end);
Expand All @@ -186,27 +191,15 @@ export default class VariableDeclaration extends NodeBase {
}
isInDeclaration = false;
} else {
if (options.format === 'system' && node.init !== null) {
if (node.id.type !== NodeType.Identifier) {
node.id.addExportedVariables(systemPatternExports, options.exportNamesByVariable);
} else {
const exportNames = options.exportNamesByVariable.get(node.id.variable!);
if (exportNames) {
const _ = options.compact ? '' : ' ';
const operatorPos = findFirstOccurrenceOutsideComment(
code.original,
'=',
node.id.end
);
code.prependLeft(
findNonWhiteSpace(code.original, operatorPos + 1),
exportNames.length === 1
? `exports('${exportNames[0]}',${_}`
: getSystemExportFunctionLeft([node.id.variable!], false, options)
);
nextSeparatorString += ')';
}
}
if (singleSystemExport && singleSystemExport === node.id.variable) {
const operatorPos = findFirstOccurrenceOutsideComment(code.original, '=', node.id.end);
renderSystemExportExpression(
singleSystemExport,
findNonWhiteSpace(code.original, operatorPos + 1),
separator === null ? contentEnd : separator,
code,
options
);
}
if (isInDeclaration) {
separatorString += ',';
Expand Down Expand Up @@ -237,9 +230,40 @@ export default class VariableDeclaration extends NodeBase {
lastSeparatorPos,
actualContentEnd!,
renderedContentEnd,
systemPatternExports,
aggregatedSystemExports,
options,
isNoStatement
);
}
}

function gatherSystemExportsAndGetSingleExport(
separatedNodes: {
node: VariableDeclarator;
}[],
options: RenderOptions,
aggregatedSystemExports: Variable[]
): Variable | null {
let singleSystemExport: Variable | null = null;
if (options.format === 'system') {
for (const { node } of separatedNodes) {
if (
node.id instanceof Identifier &&
node.init &&
aggregatedSystemExports.length === 0 &&
options.exportNamesByVariable.get(node.id.variable!)?.length === 1
) {
singleSystemExport = node.id.variable!;
aggregatedSystemExports.push(singleSystemExport);
} else {
node.id.addExportedVariables(aggregatedSystemExports, options.exportNamesByVariable);
}
}
if (aggregatedSystemExports.length > 1) {
singleSystemExport = null;
} else if (singleSystemExport) {
aggregatedSystemExports.length = 0;
}
}
return singleSystemExport;
}
16 changes: 5 additions & 11 deletions src/finalisers/system.ts
Expand Up @@ -6,13 +6,11 @@ import { FinaliserOptions } from './index';

function getStarExcludes({ dependencies, exports }: ModuleDeclarations): Set<string> {
const starExcludes = new Set(exports.map(expt => expt.exported));
if (!starExcludes.has('default')) starExcludes.add('default');
// also include reexport names
starExcludes.add('default');
for (const { reexports } of dependencies) {
if (reexports) {
for (const reexport of reexports) {
if (reexport.imported !== '*' && !starExcludes.has(reexport.reexported))
starExcludes.add(reexport.reexported);
if (reexport.imported !== '*') starExcludes.add(reexport.reexported);
}
}
}
Expand Down Expand Up @@ -60,9 +58,7 @@ function getExportsBlock(

const getHoistedExportsBlock = (exports: ChunkExports, _: string, t: string, n: string): string =>
getExportsBlock(
exports
.filter(expt => expt.hoisted || expt.uninitialized)
.map(expt => ({ name: expt.exported, value: expt.uninitialized ? 'void 0' : expt.local })),
exports.filter(expt => expt.hoisted).map(expt => ({ name: expt.exported, value: expt.local })),
_,
t,
n
Expand Down Expand Up @@ -139,10 +135,8 @@ export default function system(
if (!starExcludes) {
starExcludes = getStarExcludes({ dependencies, exports });
}
if (!createdSetter) {
setter.push(`${varOrConst} _setter${_}=${_}{};`);
createdSetter = true;
}
createdSetter = true;
setter.push(`${varOrConst} _setter${_}=${_}{};`);
setter.push(`for${_}(var _$p${_}in${_}module)${_}{`);
setter.push(`${t}if${_}(!_starExcludes[_$p])${_}_setter[_$p]${_}=${_}module[_$p];`);
setter.push('}');
Expand Down