Skip to content

Commit

Permalink
Handle namespaces that reexport themselves (#3077)
Browse files Browse the repository at this point in the history
* Create test

* Separate namespace initialisation from creation to prevent an infinite recursion

* Throw for unexpected warnings in form tests

This should also reduce test noise a lot

* Update dependencies and fix vulnerability

* Add test that guesses variable names to improve coverage again

* Test that warnings can be cast to string

* Retrigger CI
  • Loading branch information
lukastaegert committed Aug 25, 2019
1 parent a7e5ff2 commit 2c93e33
Show file tree
Hide file tree
Showing 84 changed files with 975 additions and 467 deletions.
1,016 changes: 627 additions & 389 deletions package-lock.json

Large diffs are not rendered by default.

16 changes: 8 additions & 8 deletions package.json
Expand Up @@ -66,17 +66,17 @@
"@types/micromatch": "^3.1.0",
"@types/minimist": "^1.2.0",
"acorn-import-meta": "^1.0.0",
"acorn-jsx": "^5.0.1",
"acorn-jsx": "^5.0.2",
"acorn-walk": "^7.0.0",
"buble": "^0.19.8",
"chokidar": "^2.1.6",
"chokidar": "^2.1.8",
"codecov": "^3.5.0",
"console-group": "^0.3.3",
"core-js": "^3.2.1",
"date-time": "^3.1.0",
"es5-shim": "^4.5.13",
"es6-shim": "^0.35.5",
"eslint": "^6.1.0",
"eslint": "^6.2.1",
"eslint-plugin-import": "^2.18.2",
"execa": "^2.0.4",
"fixturify": "^1.2.0",
Expand All @@ -87,7 +87,7 @@
"lint-staged": "^9.2.3",
"locate-character": "^2.0.5",
"magic-string": "^0.25.3",
"markdownlint-cli": "^0.17.0",
"markdownlint-cli": "^0.18.0",
"micromatch": "^4.0.2",
"minimist": "^1.2.0",
"mocha": "^6.2.0",
Expand All @@ -97,8 +97,8 @@
"pretty-ms": "^5.0.0",
"require-relative": "^0.8.7",
"requirejs": "^2.3.6",
"rollup": "^1.19.4",
"rollup-plugin-alias": "^1.5.2",
"rollup": "^1.20.1",
"rollup-plugin-alias": "^2.0.0",
"rollup-plugin-buble": "^0.19.8",
"rollup-plugin-commonjs": "^10.0.2",
"rollup-plugin-json": "^4.0.0",
Expand All @@ -116,9 +116,9 @@
"source-map-support": "^0.5.13",
"sourcemap-codec": "^1.4.6",
"systemjs": "^5.0.0",
"terser": "^4.1.4",
"terser": "^4.2.0",
"tslib": "^1.10.0",
"tslint": "^5.18.0",
"tslint": "^5.19.0",
"turbocolor": "^2.6.1",
"typescript": "^3.5.3",
"url-parse": "^1.4.7"
Expand Down
6 changes: 4 additions & 2 deletions rollup.config.js
Expand Up @@ -135,8 +135,10 @@ function fixAcornEsmImport() {

const moduleAliases = {
resolve: ['.js', '.json', '.md'],
'help.md': path.resolve('cli/help.md'),
'package.json': path.resolve('package.json')
entries: [
{ find: 'help.md', replacement: path.resolve('cli/help.md') },
{ find: 'package.json', replacement: path.resolve('package.json') }
]
};

const treeshake = {
Expand Down
8 changes: 5 additions & 3 deletions src/Module.ts
Expand Up @@ -342,9 +342,11 @@ export default class Module {
}

getOrCreateNamespace(): NamespaceVariable {
return (
this.namespaceVariable || (this.namespaceVariable = new NamespaceVariable(this.astContext))
);
if (!this.namespaceVariable) {
this.namespaceVariable = new NamespaceVariable(this.astContext);
this.namespaceVariable.initialise();
}
return this.namespaceVariable;
}

getReexports(): string[] {
Expand Down
11 changes: 7 additions & 4 deletions src/ast/variables/NamespaceVariable.ts
Expand Up @@ -19,10 +19,6 @@ export default class NamespaceVariable extends Variable {
super(context.getModuleName());
this.context = context;
this.module = context.module;
for (const name of this.context.getExports().concat(this.context.getReexports())) {
if (name[0] === '*' && name.length > 1) this.containsExternalNamespace = true;
this.memberVariables[name] = this.context.traceExport(name);
}
}

addReference(identifier: Identifier) {
Expand Down Expand Up @@ -69,6 +65,13 @@ export default class NamespaceVariable extends Variable {
}
}

initialise() {
for (const name of this.context.getExports().concat(this.context.getReexports())) {
if (name[0] === '*' && name.length > 1) this.containsExternalNamespace = true;
this.memberVariables[name] = this.context.traceExport(name);
}
}

renderBlock(options: RenderOptions) {
const _ = options.compact ? '' : ' ';
const n = options.compact ? '' : '\n';
Expand Down
13 changes: 9 additions & 4 deletions test/form/index.js
Expand Up @@ -21,10 +21,15 @@ runTestSuiteWithSamples('form', path.resolve(__dirname, 'samples'), (dir, config
extend(
{
input: dir + '/main.js',
onwarn: msg => {
if (/No name was provided for/.test(msg)) return;
if (/as external dependency/.test(msg)) return;
console.error(msg);
onwarn: warning => {
if (
!(config.expectedWarnings && config.expectedWarnings.indexOf(warning.code) >= 0)
) {
throw new Error(
`Unexpected warnings (${warning.code}): ${warning.message}\n` +
'If you expect warnings, list their codes in config.expectedWarnings'
);
}
},
strictDeprecations: true
},
Expand Down
@@ -1,3 +1,4 @@
module.exports = {
description: 'Tree-shake known object prototype functions'
description: 'Tree-shake known object prototype functions',
expectedWarnings: ['EMPTY_BUNDLE']
};
4 changes: 4 additions & 0 deletions test/form/samples/compact-multiple-imports/_config.js
Expand Up @@ -5,6 +5,10 @@ module.exports = {
return id.startsWith('external');
},
output: {
globals: {
'external-3': 'external3',
'external-4': 'external4'
},
compact: true
}
}
Expand Down
6 changes: 5 additions & 1 deletion test/form/samples/compact/_config.js
@@ -1,11 +1,15 @@
module.exports = {
description: 'compact output with compact: true',
expectedWarnings: ['CIRCULAR_DEPENDENCY'],
options: {
external: ['external'],
output: {
name: 'foo',
compact: true,
namespaceToStringTag: true
namespaceToStringTag: true,
globals: {
external: 'x'
}
}
}
};
8 changes: 7 additions & 1 deletion test/form/samples/conflicting-imports/_config.js
@@ -1,6 +1,12 @@
module.exports = {
description: 'ensures bundle imports are deconflicted (#659)',
options: {
external: ['foo', 'bar']
external: ['foo', 'bar'],
output: {
globals: {
bar: 'bar',
foo: 'foo'
}
}
}
};
@@ -1,5 +1,6 @@
module.exports = {
description: 'allows custom module-specific context with a function option',
expectedWarnings: ['THIS_IS_UNDEFINED'],
options: {
moduleContext(id) {
return /main\.js$/.test(id) ? 'lolwut' : 'undefined';
Expand Down
1 change: 1 addition & 0 deletions test/form/samples/custom-module-context/_config.js
@@ -1,5 +1,6 @@
module.exports = {
description: 'allows custom module-specific context',
expectedWarnings: ['THIS_IS_UNDEFINED'],
options: {
moduleContext: {
'main.js': 'lolwut'
Expand Down
Expand Up @@ -3,6 +3,7 @@ module.exports = {
options: {
external: 'external',
output: {
globals: { external: 'external' },
name: 'bundle'
}
}
Expand Down
1 change: 1 addition & 0 deletions test/form/samples/dedupes-external-imports/_config.js
Expand Up @@ -3,6 +3,7 @@ module.exports = {
options: {
external: ['external'],
output: {
globals: { external: 'external' },
name: 'myBundle'
}
}
Expand Down
@@ -1,8 +1,11 @@
module.exports = {
description: 'prunes pure unused external imports ([#1352])',
options: {
strictDeprecations: false,
external: ['external', 'other'],
treeshake: { pureExternalModules: ['external'] }
},
description: 'prunes pure unused external imports ([#1352])'
treeshake: { pureExternalModules: ['external'] },
output: {
globals: { other: 'other' }
}
}
};
@@ -1,8 +1,12 @@
module.exports = {
description: 'prunes pure unused external imports ([#1352])',
expectedWarnings: ['EMPTY_BUNDLE'],
options: {
strictDeprecations: false,
external: ['external', 'other'],
treeshake: { pureExternalModules: id => id === 'external' }
},
description: 'prunes pure unused external imports ([#1352])'
treeshake: { pureExternalModules: id => id === 'external' },
output: {
globals: { other: 'other' }
}
}
};
@@ -1,8 +1,9 @@
module.exports = {
description: 'prunes pure unused external imports ([#1352])',
expectedWarnings: ['EMPTY_BUNDLE'],
options: {
strictDeprecations: false,
external: ['external', 'other'],
treeshake: { pureExternalModules: true }
},
description: 'prunes pure unused external imports ([#1352])'
}
};
Expand Up @@ -2,6 +2,7 @@ const assert = require('assert');

module.exports = {
description: 'plugin .transformBundle gets passed options',
expectedWarnings: ['DEPRECATED_FEATURE'],
options: {
strictDeprecations: false,
plugins: [
Expand Down
@@ -1,10 +1,11 @@
module.exports = {
description: 'allows plugins to transform bundle',
expectedWarnings: ['DEPRECATED_FEATURE'],
options: {
strictDeprecations: false,
plugins: [
{
transformBundle(code) {
transformBundle() {
return '/* first plugin */';
}
},
Expand Down
5 changes: 4 additions & 1 deletion test/form/samples/export-all-before-named/_config.js
@@ -1,7 +1,10 @@
module.exports = {
description: 'external `export *` must not interfere with internal exports',
options: {
output: { name: 'exposedInternals' },
output: {
globals: { external: 'external' },
name: 'exposedInternals'
},
external: ['external']
}
};
5 changes: 4 additions & 1 deletion test/form/samples/export-default-import/_config.js
Expand Up @@ -2,6 +2,9 @@ module.exports = {
description: 'correctly exports a default import, even in ES mode (#513)',
options: {
external: ['x'],
output: { name: 'myBundle' }
output: {
globals: { x: 'x' },
name: 'myBundle'
}
}
};
1 change: 1 addition & 0 deletions test/form/samples/external-deshadowing/_config.js
Expand Up @@ -3,6 +3,7 @@ module.exports = {
options: {
external: ['a', 'b'],
output: {
globals: { a: 'a', b: 'b' },
name: 'myBundle'
}
}
Expand Down
2 changes: 1 addition & 1 deletion test/form/samples/external-deshadowing/_expected/iife.js
Expand Up @@ -16,4 +16,4 @@ var myBundle = (function (exports, a, Test$1) {

return exports;

}({}, a, Test$1));
}({}, a, b));
2 changes: 1 addition & 1 deletion test/form/samples/external-deshadowing/_expected/umd.js
@@ -1,7 +1,7 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('a'), require('b')) :
typeof define === 'function' && define.amd ? define(['exports', 'a', 'b'], factory) :
(global = global || self, factory(global.myBundle = {}, global.a, global.Test$1));
(global = global || self, factory(global.myBundle = {}, global.a, global.b));
}(this, function (exports, a, Test$1) { 'use strict';

Test$1 = Test$1 && Test$1.hasOwnProperty('default') ? Test$1['default'] : Test$1;
Expand Down
1 change: 1 addition & 0 deletions test/form/samples/external-export-tracing/_config.js
Expand Up @@ -3,6 +3,7 @@ module.exports = {
options: {
external: ['external'],
output: {
globals: { external: 'external' },
name: 'myBundle'
}
}
Expand Down
5 changes: 4 additions & 1 deletion test/form/samples/external-import-alias-shadow/_config.js
@@ -1,6 +1,9 @@
module.exports = {
description: 'handles external aliased named imports that shadow another name',
options: {
external: ['acorn']
external: ['acorn'],
output: {
globals: { acorn: 'acorn' }
}
}
};
11 changes: 10 additions & 1 deletion test/form/samples/external-imports/_config.js
@@ -1,6 +1,15 @@
module.exports = {
description: 'prefixes global names with `global.` when creating UMD bundle (#57)',
expectedWarnings: ['UNUSED_EXTERNAL_IMPORT'],
options: {
external: ['factory', 'baz', 'shipping-port', 'alphabet']
external: ['factory', 'baz', 'shipping-port', 'alphabet'],
output: {
globals: {
alphabet: 'alphabet',
baz: 'baz',
factory: 'factory',
'shipping-port': 'containers'
}
}
}
};
5 changes: 4 additions & 1 deletion test/form/samples/external-namespace-and-named/_config.js
@@ -1,6 +1,9 @@
module.exports = {
description: 'Correctly handles external namespace tracing with both namespace and named exports',
options: {
external: ['foo']
external: ['foo'],
output: {
globals: { foo: 'foo' }
}
}
};
1 change: 1 addition & 0 deletions test/form/samples/external-namespace-reexport/_config.js
Expand Up @@ -3,6 +3,7 @@ module.exports = {
options: {
external: ['highcharts'],
output: {
globals: { highcharts: 'highcharts' },
name: 'myBundle'
}
}
Expand Down
15 changes: 15 additions & 0 deletions test/form/samples/guessed-global-names/_config.js
@@ -0,0 +1,15 @@
const { resolve } = require('path');

module.exports = {
description: 'guesses global names if necessary',
expectedWarnings: ['MISSING_GLOBAL_NAME'],
options: {
external: [
'unchanged',
'changed',
'special-character',
'with/slash',
resolve(__dirname, 'relative.js')
]
}
};
7 changes: 7 additions & 0 deletions test/form/samples/guessed-global-names/_expected/amd.js
@@ -0,0 +1,7 @@
define(['unchanged', 'changed', 'special-character', 'with/slash', './relative'], function (unchanged, changedName, specialCharacter, slash, relative_js) { 'use strict';

changedName = changedName && changedName.hasOwnProperty('default') ? changedName['default'] : changedName;

console.log(unchanged.foo, changedName, specialCharacter.bar, slash.baz, relative_js.quux);

});

0 comments on commit 2c93e33

Please sign in to comment.