diff --git a/src/finalisers/iife.js b/src/finalisers/iife.js index 8120594..3946286 100644 --- a/src/finalisers/iife.js +++ b/src/finalisers/iife.js @@ -3,16 +3,23 @@ import { getName } from '../utils/map-helpers.js'; import getInteropBlock from './shared/getInteropBlock.js'; import getExportBlock from './shared/getExportBlock.js'; import getGlobalNameMaker from './shared/getGlobalNameMaker.js'; +import propertyStringFor from './shared/propertyStringFor'; + +// thisProp('foo.bar.baz') === "this['foo']['bar']['baz']" +const thisProp = propertyStringFor('this'); + +// propString('foo.bar') === "['foo']['bar']" +const propString = propertyStringFor(''); function setupNamespace ( keypath ) { - const parts = keypath.split( '.' ); // TODO support e.g. `foo['something-hyphenated']`? + const parts = keypath.split( '.' ); parts.pop(); let acc = 'this'; return parts - .map( part => ( acc += `.${part}`, `${acc} = ${acc} || {};` ) ) + .map( part => ( acc += propString(part), `${acc} = ${acc} || {};` ) ) .join( '\n' ) + '\n'; } @@ -31,7 +38,7 @@ export default function iife ( bundle, magicString, { exportMode, indentString, } if ( exportMode === 'named' ) { - dependencies.unshift( `(this.${name} = this.${name} || {})` ); + dependencies.unshift( `(${thisProp(name)} = ${thisProp(name)} || {})` ); args.unshift( 'exports' ); } @@ -41,7 +48,7 @@ export default function iife ( bundle, magicString, { exportMode, indentString, const wrapperOutro = `\n\n}(${dependencies}));`; if ( exportMode === 'default' ) { - wrapperIntro = ( isNamespaced ? `this.` : `${bundle.varOrConst} ` ) + `${name} = ${wrapperIntro}`; + wrapperIntro = ( isNamespaced ? thisProp(name) : `${bundle.varOrConst} ${name}` ) + ` = ${wrapperIntro}`; } if ( isNamespaced ) { diff --git a/src/finalisers/shared/propertyStringFor.js b/src/finalisers/shared/propertyStringFor.js new file mode 100644 index 0000000..f0c2948 --- /dev/null +++ b/src/finalisers/shared/propertyStringFor.js @@ -0,0 +1,17 @@ +// Generate strings which dereference dotted properties, but use array notation + +const shouldUseDot = /^[a-zA-Z$_][a-zA-Z0-9$_]*$/; +const dereferenceString = prop => + prop.match(shouldUseDot) ? `.${prop}` : `['${prop}']`; + +/** + * returns a function which generates property dereference strings for the given name + * + * const getGlobalProp = propertyStringFor('global'); + * getGlobalProp('foo.bar.baz') => `global['foo']['bar']['baz']` + */ +const propertyStringFor = objName => propName => + objName + propName.split('.').map(dereferenceString).join(''); + + +export default propertyStringFor; \ No newline at end of file diff --git a/src/finalisers/umd.js b/src/finalisers/umd.js index 67b9860..6f0541f 100644 --- a/src/finalisers/umd.js +++ b/src/finalisers/umd.js @@ -4,6 +4,13 @@ import getInteropBlock from './shared/getInteropBlock.js'; import getExportBlock from './shared/getExportBlock.js'; import getGlobalNameMaker from './shared/getGlobalNameMaker.js'; import esModuleExport from './shared/esModuleExport.js'; +import propertyStringFor from './shared/propertyStringFor.js'; + +// globalProp('foo.bar') === "global['foo']['bar']" +const globalProp = propertyStringFor('global'); + +// propString('foo.bar') === "['foo']['bar']" +const propString = propertyStringFor(''); function setupNamespace ( name ) { const parts = name.split( '.' ); @@ -11,8 +18,8 @@ function setupNamespace ( name ) { let acc = 'global'; return parts - .map( part => ( acc += `.${part}`, `${acc} = ${acc} || {}` ) ) - .concat( `global.${name}` ) + .map( part => ( acc += propString(part), `${acc} = ${acc} || {}` ) ) + .concat( globalProp(name) ) .join( ', ' ); } @@ -27,14 +34,14 @@ export default function umd ( bundle, magicString, { exportMode, indentString, i const amdDeps = bundle.externalModules.map( quotePath ); const cjsDeps = bundle.externalModules.map( req ); - const globalDeps = bundle.externalModules.map( module => `global.${globalNameMaker( module )}` ); + const globalDeps = bundle.externalModules.map( module => globalProp(globalNameMaker( module )) ); const args = bundle.externalModules.map( getName ); if ( exportMode === 'named' ) { amdDeps.unshift( `'exports'` ); cjsDeps.unshift( `exports` ); - globalDeps.unshift( `(${setupNamespace(options.moduleName)} = global.${options.moduleName} || {})` ); + globalDeps.unshift( `(${setupNamespace(options.moduleName)} = ${globalProp(options.moduleName)} || {})` ); args.unshift( 'exports' ); } @@ -50,10 +57,10 @@ export default function umd ( bundle, magicString, { exportMode, indentString, i const globalExport = options.noConflict === true ? `(function() { - var current = global.${options.moduleName}; + var current = ${globalProp(options.moduleName)}; var exports = factory(${globalDeps}); - global.${options.moduleName} = exports; - exports.noConflict = function() { global.${options.moduleName} = current; return exports; }; + ${globalProp(options.moduleName)} = exports; + exports.noConflict = function() { ${globalProp(options.moduleName)} = current; return exports; }; })()` : `(${defaultExport}factory(${globalDeps}))`; const wrapperIntro = diff --git a/test/form/module-name-scoped-package/_config.js b/test/form/module-name-scoped-package/_config.js new file mode 100644 index 0000000..5681881 --- /dev/null +++ b/test/form/module-name-scoped-package/_config.js @@ -0,0 +1,6 @@ +module.exports = { + description: 'allows module name with dashes to be added to the global object', + options: { + moduleName: '@scoped/npm-package' + } +}; diff --git a/test/form/module-name-scoped-package/_expected/amd.js b/test/form/module-name-scoped-package/_expected/amd.js new file mode 100644 index 0000000..69586a0 --- /dev/null +++ b/test/form/module-name-scoped-package/_expected/amd.js @@ -0,0 +1,9 @@ +define(['exports'], function (exports) { 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/form/module-name-scoped-package/_expected/cjs.js b/test/form/module-name-scoped-package/_expected/cjs.js new file mode 100644 index 0000000..796e3ef --- /dev/null +++ b/test/form/module-name-scoped-package/_expected/cjs.js @@ -0,0 +1,7 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +let foo = 'foo'; + +exports.foo = foo; diff --git a/test/form/module-name-scoped-package/_expected/es.js b/test/form/module-name-scoped-package/_expected/es.js new file mode 100644 index 0000000..3ee7d0b --- /dev/null +++ b/test/form/module-name-scoped-package/_expected/es.js @@ -0,0 +1,3 @@ +let foo = 'foo'; + +export { foo }; diff --git a/test/form/module-name-scoped-package/_expected/iife.js b/test/form/module-name-scoped-package/_expected/iife.js new file mode 100644 index 0000000..7445d49 --- /dev/null +++ b/test/form/module-name-scoped-package/_expected/iife.js @@ -0,0 +1,8 @@ +(function (exports) { + 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + +}((this['@scoped/npm-package'] = this['@scoped/npm-package'] || {}))); diff --git a/test/form/module-name-scoped-package/_expected/umd.js b/test/form/module-name-scoped-package/_expected/umd.js new file mode 100644 index 0000000..3382219 --- /dev/null +++ b/test/form/module-name-scoped-package/_expected/umd.js @@ -0,0 +1,13 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global['@scoped/npm-package'] = global['@scoped/npm-package'] || {}))); +}(this, (function (exports) { 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/test/form/module-name-scoped-package/main.js b/test/form/module-name-scoped-package/main.js new file mode 100644 index 0000000..816d625 --- /dev/null +++ b/test/form/module-name-scoped-package/main.js @@ -0,0 +1 @@ +export let foo = 'foo'; diff --git a/test/form/module-name-with-dashes/_config.js b/test/form/module-name-with-dashes/_config.js new file mode 100644 index 0000000..c466b88 --- /dev/null +++ b/test/form/module-name-with-dashes/_config.js @@ -0,0 +1,6 @@ +module.exports = { + description: 'allows module name with dashes to be added to the global object', + options: { + moduleName: 'module-name-with-dashes' + } +}; diff --git a/test/form/module-name-with-dashes/_expected/amd.js b/test/form/module-name-with-dashes/_expected/amd.js new file mode 100644 index 0000000..69586a0 --- /dev/null +++ b/test/form/module-name-with-dashes/_expected/amd.js @@ -0,0 +1,9 @@ +define(['exports'], function (exports) { 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}); diff --git a/test/form/module-name-with-dashes/_expected/cjs.js b/test/form/module-name-with-dashes/_expected/cjs.js new file mode 100644 index 0000000..796e3ef --- /dev/null +++ b/test/form/module-name-with-dashes/_expected/cjs.js @@ -0,0 +1,7 @@ +'use strict'; + +Object.defineProperty(exports, '__esModule', { value: true }); + +let foo = 'foo'; + +exports.foo = foo; diff --git a/test/form/module-name-with-dashes/_expected/es.js b/test/form/module-name-with-dashes/_expected/es.js new file mode 100644 index 0000000..3ee7d0b --- /dev/null +++ b/test/form/module-name-with-dashes/_expected/es.js @@ -0,0 +1,3 @@ +let foo = 'foo'; + +export { foo }; diff --git a/test/form/module-name-with-dashes/_expected/iife.js b/test/form/module-name-with-dashes/_expected/iife.js new file mode 100644 index 0000000..5eb1062 --- /dev/null +++ b/test/form/module-name-with-dashes/_expected/iife.js @@ -0,0 +1,8 @@ +(function (exports) { + 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + +}((this['module-name-with-dashes'] = this['module-name-with-dashes'] || {}))); diff --git a/test/form/module-name-with-dashes/_expected/umd.js b/test/form/module-name-with-dashes/_expected/umd.js new file mode 100644 index 0000000..8d90ff6 --- /dev/null +++ b/test/form/module-name-with-dashes/_expected/umd.js @@ -0,0 +1,13 @@ +(function (global, factory) { + typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) : + typeof define === 'function' && define.amd ? define(['exports'], factory) : + (factory((global['module-name-with-dashes'] = global['module-name-with-dashes'] || {}))); +}(this, (function (exports) { 'use strict'; + + let foo = 'foo'; + + exports.foo = foo; + + Object.defineProperty(exports, '__esModule', { value: true }); + +}))); diff --git a/test/form/module-name-with-dashes/main.js b/test/form/module-name-with-dashes/main.js new file mode 100644 index 0000000..816d625 --- /dev/null +++ b/test/form/module-name-with-dashes/main.js @@ -0,0 +1 @@ +export let foo = 'foo';