Skip to content

Commit

Permalink
Make sure uninitialised exports turn up via .hasOwnProperty for non-E…
Browse files Browse the repository at this point in the history
…S formats (#3957)
  • Loading branch information
lukastaegert committed Feb 12, 2021
1 parent 45d8e5e commit 3394ae9
Show file tree
Hide file tree
Showing 20 changed files with 109 additions and 48 deletions.
46 changes: 13 additions & 33 deletions src/ast/nodes/VariableDeclaration.ts
@@ -1,5 +1,6 @@
import MagicString from 'magic-string';
import { BLANK } from '../../utils/blank';
import { isReassignedExportsMember } from '../../utils/reassignedExportsMember';
import {
findFirstOccurrenceOutsideComment,
findNonWhiteSpace,
Expand All @@ -19,15 +20,6 @@ import * as NodeType from './NodeType';
import { IncludeChildren, NodeBase } from './shared/Node';
import VariableDeclarator from './VariableDeclarator';

function isReassignedExportsMember(
variable: Variable,
exportNamesByVariable: Map<Variable, string[]>
): boolean {
return (
variable.renderBaseName !== null && exportNamesByVariable.has(variable) && variable.isReassigned
);
}

function areAllDeclarationsIncludedAndNotExported(
declarations: VariableDeclarator[],
exportNamesByVariable: Map<Variable, string[]>
Expand Down Expand Up @@ -149,7 +141,7 @@ export default class VariableDeclaration extends NodeBase {
private renderReplacedDeclarations(
code: MagicString,
options: RenderOptions,
{ start = this.start, end = this.end, isNoStatement }: NodeRenderOptions
{ isNoStatement }: NodeRenderOptions
): void {
const separatedNodes = getCommaSeparatedNodesWithBoundaries(
this.declarations,
Expand All @@ -168,15 +160,7 @@ export default class VariableDeclaration extends NodeBase {
nextSeparatorString;
const systemPatternExports: Variable[] = [];
for (const { node, start, separator, contentEnd, end } of separatedNodes) {
if (
!node.included ||
(node.id instanceof Identifier &&
isReassignedExportsMember(
(node.id as IdentifierWithVariable).variable,
options.exportNamesByVariable
) &&
node.init === null)
) {
if (!node.included) {
code.remove(start, end);
continue;
}
Expand Down Expand Up @@ -240,19 +224,15 @@ export default class VariableDeclaration extends NodeBase {
lastSeparatorPos = separator!;
separatorString = nextSeparatorString;
}
if (hasRenderedContent) {
this.renderDeclarationEnd(
code,
separatorString,
lastSeparatorPos,
actualContentEnd!,
renderedContentEnd,
systemPatternExports,
options,
isNoStatement
);
} else {
code.remove(start, end);
}
this.renderDeclarationEnd(
code,
separatorString,
lastSeparatorPos,
actualContentEnd!,
renderedContentEnd,
systemPatternExports,
options,
isNoStatement
);
}
}
8 changes: 8 additions & 0 deletions src/ast/nodes/VariableDeclarator.ts
@@ -1,5 +1,6 @@
import MagicString from 'magic-string';
import { BLANK } from '../../utils/blank';
import { isReassignedExportsMember } from '../../utils/reassignedExportsMember';
import {
findFirstOccurrenceOutsideComment,
findNonWhiteSpace,
Expand All @@ -8,6 +9,7 @@ import {
import { HasEffectsContext, InclusionContext } from '../ExecutionContext';
import { ObjectPath } from '../utils/PathTracker';
import { UNDEFINED_EXPRESSION } from '../values';
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 @@ -53,6 +55,12 @@ export default class VariableDeclarator extends NodeBase {
options,
renderId ? BLANK : { renderedParentType: NodeType.ExpressionStatement }
);
} else if (
this.id instanceof Identifier &&
isReassignedExportsMember(this.id.variable!, options.exportNamesByVariable)
) {
const _ = options.compact ? '' : ' ';
code.appendLeft(this.end, `${_}=${_}void 0`);
}
}
}
10 changes: 10 additions & 0 deletions src/utils/reassignedExportsMember.ts
@@ -0,0 +1,10 @@
import Variable from '../ast/variables/Variable';

export function isReassignedExportsMember(
variable: Variable,
exportNamesByVariable: Map<Variable, string[]>
): boolean {
return (
variable.renderBaseName !== null && exportNamesByVariable.has(variable) && variable.isReassigned
);
}
3 changes: 2 additions & 1 deletion test/form/samples/assignment-to-exports/_expected/amd.js
Expand Up @@ -5,6 +5,7 @@ define(['exports'], function (exports) { 'use strict';

// Reassigned uninitialised export
exports.bar1 = 1;
exports.bar1 = void 0;

// Reassigned initialised export
exports.baz1 = 1;
Expand All @@ -14,7 +15,7 @@ define(['exports'], function (exports) { 'use strict';
var kept1, foo2, kept2;

// Reassigned uninitialised export
var kept1, kept2;
var kept1; exports.bar2 = void 0; var kept2;
exports.bar2 = 1;

// Reassigned initialised export
Expand Down
3 changes: 2 additions & 1 deletion test/form/samples/assignment-to-exports/_expected/cjs.js
Expand Up @@ -7,6 +7,7 @@ var foo1;

// Reassigned uninitialised export
exports.bar1 = 1;
exports.bar1 = void 0;

// Reassigned initialised export
exports.baz1 = 1;
Expand All @@ -16,7 +17,7 @@ exports.baz1 = 2;
var kept1, foo2, kept2;

// Reassigned uninitialised export
var kept1, kept2;
var kept1; exports.bar2 = void 0; var kept2;
exports.bar2 = 1;

// Reassigned initialised export
Expand Down
2 changes: 1 addition & 1 deletion test/form/samples/assignment-to-exports/_expected/es.js
Expand Up @@ -3,7 +3,7 @@ var foo1;

// Reassigned uninitialised export
bar1 = 1;
var bar1; // this will be removed for non ES6 bundles
var bar1;

// Reassigned initialised export
var baz1 = 1;
Expand Down
3 changes: 2 additions & 1 deletion test/form/samples/assignment-to-exports/_expected/iife.js
Expand Up @@ -6,6 +6,7 @@ var bundle = (function (exports) {

// Reassigned uninitialised export
exports.bar1 = 1;
exports.bar1 = void 0;

// Reassigned initialised export
exports.baz1 = 1;
Expand All @@ -15,7 +16,7 @@ var bundle = (function (exports) {
var kept1, foo2, kept2;

// Reassigned uninitialised export
var kept1, kept2;
var kept1; exports.bar2 = void 0; var kept2;
exports.bar2 = 1;

// Reassigned initialised export
Expand Down
Expand Up @@ -15,7 +15,7 @@ System.register('bundle', [], function (exports) {

// Reassigned uninitialised export
bar1 = exports('bar1', 1);
var bar1; // this will be removed for non ES6 bundles
var bar1;

// Reassigned initialised export
var baz1 = exports('baz1', 1);
Expand Down
3 changes: 2 additions & 1 deletion test/form/samples/assignment-to-exports/_expected/umd.js
Expand Up @@ -9,6 +9,7 @@

// Reassigned uninitialised export
exports.bar1 = 1;
exports.bar1 = void 0;

// Reassigned initialised export
exports.baz1 = 1;
Expand All @@ -18,7 +19,7 @@
var kept1, foo2, kept2;

// Reassigned uninitialised export
var kept1, kept2;
var kept1; exports.bar2 = void 0; var kept2;
exports.bar2 = 1;

// Reassigned initialised export
Expand Down
2 changes: 1 addition & 1 deletion test/form/samples/assignment-to-exports/main.js
Expand Up @@ -3,7 +3,7 @@ export var foo1;

// Reassigned uninitialised export
bar1 = 1;
export var bar1; // this will be removed for non ES6 bundles
export var bar1;

// Reassigned initialised export
export var baz1 = 1;
Expand Down
@@ -1,9 +1,9 @@
define(['exports'], function (exports) { 'use strict';

var aFoo;
var aFoo; exports.aBar = void 0;
exports.aBar = 2;

var bBar;
exports.bFoo = void 0; var bBar;
exports.bFoo = 2;

var cFoo; exports.cBar = 1;
Expand Down
Expand Up @@ -2,10 +2,10 @@

Object.defineProperty(exports, '__esModule', { value: true });

var aFoo;
var aFoo; exports.aBar = void 0;
exports.aBar = 2;

var bBar;
exports.bFoo = void 0; var bBar;
exports.bFoo = 2;

var cFoo; exports.cBar = 1;
Expand Down
@@ -1,10 +1,10 @@
var bundle = (function (exports) {
'use strict';

var aFoo;
var aFoo; exports.aBar = void 0;
exports.aBar = 2;

var bBar;
exports.bFoo = void 0; var bBar;
exports.bFoo = 2;

var cFoo; exports.cBar = 1;
Expand Down
Expand Up @@ -4,10 +4,10 @@
(global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.bundle = {}));
}(this, (function (exports) { 'use strict';

var aFoo;
var aFoo; exports.aBar = void 0;
exports.aBar = 2;

var bBar;
exports.bFoo = void 0; var bBar;
exports.bFoo = 2;

var cFoo; exports.cBar = 1;
Expand Down
@@ -0,0 +1,17 @@
const assert = require('assert');

module.exports = {
description: 'creates an export as an exports property even if is has no initializer',
options: { output: { compact: true } },
exports(exports) {
assert.strictEqual(exports.foo, undefined);
assert.strictEqual(exports.bar, undefined);
assert.strictEqual(exports.baz, undefined);
assert.ok(exports.hasOwnProperty('foo'));
assert.ok(exports.hasOwnProperty('bar'));
assert.ok(exports.hasOwnProperty('baz'));
exports.defineFooBar();
assert.strictEqual(exports.foo, 'defined');
assert.strictEqual(exports.bar, 'defined');
}
};
@@ -0,0 +1,6 @@
export let foo;
export let bar, quux = 3, baz;
export function defineFooBar() {
foo = 'defined';
bar = 'defined';
}
16 changes: 16 additions & 0 deletions test/function/samples/create-undefined-export-property/_config.js
@@ -0,0 +1,16 @@
const assert = require('assert');

module.exports = {
description: 'creates an export as an exports property even if is has no initializer',
exports(exports) {
assert.strictEqual(exports.foo, undefined);
assert.strictEqual(exports.bar, undefined);
assert.strictEqual(exports.baz, undefined);
assert.ok(exports.hasOwnProperty('foo'));
assert.ok(exports.hasOwnProperty('bar'));
assert.ok(exports.hasOwnProperty('baz'));
exports.defineFooBar();
assert.strictEqual(exports.foo, 'defined');
assert.strictEqual(exports.bar, 'defined');
}
};
@@ -0,0 +1,6 @@
export let foo;
export let bar, quux = 3, baz;
export function defineFooBar() {
foo = 'defined';
bar = 'defined';
}
3 changes: 3 additions & 0 deletions test/function/samples/destructuring-loop/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'handles loops with destructuring declarations'
};
11 changes: 11 additions & 0 deletions test/function/samples/destructuring-loop/main.js
@@ -0,0 +1,11 @@
let result;

for (const [foo] of [['foo']]) {
result = foo;
}
assert.strictEqual(result, 'foo');

for (const { bar } of [{ bar: 'bar' }]) {
result = bar;
}
assert.strictEqual(result, 'bar');

0 comments on commit 3394ae9

Please sign in to comment.