diff --git a/src/Bundle.js b/src/Bundle.js index b92ffea..4b875b8 100644 --- a/src/Bundle.js +++ b/src/Bundle.js @@ -39,7 +39,9 @@ export default class Bundle { this.statements = null; this.externalModules = []; this.internalNamespaceModules = []; + this.assumedGlobals = blank(); + this.assumedGlobals.exports = true; // TODO strictly speaking, this only applies with non-ES6, non-default-only bundles } build () { @@ -91,16 +93,14 @@ export default class Bundle { // Assign names to external modules this.externalModules.forEach( module => { - // TODO is this right? let name = makeLegalIdentifier( module.suggestedNames['*'] || module.suggestedNames.default || module.id ); - if ( definers[ name ] ) { + while ( definers[ name ] ) { conflicts[ name ] = true; - } else { - definers[ name ] = []; + name = `_${name}`; } - definers[ name ].push( module ); + definers[ name ] = [ module ]; module.name = name; this.assumedGlobals[ name ] = true; }); @@ -186,12 +186,24 @@ export default class Bundle { return this.modulePromises[ importee ]; } + if ( id === importer ) { + throw new Error( `A module cannot import itself (${id})` ); + } + if ( !this.modulePromises[ id ] ) { this.modulePromises[ id ] = Promise.resolve( this.load( id, this.loadOptions ) ) .then( source => { + let ast; + + if ( typeof source === 'object' ) { + ast = source.ast; + source = source.code; + } + const module = new Module({ id, source, + ast, bundle: this }); @@ -315,7 +327,10 @@ export default class Bundle { const exportKeys = keys( module.exports ); return `var ${module.getCanonicalName('*', format === 'es6')} = {\n` + - exportKeys.map( key => `${indentString}get ${key} () { return ${module.getCanonicalName(key, format === 'es6')}; }` ).join( ',\n' ) + + exportKeys.map( key => { + const localName = module.exports[ key ].localName; + return `${indentString}get ${key} () { return ${module.getCanonicalName(localName, format === 'es6')}; }`; + }).join( ',\n' ) + `\n};\n\n`; }).join( '' ); @@ -335,6 +350,9 @@ export default class Bundle { indentString: getIndentString( magicString, options ) }, options ); + if ( options.banner ) magicString.prepend( options.banner + '\n' ); + if ( options.footer ) magicString.append( '\n' + options.footer ); + const code = magicString.toString(); let map = null; diff --git a/src/Module.js b/src/Module.js index 3cf9b8a..9790351 100644 --- a/src/Module.js +++ b/src/Module.js @@ -29,7 +29,7 @@ function isEmptyExportedVarDeclaration ( node, module, allBundleExports, es6 ) { } export default class Module { - constructor ({ id, source, bundle }) { + constructor ({ id, source, ast, bundle }) { this.source = source; this.bundle = bundle; @@ -41,10 +41,17 @@ export default class Module { filename: id }); + // remove existing sourceMappingURL comments + const pattern = /\/\/#\s+sourceMappingURL=.+\n?/g; + let match; + while ( match = pattern.exec( source ) ) { + this.magicString.remove( match.index, match.index + match[0].length ); + } + this.suggestedNames = blank(); this.comments = []; - this.statements = this._parse(); + this.statements = this._parse( ast ); // imports and exports, indexed by ID this.imports = blank(); @@ -510,21 +517,22 @@ export default class Module { } // TODO rename this to parse, once https://github.com/rollup/rollup/issues/42 is fixed - _parse () { - // Try to extract a list of top-level statements/declarations. If - // the parse fails, attach file info and abort - let ast; - - try { - ast = parse( this.source, { - ecmaVersion: 6, - sourceType: 'module', - onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }) - }); - } catch ( err ) { - err.code = 'PARSE_ERROR'; - err.file = this.id; // see above - not necessarily true, but true enough - throw err; + _parse ( ast ) { + // The ast can be supplied programmatically (but usually won't be) + if ( !ast ) { + // Try to extract a list of top-level statements/declarations. If + // the parse fails, attach file info and abort + try { + ast = parse( this.source, { + ecmaVersion: 6, + sourceType: 'module', + onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }) + }); + } catch ( err ) { + err.code = 'PARSE_ERROR'; + err.file = this.id; // see above - not necessarily true, but true enough + throw err; + } } walk( ast, { @@ -633,7 +641,11 @@ export default class Module { // split up/remove var declarations as necessary if ( statement.node.isSynthetic ) { - magicString.insert( statement.start, `${statement.node.kind} ` ); + // insert `var/let/const` if necessary + if ( !allBundleExports[ statement.node.declarations[0].id.name ] ) { + magicString.insert( statement.start, `${statement.node.kind} ` ); + } + magicString.overwrite( statement.end, statement.next, ';\n' ); // TODO account for trailing newlines } diff --git a/src/Statement.js b/src/Statement.js index 6583861..6828981 100644 --- a/src/Statement.js +++ b/src/Statement.js @@ -90,7 +90,11 @@ export default class Statement { } if ( newScope ) { - Object.defineProperty( node, '_scope', { value: newScope }); + Object.defineProperty( node, '_scope', { + value: newScope, + configurable: true + }); + scope = newScope; } }, diff --git a/src/finalisers/amd.js b/src/finalisers/amd.js index 02a947b..831de3a 100644 --- a/src/finalisers/amd.js +++ b/src/finalisers/amd.js @@ -1,5 +1,6 @@ import { getName, quoteId } from '../utils/map-helpers'; import getInteropBlock from './shared/getInteropBlock'; +import getExportBlock from './shared/getExportBlock'; export default function amd ( bundle, magicString, { exportMode, indentString }, options ) { let deps = bundle.externalModules.map( quoteId ); @@ -11,27 +12,17 @@ export default function amd ( bundle, magicString, { exportMode, indentString }, } const params = - ( options.moduleId ? `['${options.moduleId}'], ` : `` ) + + ( options.moduleId ? `'${options.moduleId}', ` : `` ) + ( deps.length ? `[${deps.join( ', ' )}], ` : `` ); - const intro = `define(${params}function (${args.join( ', ' )}) { 'use strict';\n\n`; + const useStrict = options.useStrict !== false ? ` 'use strict';` : ``; + const intro = `define(${params}function (${args.join( ', ' )}) {${useStrict}\n\n`; // var foo__default = 'default' in foo ? foo['default'] : foo; const interopBlock = getInteropBlock( bundle ); if ( interopBlock ) magicString.prepend( interopBlock + '\n\n' ); - const exports = bundle.entryModule.exports; - - let exportBlock; - - if ( exportMode === 'default' ) { - exportBlock = `return ${bundle.entryModule.getCanonicalName('default')};`; - } else { - exportBlock = bundle.toExport.map( name => { - return `exports.${name} = ${exports[name].localName};`; - }).join( '\n' ); - } - + const exportBlock = getExportBlock( bundle, exportMode ); if ( exportBlock ) magicString.append( '\n\n' + exportBlock ); return magicString diff --git a/src/finalisers/cjs.js b/src/finalisers/cjs.js index 1f2f92a..034273d 100644 --- a/src/finalisers/cjs.js +++ b/src/finalisers/cjs.js @@ -1,5 +1,7 @@ -export default function cjs ( bundle, magicString, { exportMode }) { - let intro = `'use strict';\n\n`; +import getExportBlock from './shared/getExportBlock'; + +export default function cjs ( bundle, magicString, { exportMode }, options ) { + let intro = options.useStrict === false ? `` : `'use strict';\n\n`; // TODO handle empty imports, once they're supported const importBlock = bundle.externalModules @@ -21,23 +23,8 @@ export default function cjs ( bundle, magicString, { exportMode }) { magicString.prepend( intro ); - let exportBlock; - if ( exportMode === 'default' && bundle.entryModule.exports.default ) { - exportBlock = `module.exports = ${bundle.entryModule.getCanonicalName('default')};`; - } else if ( exportMode === 'named' ) { - exportBlock = bundle.toExport - .map( key => { - const specifier = bundle.entryModule.exports[ key ]; - const name = bundle.entryModule.getCanonicalName( specifier.localName ); - - return `exports.${key} = ${name};`; - }) - .join( '\n' ); - } - - if ( exportBlock ) { - magicString.append( '\n\n' + exportBlock ); - } + const exportBlock = getExportBlock( bundle, exportMode, 'module.exports =' ); + if ( exportBlock ) magicString.append( '\n\n' + exportBlock ); return magicString; } diff --git a/src/finalisers/iife.js b/src/finalisers/iife.js index dd6b6d0..fef3978 100644 --- a/src/finalisers/iife.js +++ b/src/finalisers/iife.js @@ -1,6 +1,7 @@ import { blank } from '../utils/object'; import { getName } from '../utils/map-helpers'; import getInteropBlock from './shared/getInteropBlock'; +import getExportBlock from './shared/getExportBlock'; export default function iife ( bundle, magicString, { exportMode, indentString }, options ) { const globalNames = options.globals || blank(); @@ -20,19 +21,20 @@ export default function iife ( bundle, magicString, { exportMode, indentString } args.unshift( 'exports' ); } - let intro = `(function (${args}) { 'use strict';\n\n`; + const useStrict = options.useStrict !== false ? ` 'use strict';` : ``; + let intro = `(function (${args}) {${useStrict}\n\n`; let outro = `\n\n})(${dependencies});`; - // var foo__default = 'default' in foo ? foo['default'] : foo; - const interopBlock = getInteropBlock( bundle ); - if ( interopBlock ) magicString.prepend( interopBlock + '\n\n' ); - if ( exportMode === 'default' ) { intro = `var ${options.moduleName} = ${intro}`; - magicString.append( `\n\nreturn ${bundle.entryModule.getCanonicalName('default')};` ); } - // TODO named exports + // var foo__default = 'default' in foo ? foo['default'] : foo; + const interopBlock = getInteropBlock( bundle ); + if ( interopBlock ) magicString.prepend( interopBlock + '\n\n' ); + + const exportBlock = getExportBlock( bundle, exportMode ); + if ( exportBlock ) magicString.append( '\n\n' + exportBlock ); return magicString .indent( indentString ) diff --git a/src/finalisers/shared/getExportBlock.js b/src/finalisers/shared/getExportBlock.js new file mode 100644 index 0000000..c02c727 --- /dev/null +++ b/src/finalisers/shared/getExportBlock.js @@ -0,0 +1,12 @@ +export default function getExportBlock ( bundle, exportMode, mechanism = 'return' ) { + if ( exportMode === 'default' ) { + return `${mechanism} ${bundle.entryModule.getCanonicalName('default')};`; + } + + return bundle.toExport + .map( name => { + const prop = name === 'default' ? `['default']` : `.${name}`; + return `exports${prop} = ${bundle.entryModule.getCanonicalName(name)};`; + }) + .join( '\n' ); +} diff --git a/src/finalisers/shared/getInteropBlock.js b/src/finalisers/shared/getInteropBlock.js index 2fadc3a..8060e00 100644 --- a/src/finalisers/shared/getInteropBlock.js +++ b/src/finalisers/shared/getInteropBlock.js @@ -1,6 +1,12 @@ export default function getInteropBlock ( bundle ) { return bundle.externalModules - .filter( module => module.needsDefault && module.needsNamed ) - .map( module => `var ${module.name}__default = 'default' in ${module.name} ? ${module.name}['default'] : ${module.name};` ) + .map( module => { + return module.needsDefault ? + ( module.needsNamed ? + `var ${module.name}__default = 'default' in ${module.name} ? ${module.name}['default'] : ${module.name};` : + `${module.name} = 'default' in ${module.name} ? ${module.name}['default'] : ${module.name};` ) : + null; + }) + .filter( Boolean ) .join( '\n' ); } diff --git a/src/finalisers/umd.js b/src/finalisers/umd.js index 8dc20ff..d2f01db 100644 --- a/src/finalisers/umd.js +++ b/src/finalisers/umd.js @@ -1,6 +1,7 @@ import { blank } from '../utils/object'; import { getName, quoteId, req } from '../utils/map-helpers'; import getInteropBlock from './shared/getInteropBlock'; +import getExportBlock from './shared/getExportBlock'; export default function umd ( bundle, magicString, { exportMode, indentString }, options ) { if ( exportMode !== 'none' && !options.moduleName ) { @@ -26,18 +27,20 @@ export default function umd ( bundle, magicString, { exportMode, indentString }, } const amdParams = - ( options.moduleId ? `['${options.moduleId}'], ` : `` ) + + ( options.moduleId ? `'${options.moduleId}', ` : `` ) + ( amdDeps.length ? `[${amdDeps.join( ', ' )}], ` : `` ); const cjsExport = exportMode === 'default' ? `module.exports = ` : ``; const defaultExport = exportMode === 'default' ? `global.${options.moduleName} = ` : ''; + const useStrict = options.useStrict !== false ? ` 'use strict';` : ``; + const intro = `(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? ${cjsExport}factory(${cjsDeps.join( ', ' )}) : typeof define === 'function' && define.amd ? define(${amdParams}factory) : ${defaultExport}factory(${globalDeps}); - }(this, function (${args}) { 'use strict'; + }(this, function (${args}) {${useStrict} `.replace( /^\t\t/gm, '' ).replace( /^\t/gm, magicString.getIndentString() ); @@ -45,23 +48,8 @@ export default function umd ( bundle, magicString, { exportMode, indentString }, const interopBlock = getInteropBlock( bundle ); if ( interopBlock ) magicString.prepend( interopBlock + '\n\n' ); - const exports = bundle.entryModule.exports; - - let exportBlock; - - if ( exportMode === 'default' ) { - const canonicalName = bundle.entryModule.getCanonicalName( 'default' ); - exportBlock = `return ${canonicalName};`; - } else { - exportBlock = bundle.toExport.map( name => { - const canonicalName = bundle.entryModule.getCanonicalName( exports[ name ].localName ); - return `exports.${name} = ${canonicalName};`; - }).join( '\n' ); - } - - if ( exportBlock ) { - magicString.append( '\n\n' + exportBlock ); - } + const exportBlock = getExportBlock( bundle, exportMode ); + if ( exportBlock ) magicString.append( '\n\n' + exportBlock ); return magicString .trim() diff --git a/src/rollup.js b/src/rollup.js index 846c8f2..ee2b3b0 100644 --- a/src/rollup.js +++ b/src/rollup.js @@ -1,5 +1,6 @@ import { basename } from './utils/path'; import { writeFile } from 'sander'; +import { keys } from './utils/object'; import Bundle from './Bundle'; let SOURCEMAPPING_URL = 'sourceMa'; @@ -14,6 +15,9 @@ export function rollup ( options ) { return bundle.build().then( () => { return { + imports: bundle.externalModules.map( module => module.id ), + exports: keys( bundle.entryModule.exports ), + generate: options => bundle.render( options ), write: options => { if ( !options || !options.dest ) { diff --git a/test/form/banner-and-footer/_config.js b/test/form/banner-and-footer/_config.js new file mode 100644 index 0000000..cc113e0 --- /dev/null +++ b/test/form/banner-and-footer/_config.js @@ -0,0 +1,7 @@ +module.exports = { + description: 'adds a banner/footer', + options: { + banner: '/* this is a banner */', + footer: '/* this is a footer */' + } +}; diff --git a/test/form/banner-and-footer/_expected/amd.js b/test/form/banner-and-footer/_expected/amd.js new file mode 100644 index 0000000..86e9835 --- /dev/null +++ b/test/form/banner-and-footer/_expected/amd.js @@ -0,0 +1,7 @@ +/* this is a banner */ +define(function () { 'use strict'; + + console.log( 'hello world' ); + +}); +/* this is a footer */ diff --git a/test/form/banner-and-footer/_expected/cjs.js b/test/form/banner-and-footer/_expected/cjs.js new file mode 100644 index 0000000..90c4119 --- /dev/null +++ b/test/form/banner-and-footer/_expected/cjs.js @@ -0,0 +1,5 @@ +/* this is a banner */ +'use strict'; + +console.log( 'hello world' ); +/* this is a footer */ diff --git a/test/form/banner-and-footer/_expected/es6.js b/test/form/banner-and-footer/_expected/es6.js new file mode 100644 index 0000000..93e3dfb --- /dev/null +++ b/test/form/banner-and-footer/_expected/es6.js @@ -0,0 +1,3 @@ +/* this is a banner */ +console.log( 'hello world' ); +/* this is a footer */ diff --git a/test/form/banner-and-footer/_expected/iife.js b/test/form/banner-and-footer/_expected/iife.js new file mode 100644 index 0000000..8135f24 --- /dev/null +++ b/test/form/banner-and-footer/_expected/iife.js @@ -0,0 +1,7 @@ +/* this is a banner */ +(function () { 'use strict'; + + console.log( 'hello world' ); + +})(); +/* this is a footer */ diff --git a/test/form/banner-and-footer/_expected/umd.js b/test/form/banner-and-footer/_expected/umd.js new file mode 100644 index 0000000..74dd673 --- /dev/null +++ b/test/form/banner-and-footer/_expected/umd.js @@ -0,0 +1,11 @@ +/* this is a banner */ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + factory(); +}(this, function () { 'use strict'; + + console.log( 'hello world' ); + +})); +/* this is a footer */ diff --git a/test/form/banner-and-footer/main.js b/test/form/banner-and-footer/main.js new file mode 100644 index 0000000..3b5a604 --- /dev/null +++ b/test/form/banner-and-footer/main.js @@ -0,0 +1 @@ +console.log( 'hello world' ); diff --git a/test/form/external-imports-custom-names/_expected/amd.js b/test/form/external-imports-custom-names/_expected/amd.js index 9cb5e1a..936a550 100644 --- a/test/form/external-imports-custom-names/_expected/amd.js +++ b/test/form/external-imports-custom-names/_expected/amd.js @@ -1,5 +1,7 @@ define(['jquery'], function ($) { 'use strict'; + $ = 'default' in $ ? $['default'] : $; + $( function () { $( 'body' ).html( '

hello world!

' ); }); diff --git a/test/form/external-imports-custom-names/_expected/iife.js b/test/form/external-imports-custom-names/_expected/iife.js index 1ff0551..4b34e9b 100644 --- a/test/form/external-imports-custom-names/_expected/iife.js +++ b/test/form/external-imports-custom-names/_expected/iife.js @@ -1,5 +1,7 @@ (function ($) { 'use strict'; + $ = 'default' in $ ? $['default'] : $; + $( function () { $( 'body' ).html( '

hello world!

' ); }); diff --git a/test/form/external-imports-custom-names/_expected/umd.js b/test/form/external-imports-custom-names/_expected/umd.js index e8013aa..8912390 100644 --- a/test/form/external-imports-custom-names/_expected/umd.js +++ b/test/form/external-imports-custom-names/_expected/umd.js @@ -4,6 +4,8 @@ factory(global.jQuery); }(this, function ($) { 'use strict'; + $ = 'default' in $ ? $['default'] : $; + $( function () { $( 'body' ).html( '

hello world!

' ); }); diff --git a/test/form/external-imports/_expected/amd.js b/test/form/external-imports/_expected/amd.js index 8e696cb..a259937 100644 --- a/test/form/external-imports/_expected/amd.js +++ b/test/form/external-imports/_expected/amd.js @@ -1,5 +1,6 @@ define(['factory', 'baz', 'shipping-port', 'alphabet'], function (factory, baz, containers, alphabet) { 'use strict'; + factory = 'default' in factory ? factory['default'] : factory; var alphabet__default = 'default' in alphabet ? alphabet['default'] : alphabet; factory( null ); diff --git a/test/form/external-imports/_expected/iife.js b/test/form/external-imports/_expected/iife.js index 897ee39..e3857fb 100644 --- a/test/form/external-imports/_expected/iife.js +++ b/test/form/external-imports/_expected/iife.js @@ -1,5 +1,6 @@ (function (factory,baz,containers,alphabet) { 'use strict'; + factory = 'default' in factory ? factory['default'] : factory; var alphabet__default = 'default' in alphabet ? alphabet['default'] : alphabet; factory( null ); diff --git a/test/form/external-imports/_expected/umd.js b/test/form/external-imports/_expected/umd.js index f6064c8..196c394 100644 --- a/test/form/external-imports/_expected/umd.js +++ b/test/form/external-imports/_expected/umd.js @@ -4,6 +4,7 @@ factory(global.factory,global.baz,global.containers,global.alphabet); }(this, function (factory,baz,containers,alphabet) { 'use strict'; + factory = 'default' in factory ? factory['default'] : factory; var alphabet__default = 'default' in alphabet ? alphabet['default'] : alphabet; factory( null ); diff --git a/test/form/removes-existing-sourcemap-comments/_config.js b/test/form/removes-existing-sourcemap-comments/_config.js new file mode 100644 index 0000000..e1b917a --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'removes existing sourcemap comments' +}; diff --git a/test/form/removes-existing-sourcemap-comments/_expected/amd.js b/test/form/removes-existing-sourcemap-comments/_expected/amd.js new file mode 100644 index 0000000..e614344 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_expected/amd.js @@ -0,0 +1,9 @@ +define(function () { 'use strict'; + + function foo () { + return 42; + } + + console.log( foo() ); + +}); diff --git a/test/form/removes-existing-sourcemap-comments/_expected/cjs.js b/test/form/removes-existing-sourcemap-comments/_expected/cjs.js new file mode 100644 index 0000000..d7a8df2 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_expected/cjs.js @@ -0,0 +1,7 @@ +'use strict'; + +function foo () { + return 42; +} + +console.log( foo() ); diff --git a/test/form/removes-existing-sourcemap-comments/_expected/es6.js b/test/form/removes-existing-sourcemap-comments/_expected/es6.js new file mode 100644 index 0000000..c458828 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_expected/es6.js @@ -0,0 +1,5 @@ +function foo () { + return 42; +} + +console.log( foo() ); diff --git a/test/form/removes-existing-sourcemap-comments/_expected/iife.js b/test/form/removes-existing-sourcemap-comments/_expected/iife.js new file mode 100644 index 0000000..07a64a4 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_expected/iife.js @@ -0,0 +1,9 @@ +(function () { 'use strict'; + + function foo () { + return 42; + } + + console.log( foo() ); + +})(); diff --git a/test/form/removes-existing-sourcemap-comments/_expected/umd.js b/test/form/removes-existing-sourcemap-comments/_expected/umd.js new file mode 100644 index 0000000..79f644c --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/_expected/umd.js @@ -0,0 +1,13 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory() : + typeof define === 'function' && define.amd ? define(factory) : + factory(); +}(this, function () { 'use strict'; + + function foo () { + return 42; + } + + console.log( foo() ); + +})); diff --git a/test/form/removes-existing-sourcemap-comments/foo.js b/test/form/removes-existing-sourcemap-comments/foo.js new file mode 100644 index 0000000..74fda08 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/foo.js @@ -0,0 +1,5 @@ +export default function () { + return 42; +} + +//# sourceMappingURL=foo.js.map diff --git a/test/form/removes-existing-sourcemap-comments/main.js b/test/form/removes-existing-sourcemap-comments/main.js new file mode 100644 index 0000000..3c48af8 --- /dev/null +++ b/test/form/removes-existing-sourcemap-comments/main.js @@ -0,0 +1,5 @@ +import foo from './foo'; + +console.log( foo() ); + +//# sourceMappingURL=main.js.map diff --git a/test/function/deconflicts-exports/_config.js b/test/function/deconflicts-exports/_config.js new file mode 100644 index 0000000..8724967 --- /dev/null +++ b/test/function/deconflicts-exports/_config.js @@ -0,0 +1,10 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'renames variables named `exports` if necessary', + exports: function ( exports ) { + assert.deepEqual( Object.keys( exports ), [ 'a', 'b' ] ); + assert.equal( exports.a, 'A' ); + assert.equal( exports.b, 42 ); + } +}; diff --git a/test/function/deconflicts-exports/main.js b/test/function/deconflicts-exports/main.js new file mode 100644 index 0000000..ea04690 --- /dev/null +++ b/test/function/deconflicts-exports/main.js @@ -0,0 +1,8 @@ +var exports = { + number: 21 +}; + +export var a = 'A'; +export var b = exports.number * 2; + +assert.deepEqual( Object.keys( exports ), [ 'number' ]); diff --git a/test/function/deconflicts-external-imports/_config.js b/test/function/deconflicts-external-imports/_config.js new file mode 100644 index 0000000..5d981c0 --- /dev/null +++ b/test/function/deconflicts-external-imports/_config.js @@ -0,0 +1,13 @@ +module.exports = { + description: 'deconflicts external imports', + context: { + require: function ( id ) { + return function () { + return id; + }; + } + }, + options: { + external: [ 'foo', 'bar' ] + } +}; diff --git a/test/function/deconflicts-external-imports/a.js b/test/function/deconflicts-external-imports/a.js new file mode 100644 index 0000000..b5f4daa --- /dev/null +++ b/test/function/deconflicts-external-imports/a.js @@ -0,0 +1,5 @@ +import foo from 'foo'; + +export default function () { + assert.equal( foo(), 'foo' ); +} diff --git a/test/function/deconflicts-external-imports/b.js b/test/function/deconflicts-external-imports/b.js new file mode 100644 index 0000000..8316a4a --- /dev/null +++ b/test/function/deconflicts-external-imports/b.js @@ -0,0 +1,5 @@ +import foo from 'bar'; + +export default function () { + assert.equal( foo(), 'bar' ); +} diff --git a/test/function/deconflicts-external-imports/main.js b/test/function/deconflicts-external-imports/main.js new file mode 100644 index 0000000..6527271 --- /dev/null +++ b/test/function/deconflicts-external-imports/main.js @@ -0,0 +1,5 @@ +import a from './a'; +import b from './b'; + +a(); +b(); diff --git a/test/function/export-and-import-reference-share-var/_config.js b/test/function/export-and-import-reference-share-var/_config.js new file mode 100644 index 0000000..321e785 --- /dev/null +++ b/test/function/export-and-import-reference-share-var/_config.js @@ -0,0 +1,10 @@ +var assert = require( 'assert' ); + +module.exports = { + description: 'allows export and import reference to share name', + exports: function ( exports ) { + assert.equal( exports.b, 9 ); + } +}; + +// adapted from es6-module-transpiler diff --git a/test/function/export-and-import-reference-share-var/foo.js b/test/function/export-and-import-reference-share-var/foo.js new file mode 100644 index 0000000..e284e3a --- /dev/null +++ b/test/function/export-and-import-reference-share-var/foo.js @@ -0,0 +1,2 @@ +export var a = 1; +assert.equal(a, 1); diff --git a/test/function/export-and-import-reference-share-var/main.js b/test/function/export-and-import-reference-share-var/main.js new file mode 100644 index 0000000..f37ca04 --- /dev/null +++ b/test/function/export-and-import-reference-share-var/main.js @@ -0,0 +1,13 @@ +import { a } from './foo'; + +// This variable declaration is going to be altered because `b` needs to be +// re-written. We need to make sure that the `a` re-writing and the unaffected +// `c` declarator are not being clobbered by that alteration. +var a_ = a, b = 9, c = 'c'; + +assert.equal(a, 1); +assert.equal(a_, 1); +assert.equal(b, 9); +assert.equal(c, 'c'); + +export { b }; diff --git a/test/function/import-namespace-from-internal-module-renamed/_config.js b/test/function/import-namespace-from-internal-module-renamed/_config.js new file mode 100644 index 0000000..77f908a --- /dev/null +++ b/test/function/import-namespace-from-internal-module-renamed/_config.js @@ -0,0 +1,3 @@ +module.exports = { + description: 'correctly exports x as y inside a bundle' +}; diff --git a/test/function/import-namespace-from-internal-module-renamed/foo.js b/test/function/import-namespace-from-internal-module-renamed/foo.js new file mode 100644 index 0000000..6a9cd7c --- /dev/null +++ b/test/function/import-namespace-from-internal-module-renamed/foo.js @@ -0,0 +1,3 @@ +var x = 42; + +export { x as y }; diff --git a/test/function/import-namespace-from-internal-module-renamed/main.js b/test/function/import-namespace-from-internal-module-renamed/main.js new file mode 100644 index 0000000..12aa3ee --- /dev/null +++ b/test/function/import-namespace-from-internal-module-renamed/main.js @@ -0,0 +1,3 @@ +import * as foo from './foo'; + +assert.equal( foo.y, 42 ); diff --git a/test/function/uses-supplied-ast/_config.js b/test/function/uses-supplied-ast/_config.js new file mode 100644 index 0000000..fff6bd6 --- /dev/null +++ b/test/function/uses-supplied-ast/_config.js @@ -0,0 +1,34 @@ +var acorn = require( 'acorn' ); + +var modules = { + 'main': 'import foo from \'foo\';\nfoo();', + + // the code points to './bar' but the AST points to './baz', so we + // can check the AST is being used + 'foo': { + code: 'import bar from \'bar\';\nexport default function foo () {\n\tconsole.log( bar );\n}', + ast: acorn.parse( 'import bar from \'baz\';\nexport default function foo () {\n\tconsole.log( bar );\n}', { + ecmaVersion: 6, + sourceType: 'module' + }) + }, + + 'baz': 'export default 42;' +}; + +module.exports = { + description: 'uses supplied AST', + options: { + resolveId: function ( importee, importer ) { + if ( !importer ) return 'main'; + return importee; + }, + load: function ( id ) { + if ( id === 'bar' ) { + throw new Error( 'loaded incorrect module' ); + } + + return modules[ id ]; + } + } +};