Browse Source

Add recent tests and fixes on top of 0.15.0

preserve updates and fixes

include readdirSync

assignment pattern fix

handle side-effects

update tests

fix double removal bug

reinstate sourcemaps

update tests

add missing break statement

handle export * from internal

add back tests

update all tests

skip namespace optimisation tests for now

reinstate various fixes

reinstate fast/leaner deconflicting, update tests
contingency-plan
Rich-Harris 9 years ago
parent
commit
8fdb8d9318
  1. 1
      .babelrc
  2. 4
      .eslintrc
  3. 1
      .gitignore
  4. 3
      .travis.yml
  5. 27
      CHANGELOG.md
  6. 3
      README.md
  7. 33
      appveyor.yml
  8. 4
      browser/sander.js
  9. 3
      gobblefile.js
  10. 23
      package.json
  11. 35
      src/Bundle.js
  12. 57
      src/Module.js
  13. 55
      src/Statement.js
  14. 58
      src/ast/Scope.js
  15. 7
      src/rollup.js
  16. 4
      src/utils/getExportMode.js
  17. 5
      src/utils/makeLegalIdentifier.js
  18. 6
      src/utils/path.js
  19. 40
      src/utils/resolveId.js
  20. 6
      src/utils/sourceMappingURL.js
  21. 4
      test/cli/external-modules/main.js
  22. 6
      test/form/export-all-from-internal/_config.js
  23. 9
      test/form/export-all-from-internal/_expected/amd.js
  24. 7
      test/form/export-all-from-internal/_expected/cjs.js
  25. 4
      test/form/export-all-from-internal/_expected/es6.js
  26. 9
      test/form/export-all-from-internal/_expected/iife.js
  27. 13
      test/form/export-all-from-internal/_expected/umd.js
  28. 3
      test/form/export-all-from-internal/internal.js
  29. 1
      test/form/export-all-from-internal/main.js
  30. 4
      test/form/internal-conflict-resolution/_expected/amd.js
  31. 4
      test/form/internal-conflict-resolution/_expected/cjs.js
  32. 4
      test/form/internal-conflict-resolution/_expected/es6.js
  33. 4
      test/form/internal-conflict-resolution/_expected/iife.js
  34. 4
      test/form/internal-conflict-resolution/_expected/umd.js
  35. 4
      test/form/namespace-optimization/_config.js
  36. 7
      test/form/namespace-optimization/_expected/amd.js
  37. 5
      test/form/namespace-optimization/_expected/cjs.js
  38. 3
      test/form/namespace-optimization/_expected/es6.js
  39. 7
      test/form/namespace-optimization/_expected/iife.js
  40. 11
      test/form/namespace-optimization/_expected/umd.js
  41. 3
      test/form/namespace-optimization/bar.js
  42. 3
      test/form/namespace-optimization/foo.js
  43. 3
      test/form/namespace-optimization/main.js
  44. 1
      test/form/namespace-optimization/quux.js
  45. 3
      test/form/unused-side-effect/_config.js
  46. 7
      test/form/unused-side-effect/_expected/amd.js
  47. 5
      test/form/unused-side-effect/_expected/cjs.js
  48. 3
      test/form/unused-side-effect/_expected/es6.js
  49. 7
      test/form/unused-side-effect/_expected/iife.js
  50. 11
      test/form/unused-side-effect/_expected/umd.js
  51. 13
      test/form/unused-side-effect/foo.js
  52. 2
      test/form/unused-side-effect/main.js
  53. 6
      test/function/allows-external-modules-from-nested-module/main.js
  54. 4
      test/function/assignment-patterns/_config.js
  55. 21
      test/function/assignment-patterns/main.js
  56. 8
      test/function/assignment-patterns/other.js
  57. 8
      test/function/cannot-import-self/_config.js
  58. 1
      test/function/cannot-import-self/main.js
  59. 2
      test/function/custom-path-resolver-async/_config.js
  60. 2
      test/function/custom-path-resolver-sync/_config.js
  61. 2
      test/function/duplicate-import-fails/_config.js
  62. 2
      test/function/duplicate-import-specifier-fails/_config.js
  63. 3
      test/function/dynamic-namespace-lookup/_config.js
  64. 2
      test/function/dynamic-namespace-lookup/foo.js
  65. 8
      test/function/dynamic-namespace-lookup/main.js
  66. 2
      test/function/export-not-at-top-level-fails/_config.js
  67. 11
      test/function/export-type-mismatch-b/_config.js
  68. 1
      test/function/export-type-mismatch-b/main.js
  69. 11
      test/function/export-type-mismatch-c/_config.js
  70. 1
      test/function/export-type-mismatch-c/main.js
  71. 11
      test/function/export-type-mismatch/_config.js
  72. 1
      test/function/export-type-mismatch/main.js
  73. 3
      test/function/globally-called-modifying-function/_config.js
  74. 3
      test/function/globally-called-modifying-function/main.js
  75. 17
      test/function/globally-called-modifying-function/module.js
  76. 3
      test/function/handles-multiple-declarations/_config.js
  77. 2
      test/function/handles-multiple-declarations/main.js
  78. 12
      test/function/has-modules-array/_config.js
  79. 1
      test/function/has-modules-array/foo.js
  80. 2
      test/function/has-modules-array/main.js
  81. 2
      test/function/import-default-from-external/main.js
  82. 4
      test/function/import-from-external-subdirectory/_config.js
  83. 5
      test/function/import-from-external-subdirectory/main.js
  84. 4
      test/function/import-named-from-external/main.js
  85. 2
      test/function/import-namespace-from-external-module-renamed/main.js
  86. 2
      test/function/import-namespace-from-external-module/main.js
  87. 2
      test/function/import-not-at-top-level-fails/_config.js
  88. 8
      test/function/import-of-unexported-fails/_config.js
  89. 0
      test/function/import-of-unexported-fails/empty.js
  90. 3
      test/function/import-of-unexported-fails/main.js
  91. 3
      test/function/imports-are-deconflicted-b/main.js
  92. 3
      test/function/imports-are-deconflicted/main.js
  93. 14
      test/function/modify-assumed-global/_config.js
  94. 3
      test/function/modify-assumed-global/main.js
  95. 15
      test/function/modify-assumed-global/math.js
  96. 5
      test/function/module-sort-order/_config.js
  97. 20
      test/function/module-sort-order/a.js
  98. 1
      test/function/module-sort-order/b.js
  99. 3
      test/function/module-sort-order/c.js
  100. 4
      test/function/module-sort-order/main.js

1
.babelrc

@ -5,6 +5,7 @@
"es6.classes",
"es6.constants",
"es6.destructuring",
"es6.modules",
"es6.parameters",
"es6.properties.shorthand",
"es6.spread",

4
.eslintrc

@ -4,12 +4,16 @@
"quotes": [ 2, "single" ],
"linebreak-style": [ 2, "unix" ],
"semi": [ 2, "always" ],
"space-after-keywords": [ 2, "always" ],
"space-before-blocks": [ 2, "always" ],
"space-before-function-paren": [ 2, "always" ],
"no-mixed-spaces-and-tabs": [ 2, "smart-tabs" ],
"no-cond-assign": [ 0 ]
},
"env": {
"es6": true,
"browser": true,
"mocha": true,
"node": true
},
"extends": "eslint:recommended",

1
.gitignore

@ -3,3 +3,4 @@ node_modules
.gobble*
dist
_actual
coverage

3
.travis.yml

@ -1,9 +1,8 @@
sudo: false
language: node_js
node_js:
- "0.10"
- "0.12"
- "iojs"
- "4"
env:
global:
- BUILD_TIMEOUT=10000

27
CHANGELOG.md

@ -1,5 +1,32 @@
# rollup changelog
## 0.16.4
* Fix import paths with `.` ([#133](https://github.com/rollup/rollup/issues/133))
* Prevent sourceMappingURL confusion leading to broken sourcemap
* Add code coverage reporting [#130](https://github.com/rollup/rollup/pull/130))
* Add `modules` property to user-facing `bundle` – an array with `{id}` objects ([#128](https://github.com/rollup/rollup/issues/128))
## 0.16.3
* Prevent adjacent blocks of multiple var declarations causing magic-string failure ([#105](https://github.com/rollup/rollup/issues/105))
## 0.16.2
* Top-level function calls and assignments to globals are treated as side-effects, and always included
* Import files from subdirectories of external packages, e.g. `import mod from 'foo/sub/mod'` ([#126](https://github.com/rollup/rollup/issues/126))
## 0.16.1
* Handle assignment patterns, and destructured/rest parameters, when analysing scopes
* Fix bug preventing project from self-building (make base `Identifier` class markable)
## 0.16.0
* Internal refactoring ([#99](https://github.com/rollup/rollup/pull/99))
* Optimisation for statically-analysable namespace imports ([#99](https://github.com/rollup/rollup/pull/99))
* Windows support (theoretically!) ([#117](https://github.com/rollup/rollup/pull/117) / [#119](https://github.com/rollup/rollup/pull/119))
## 0.15.0
* Load all modules specified by `import` statements, and do tree-shaking synchronously once loading is complete. This results in simpler and faster code, and enables future improvements ([#97](https://github.com/rollup/rollup/pull/97))

3
README.md

@ -17,6 +17,9 @@
<img src="https://david-dm.org/rollup/rollup.svg"
alt="dependency status">
</a>
<a href="http://codecov.io/github/rollup/rollup?branch=master">
<img src="http://codecov.io/github/rollup/rollup/coverage.svg?branch=master" alt="Coverage via Codecov" />
</a>
</p>
> *I roll up, I roll up, I roll up, Shawty I roll up*

33
appveyor.yml

@ -0,0 +1,33 @@
# http://www.appveyor.com/docs/appveyor-yml
version: "{build}"
clone_depth: 10
init:
- git config --global core.autocrlf false
environment:
matrix:
# node.js
- nodejs_version: 0.10
- nodejs_version: 0.12
# io.js
- nodejs_version: 1
install:
- ps: Install-Product node $env:nodejs_version
- npm install
build: off
test_script:
- node --version && npm --version
- npm test
matrix:
fast_finish: false
# cache:
# - C:\Users\appveyor\AppData\Roaming\npm-cache -> package.json # npm cache
# - node_modules -> package.json # local npm modules

4
browser/sander.js

@ -1,3 +1,7 @@
export function readdirSync () {
throw new Error( 'Cannot use sander.readdirSync inside browser' );
}
export function readFile () {
throw new Error( 'Cannot use sander.readFile inside browser' );
}

3
gobblefile.js

@ -8,7 +8,8 @@ var node = src
entry: 'rollup.js',
dest: 'rollup.js',
format: 'cjs',
external: [ 'sander', 'acorn' ]
external: [ 'sander', 'acorn' ],
sourceMap: true
})
.transform( 'babel' );

23
package.json

@ -1,6 +1,6 @@
{
"name": "rollup",
"version": "0.15.0",
"version": "0.17.0",
"description": "Next-generation ES6 module bundler",
"main": "dist/rollup.js",
"jsnext:main": "src/rollup.js",
@ -8,15 +8,19 @@
"rollup": "./bin/rollup"
},
"scripts": {
"test": "mocha",
"pretest": "npm run build",
"test": "mocha",
"pretest-coverage": "npm run build",
"test-coverage": "rm -rf coverage/* && istanbul cover --report json node_modules/.bin/_mocha -- -u exports -R spec test/test.js",
"posttest-coverage": "remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.json -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped.lcov -t lcovonly -b dist && remap-istanbul -i coverage/coverage-final.json -o coverage/coverage-remapped -t html -b dist",
"ci": "npm run test-coverage && codecov < coverage/coverage-remapped.lcov",
"build": "gobble build -f dist",
"prepublish": "npm test",
"lint": "eslint src"
},
"repository": {
"type": "git",
"url": "https://github.com/rich-harris/rollup"
"url": "https://github.com/rollup/rollup"
},
"keywords": [
"modules",
@ -26,13 +30,18 @@
"optimizer"
],
"author": "Rich Harris",
"contributors": [
"Oskar Segersvärd <victorystick@gmail.com>"
],
"license": "MIT",
"bugs": {
"url": "https://github.com/rich-harris/rollup/issues"
"url": "https://github.com/rollup/rollup/issues"
},
"homepage": "https://github.com/rich-harris/rollup",
"homepage": "https://github.com/rollup/rollup",
"devDependencies": {
"babel": "^5.8.21",
"babel-core": "^5.5.8",
"codecov.io": "^0.1.6",
"console-group": "^0.1.2",
"eslint": "^1.1.0",
"gobble": "^0.10.1",
@ -40,9 +49,11 @@
"gobble-browserify": "^0.6.1",
"gobble-cli": "^0.4.2",
"gobble-esperanto-bundle": "^0.2.0",
"gobble-rollup": "^0.7.0",
"gobble-rollup": "^0.8.0",
"gobble-rollup-babel": "^0.1.0",
"istanbul": "^0.3.20",
"mocha": "^2.2.4",
"remap-istanbul": "^0.2.0",
"source-map": "^0.4.4"
},
"dependencies": {

35
src/Bundle.js

@ -1,4 +1,3 @@
import { basename, extname } from './utils/path';
import { Promise } from 'sander';
import MagicString from 'magic-string';
import { blank, keys } from './utils/object';
@ -66,7 +65,7 @@ export default class Bundle {
// `export default a + b` - generate an export name
// based on the id of the entry module
else {
let defaultExportName = makeLegalIdentifier( basename( this.entryModule.id ).slice( 0, -extname( this.entryModule.id ).length ) );
let defaultExportName = this.entryModule.basename();
// deconflict
let topLevelNames = [];
@ -84,16 +83,23 @@ export default class Bundle {
entryModule.markAllStatements( true );
this.markAllModifierStatements();
// Include all side-effects
// TODO does this obviate the need for markAllStatements throughout?
this.modules.forEach( module => {
module.markAllSideEffects();
});
this.orderedModules = this.sort();
});
}
// TODO would be better to deconflict once, rather than per-render
deconflict ( es6 ) {
let usedNames = blank();
let nameCount = blank();
// ensure no conflicts with globals
keys( this.assumedGlobals ).forEach( name => usedNames[ name ] = true );
keys( this.assumedGlobals ).forEach( name => nameCount[ name ] = 0 );
let allReplacements = blank();
@ -158,11 +164,15 @@ export default class Bundle {
});
function getSafeName ( name ) {
while ( usedNames[ name ] ) {
name = `_${name}`;
if ( name in nameCount ) {
nameCount[ name ] += 1;
name = `${name}$${nameCount[ name ]}`;
while ( name in nameCount ) name = `_${name}`; // just to avoid any crazy edge cases
return name;
}
usedNames[ name ] = true;
nameCount[ name ] = 0;
return name;
}
@ -322,8 +332,7 @@ export default class Bundle {
// since we're rewriting variable exports, we want to
// ensure we don't try and export them again at the bottom
this.toExport = keys( this.entryModule.exports )
.concat( keys( this.entryModule.reexports ) )
this.toExport = this.entryModule.getExports()
.filter( key => !varExports[ key ] );
let magicString = new MagicString.Bundle({ separator: '\n\n' });
@ -501,8 +510,12 @@ export default class Bundle {
const exportDeclaration = module.exports[ name ];
if ( exportDeclaration ) return this.trace( module, exportDeclaration.localName );
const exportDelegate = module.exportDelegates[ name ];
if ( exportDelegate ) return this.traceExport( exportDelegate.module, name, es6 );
for ( let i = 0; i < module.exportAlls.length; i += 1 ) {
const declaration = module.exportAlls[i];
if ( declaration.module.exports[ name ] ) {
return this.traceExport( declaration.module, name, es6 );
}
}
throw new Error( `Could not trace binding '${name}' from ${module.id}` );
}

57
src/Module.js

@ -3,8 +3,10 @@ import MagicString from 'magic-string';
import Statement from './Statement';
import walk from './ast/walk';
import { blank, keys } from './utils/object';
import { basename, extname } from './utils/path';
import getLocation from './utils/getLocation';
import makeLegalIdentifier from './utils/makeLegalIdentifier';
import SOURCEMAPPING_URL from './utils/sourceMappingURL';
function deconflict ( name, names ) {
while ( name in names ) {
@ -37,7 +39,7 @@ export default class Module {
});
// remove existing sourceMappingURL comments
const pattern = /\/\/#\s+sourceMappingURL=.+\n?/g;
const pattern = new RegExp( `\\/\\/#\\s+${SOURCEMAPPING_URL}=.+\\n?`, 'g' );
let match;
while ( match = pattern.exec( source ) ) {
this.magicString.remove( match.index, match.index + match[0].length );
@ -243,6 +245,10 @@ export default class Module {
});
}
basename () {
return makeLegalIdentifier( basename( this.id ).slice( 0, -extname( this.id ).length ) );
}
bindImportSpecifiers () {
if ( this.boundImportSpecifiers ) return;
this.boundImportSpecifiers = true;
@ -329,6 +335,16 @@ export default class Module {
});
});
// special case – `export { ... } from './other'` in entry module
if ( this.exportAlls.length ) {
this.exportAlls.forEach( ({ source }) => {
const resolved = this.resolvedIds[ source ];
const otherModule = this.bundle.moduleById[ resolved ];
strongDependencies[ otherModule.id ] = otherModule;
});
}
return { strongDependencies, weakDependencies };
}
@ -355,6 +371,26 @@ export default class Module {
return importDeclaration.module.findDefiningStatement( name );
}
getExports () {
let exports = blank();
keys( this.exports ).forEach( name => {
exports[ name ] = true;
});
keys( this.reexports ).forEach( name => {
exports[ name ] = true;
});
this.exportAlls.forEach( ({ module }) => {
module.getExports().forEach( name => {
if ( name !== 'default' ) exports[ name ] = true;
});
});
return keys( exports );
}
mark ( name ) {
// shortcut cycles
if ( this.marked[ name ] ) return;
@ -418,6 +454,12 @@ export default class Module {
}
}
markAllSideEffects () {
this.statements.forEach( statement => {
statement.markSideEffect();
});
}
markAllStatements ( isEntryModule ) {
this.statements.forEach( statement => {
if ( statement.isIncluded ) return; // TODO can this happen? probably not...
@ -530,8 +572,12 @@ export default class Module {
// should be split up. Otherwise, we may end up including code we
// don't need, just because an unwanted declarator is included
if ( node.type === 'VariableDeclaration' && node.declarations.length > 1 ) {
// remove the leading var/let/const
// remove the leading var/let/const... UNLESS the previous node
// was also a synthetic node, in which case it'll get removed anyway
const lastStatement = statements[ statements.length - 1 ];
if ( !lastStatement || !lastStatement.node.isSynthetic ) {
this.magicString.remove( node.start, node.declarations[0].start );
}
node.declarations.forEach( declarator => {
const { start, end } = declarator;
@ -642,7 +688,12 @@ export default class Module {
statement.replaceIdentifiers( magicString, replacements, bundleExports );
// modify exports as necessary
if ( statement.isExportDeclaration ) {
if ( statement.isReexportDeclaration ) {
// remove `export { foo } from './other'` and `export * from './other'`
magicString.remove( statement.start, statement.next );
}
else if ( statement.isExportDeclaration ) {
// remove `export` from `export var foo = 42`
if ( statement.node.type === 'ExportNamedDeclaration' && statement.node.declaration.type === 'VariableDeclaration' ) {
magicString.remove( statement.node.start, statement.node.declaration.start );

55
src/Statement.js

@ -3,6 +3,16 @@ import getLocation from './utils/getLocation';
import walk from './ast/walk';
import Scope from './ast/Scope';
const blockDeclarations = {
'const': true,
'let': true
};
const modifierNodes = {
AssignmentExpression: 'left',
UpdateExpression: 'argument'
};
function isIife ( node, parent ) {
return parent && parent.type === 'CallExpression' && node === parent.callee;
}
@ -31,6 +41,7 @@ export default class Statement {
this.reassigns = blank();
this.hasSideEffects = false;
this.isIncluded = false;
this.isImportDeclaration = node.type === 'ImportDeclaration';
@ -49,7 +60,8 @@ export default class Statement {
switch ( node.type ) {
case 'FunctionDeclaration':
scope.addDeclaration( node.id.name, node, false );
scope.addDeclaration( node, false, false );
break;
case 'BlockStatement':
if ( parent && /Function/.test( parent.type ) ) {
@ -62,7 +74,7 @@ export default class Statement {
// named function expressions - the name is considered
// part of the function's scope
if ( parent.type === 'FunctionExpression' && parent.id ) {
newScope.addDeclaration( parent.id.name, parent, false );
newScope.addDeclaration( parent, false, false );
}
} else {
newScope = new Scope({
@ -84,12 +96,13 @@ export default class Statement {
case 'VariableDeclaration':
node.declarations.forEach( declarator => {
scope.addDeclaration( declarator.id.name, node, true );
const isBlockDeclaration = node.type === 'VariableDeclaration' && blockDeclarations[ node.kind ];
scope.addDeclaration( declarator, isBlockDeclaration, true );
});
break;
case 'ClassDeclaration':
scope.addDeclaration( node.id.name, node, false );
scope.addDeclaration( node, false, false );
break;
}
@ -265,6 +278,7 @@ export default class Statement {
const id = this.module.resolvedIds[ this.node.source.value ];
const otherModule = this.module.bundle.moduleById[ id ];
if ( this.node.specifiers ) {
this.node.specifiers.forEach( specifier => {
const reexport = this.module.reexports[ specifier.exported.name ];
@ -273,6 +287,13 @@ export default class Statement {
if ( !otherModule.isExternal ) otherModule.markExport( specifier.local.name, specifier.exported.name, this.module );
});
} else {
otherModule.needsAll = true;
otherModule.getExports().forEach( name => {
if ( name !== 'default' ) otherModule.markExport( name, name, this.module );
});
}
return;
}
@ -283,6 +304,32 @@ export default class Statement {
});
}
markSideEffect () {
const statement = this;
walk( this.node, {
enter ( node, parent ) {
if ( /Function/.test( node.type ) && !isIife( node, parent ) ) return this.skip();
// If this is a top-level call expression, or an assignment to a global,
// this statement will need to be marked
if ( node.type === 'CallExpression' ) {
statement.mark();
}
else if ( node.type in modifierNodes ) {
let subject = node[ modifierNodes[ node.type ] ];
while ( subject.type === 'MemberExpression' ) subject = subject.object;
const bundle = statement.module.bundle;
const canonicalName = bundle.trace( statement.module, subject.name );
if ( bundle.assumedGlobals[ canonicalName ] ) statement.mark();
}
}
});
}
replaceIdentifiers ( magicString, names, bundleExports ) {
const replacementStack = [ names ];
const nameList = keys( names );

58
src/ast/Scope.js

@ -1,10 +1,38 @@
import { blank } from '../utils/object';
const blockDeclarations = {
'const': true,
'let': true
const extractors = {
Identifier ( names, param ) {
names.push( param.name );
},
ObjectPattern ( names, param ) {
param.properties.forEach( prop => {
extractors[ prop.key.type ]( names, prop.key );
});
},
ArrayPattern ( names, param ) {
param.elements.forEach( element => {
if ( element ) extractors[ element.type ]( names, element );
});
},
RestElement ( names, param ) {
extractors[ param.argument.type ]( names, param.argument );
},
AssignmentPattern ( names, param ) {
return extractors[ param.left.type ]( names, param.left );
}
};
function extractNames ( param ) {
let names = [];
extractors[ param.type ]( names, param );
return names;
}
export default class Scope {
constructor ( options ) {
options = options || {};
@ -18,26 +46,29 @@ export default class Scope {
if ( options.params ) {
options.params.forEach( param => {
this.declarations[ param.name ] = param;
extractNames( param ).forEach( name => {
this.declarations[ name ] = true;
});
});
}
}
addDeclaration ( name, declaration, isVar ) {
const isBlockDeclaration = declaration.type === 'VariableDeclaration' && blockDeclarations[ declaration.kind ];
addDeclaration ( declaration, isBlockDeclaration, isVar ) {
if ( !isBlockDeclaration && this.isBlockScope ) {
// it's a `var` or function declaration, and this
// it's a `var` or function node, and this
// is a block scope, so we need to go up
this.parent.addDeclaration( name, declaration, isVar );
this.parent.addDeclaration( declaration, isBlockDeclaration, isVar );
} else {
this.declarations[ name ] = declaration;
extractNames( declaration.id ).forEach( name => {
this.declarations[ name ] = true;
if ( isVar ) this.varDeclarations.push( name );
});
}
}
contains ( name ) {
return !!this.getDeclaration( name );
return this.declarations[ name ] ||
( this.parent ? this.parent.contains( name ) : false );
}
findDefiningScope ( name ) {
@ -51,9 +82,4 @@ export default class Scope {
return null;
}
getDeclaration ( name ) {
return this.declarations[ name ] ||
this.parent && this.parent.getDeclaration( name );
}
}

7
src/rollup.js

@ -1,11 +1,9 @@
import { basename } from './utils/path';
import { writeFile } from 'sander';
import { keys } from './utils/object';
import SOURCEMAPPING_URL from './utils/sourceMappingURL';
import Bundle from './Bundle';
let SOURCEMAPPING_URL = 'sourceMa';
SOURCEMAPPING_URL += 'ppingURL';
export function rollup ( options ) {
if ( !options || !options.entry ) {
throw new Error( 'You must supply options.entry to rollup' );
@ -17,6 +15,9 @@ export function rollup ( options ) {
return {
imports: bundle.externalModules.map( module => module.id ),
exports: keys( bundle.entryModule.exports ),
modules: bundle.orderedModules.map( module => {
return { id: module.id };
}),
generate: options => bundle.render( options ),
write: options => {

4
src/utils/getExportMode.js

@ -5,7 +5,9 @@ function badExports ( option, keys ) {
}
export default function getExportMode ( bundle, exportMode ) {
const exportKeys = keys( bundle.entryModule.exports ).concat( keys( bundle.entryModule.reexports ) );
const exportKeys = keys( bundle.entryModule.exports )
.concat( keys( bundle.entryModule.reexports ) )
.concat( bundle.entryModule.exportAlls ); // not keys, but makes our job easier this way
if ( exportMode === 'default' ) {
if ( exportKeys.length !== 1 || exportKeys[0] !== 'default' ) {

5
src/utils/makeLegalIdentifier.js

@ -8,7 +8,10 @@ reservedWords.concat( builtins ).forEach( word => blacklisted[ word ] = true );
export default function makeLegalIdentifier ( str ) {
str = str.replace( /[^$_a-zA-Z0-9]/g, '_' );
str = str
.replace( /-(\w)/g, ( _, letter ) => letter.toUpperCase() )
.replace( /[^$_a-zA-Z0-9]/g, '_' );
if ( /\d/.test( str[0] ) || blacklisted[ str ] ) str = `_${str}`;
return str;

6
src/utils/path.js

@ -1,6 +1,6 @@
// TODO does this all work on windows?
export const absolutePath = /^(?:\/|(?:[A-Za-z]:)?\\)/;
export const absolutePath = /^(?:\/|(?:[A-Za-z]:)?[\\|\/])/;
export function isAbsolute ( path ) {
return absolutePath.test( path );
@ -35,12 +35,10 @@ export function relative ( from, to ) {
toParts.shift();
}
while ( toParts[0] && toParts[0][0] === '.' ) {
while ( toParts[0] === '.' || toParts[0] === '..' ) {
const toPart = toParts.shift();
if ( toPart === '..' ) {
fromParts.pop();
} else if ( toPart !== '.' ) {
throw new Error( `Unexpected path part (${toPart})` );
}
}

40
src/utils/resolveId.js

@ -1,5 +1,14 @@
import { absolutePath, dirname, isAbsolute, resolve } from './path';
import { readFileSync } from 'sander';
import { readdirSync, readFileSync } from 'sander';
function dirExists ( dir ) {
try {
readdirSync( dir );
return true;
} catch ( err ) {
return false;
}
}
export function defaultResolver ( importee, importer, options ) {
// absolute paths are left untouched
@ -10,8 +19,10 @@ export function defaultResolver ( importee, importer, options ) {
// we try to resolve external modules
if ( importee[0] !== '.' ) {
const [ id ] = importee.split( /[\/\\]/ );
// unless we want to keep it external, that is
if ( ~options.external.indexOf( importee ) ) return null;
if ( ~options.external.indexOf( id ) ) return null;
return options.resolveExternal( importee, importer, options );
}
@ -24,29 +35,32 @@ export function defaultExternalResolver ( id, importer ) {
const root = absolutePath.exec( importer )[0];
let dir = dirname( importer );
while ( dir !== root ) {
const pkgPath = resolve( dir, 'node_modules', id, 'package.json' );
let pkgJson;
// `foo` should use jsnext:main, but `foo/src/bar` shouldn't
const parts = id.split( /[\/\\]/ );
try {
pkgJson = readFileSync( pkgPath ).toString();
} catch ( err ) {
// noop
while ( dir !== root && dir !== '.' ) {
const modulePath = resolve( dir, 'node_modules', parts[0] );
if ( dirExists( modulePath ) ) {
// `foo/src/bar`
if ( parts.length > 1 ) {
return resolve( modulePath, ...parts.slice( 1 ) ).replace( /\.js$/, '' ) + '.js';
}
if ( pkgJson ) {
// `foo`
const pkgPath = resolve( modulePath, 'package.json' );
let pkg;
try {
pkg = JSON.parse( pkgJson );
pkg = JSON.parse( readFileSync( pkgPath ).toString() );
} catch ( err ) {
throw new Error( `Malformed JSON: ${pkgPath}` );
throw new Error( `Missing or malformed package.json: ${modulePath}` );
}
const main = pkg[ 'jsnext:main' ];
if ( !main ) {
throw new Error( `Package ${id} does not have a jsnext:main field, and so cannot be included in your rollup. Try adding it as an external module instead (e.g. options.external = ['${id}']). See https://github.com/rollup/rollup/wiki/jsnext:main for more info` );
throw new Error( `Package ${id} (imported by ${importer}) does not have a jsnext:main field, and so cannot be included in your rollup. Try adding it as an external module instead (e.g. options.external = ['${id}']). See https://github.com/rollup/rollup/wiki/jsnext:main for more info` );
}
return resolve( dirname( pkgPath ), main ).replace( /\.js$/, '' ) + '.js';

6
src/utils/sourceMappingURL.js

@ -0,0 +1,6 @@
// this looks ridiculous, but it prevents sourcemap tooling from mistaking
// this for an actual sourceMappingURL
let SOURCEMAPPING_URL = 'sourceMa';
SOURCEMAPPING_URL += 'ppingURL';
export default SOURCEMAPPING_URL;

4
test/cli/external-modules/main.js

@ -1,5 +1,5 @@
import { relative } from 'path';
import { relative, normalize } from 'path';
import { format } from 'util';
assert.equal( format( 'it %s', 'works' ), 'it works' );
assert.equal( relative( 'a/b/c', 'a/c/b' ), '../../c/b' );
assert.equal( relative( 'a/b/c', 'a/c/b' ), normalize('../../c/b') );

6
test/form/export-all-from-internal/_config.js

@ -0,0 +1,6 @@
module.exports = {
description: 'should be able to export * from the bundle',
options: {
moduleName: 'exposedInternals'
}
};

9
test/form/export-all-from-internal/_expected/amd.js

@ -0,0 +1,9 @@
define(['exports'], function (exports) { 'use strict';
const a = 1;
const b = 2;
exports.a = a;
exports.b = b;
});

7
test/form/export-all-from-internal/_expected/cjs.js

@ -0,0 +1,7 @@
'use strict';
const a = 1;
const b = 2;
exports.a = a;
exports.b = b;

4
test/form/export-all-from-internal/_expected/es6.js

@ -0,0 +1,4 @@
const a = 1;
const b = 2;
export { a, b };

9
test/form/export-all-from-internal/_expected/iife.js

@ -0,0 +1,9 @@
(function (exports) { 'use strict';
const a = 1;
const b = 2;
exports.a = a;
exports.b = b;
})((this.exposedInternals = {}));

13
test/form/export-all-from-internal/_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.exposedInternals = {}));
}(this, function (exports) { 'use strict';
const a = 1;
const b = 2;
exports.a = a;
exports.b = b;
}));

3
test/form/export-all-from-internal/internal.js

@ -0,0 +1,3 @@
export const a = 1;
export const b = 2;
export default 42;

1
test/form/export-all-from-internal/main.js

@ -0,0 +1 @@
export * from './internal.js';

4
test/form/internal-conflict-resolution/_expected/amd.js

@ -1,9 +1,9 @@
define(function () { 'use strict';
var _bar = 42;
var bar$1 = 42;
function foo () {
return _bar;
return bar$1;
}
function bar () {

4
test/form/internal-conflict-resolution/_expected/cjs.js

@ -1,9 +1,9 @@
'use strict';
var _bar = 42;
var bar$1 = 42;
function foo () {
return _bar;
return bar$1;
}
function bar () {

4
test/form/internal-conflict-resolution/_expected/es6.js

@ -1,7 +1,7 @@
var _bar = 42;
var bar$1 = 42;
function foo () {
return _bar;
return bar$1;
}
function bar () {

4
test/form/internal-conflict-resolution/_expected/iife.js

@ -1,9 +1,9 @@
(function () { 'use strict';
var _bar = 42;
var bar$1 = 42;
function foo () {
return _bar;
return bar$1;
}
function bar () {

4
test/form/internal-conflict-resolution/_expected/umd.js

@ -4,10 +4,10 @@
factory();
}(this, function () { 'use strict';
var _bar = 42;
var bar$1 = 42;
function foo () {
return _bar;
return bar$1;
}
function bar () {

4
test/form/namespace-optimization/_config.js

@ -0,0 +1,4 @@
module.exports = {
skip: true,
description: 'it does static lookup optimization of internal namespaces'
};

7
test/form/namespace-optimization/_expected/amd.js

@ -0,0 +1,7 @@
define(function () { 'use strict';
function a () {}
a();
});

5
test/form/namespace-optimization/_expected/cjs.js

@ -0,0 +1,5 @@
'use strict';
function a () {}
a();

3
test/form/namespace-optimization/_expected/es6.js

@ -0,0 +1,3 @@
function a () {}
a();

7
test/form/namespace-optimization/_expected/iife.js

@ -0,0 +1,7 @@
(function () { 'use strict';
function a () {}
a();
})();

11
test/form/namespace-optimization/_expected/umd.js

@ -0,0 +1,11 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
typeof define === 'function' && define.amd ? define(factory) :
factory();
}(this, function () { 'use strict';
function a () {}
a();
}));

3
test/form/namespace-optimization/bar.js

@ -0,0 +1,3 @@
import * as quux from './quux';
export { quux };

3
test/form/namespace-optimization/foo.js

@ -0,0 +1,3 @@
import * as bar from './bar';
export { bar };

3
test/form/namespace-optimization/main.js

@ -0,0 +1,3 @@
import * as foo from './foo';
foo.bar.quux.a();

1
test/form/namespace-optimization/quux.js

@ -0,0 +1 @@
export function a () {}

3
test/form/unused-side-effect/_config.js

@ -0,0 +1,3 @@
module.exports = {
description: 'side-effects to non-globals are not blindly included'
};

7
test/form/unused-side-effect/_expected/amd.js

@ -0,0 +1,7 @@
define(function () { 'use strict';
var foo = 42;
assert.equal( foo, 42 );
});

5
test/form/unused-side-effect/_expected/cjs.js

@ -0,0 +1,5 @@
'use strict';
var foo = 42;
assert.equal( foo, 42 );

3
test/form/unused-side-effect/_expected/es6.js

@ -0,0 +1,3 @@
var foo = 42;
assert.equal( foo, 42 );

7
test/form/unused-side-effect/_expected/iife.js

@ -0,0 +1,7 @@
(function () { 'use strict';
var foo = 42;
assert.equal( foo, 42 );
})();

11
test/form/unused-side-effect/_expected/umd.js

@ -0,0 +1,11 @@
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory() :
typeof define === 'function' && define.amd ? define(factory) :
factory();
}(this, function () { 'use strict';
var foo = 42;
assert.equal( foo, 42 );
}));

13
test/form/unused-side-effect/foo.js

@ -0,0 +1,13 @@
var uid = 0;
uid = 1;
uid += 1;
uid++;
// ensure identifiers aren't treated as globals just because
// var declaration hasn't been encountered yet...
uid2 = 1;
uid2 += 1;
uid2++;
var uid2;
export var foo = 42;

2
test/form/unused-side-effect/main.js

@ -0,0 +1,2 @@
import { foo } from './foo';
assert.equal( foo, 42 );

6
test/function/allows-external-modules-from-nested-module/main.js

@ -1,8 +1,8 @@
import { relative } from 'path';
import { relative, normalize } from 'path';
import foo from './foo';
var path = 'foo/bar/baz';
var path2 = 'foo/baz/bar';
assert.equal( relative( path, path2 ), '../../baz/bar' );
assert.equal( foo, '../../c/b' );
assert.equal( relative( path, path2 ), normalize('../../baz/bar') );
assert.equal( foo, normalize('../../c/b') );

4
test/function/assignment-patterns/_config.js

@ -0,0 +1,4 @@
module.exports = {
description: 'allows reassigments to default parameters that shadow imports',
babel: true
};

21
test/function/assignment-patterns/main.js

@ -0,0 +1,21 @@
import { bar, baz, x, items, p, q, r, s } from './other';
function foo ( bar = 1, { baz } = { baz: 2 }, [[[,x = 3] = []] = []] = [], ...items ) {
bar += 1;
baz += 1;
x += 1;
let { p, q } = { p: 4, q: 5 };
let [ r, s ] = [ 6, 7 ];
p++;
q += 1;
r = 7;
s = 6;
return bar + baz + x + items.length + p + q + r + s;
}
assert.equal( foo(), 33 );
assert.equal( foo( 2 ), 34 );
assert.equal( foo( 2, { baz: 3 }, [[[99,10]]], 'a', 'b', 'c' ), 45 );

8
test/function/assignment-patterns/other.js

@ -0,0 +1,8 @@
export const bar = 'bar';
export const baz = 'baz';
export const x = 'x';
export const items = 'items';
export const p = 'p';
export const q = 'q';
export const r = 'r';
export const s = 's';

8
test/function/cannot-import-self/_config.js

@ -0,0 +1,8 @@
var assert = require( 'assert' );
module.exports = {
description: 'prevents a module importing itself',
error: function ( err ) {
assert.ok( /A module cannot import itself/.test( err.message ) );
}
};

1
test/function/cannot-import-self/main.js

@ -0,0 +1 @@
import me from './main';

2
test/function/custom-path-resolver-async/_config.js

@ -8,7 +8,7 @@ module.exports = {
var Promise = require( 'sander' ).Promise;
var resolved;
if ( importee === path.resolve( __dirname, 'main.js' ) ) return importee;
if ( path.normalize(importee) === path.resolve( __dirname, 'main.js' ) ) return importee;
if ( importee === 'foo' ) {
resolved = path.resolve( __dirname, 'bar.js' );

2
test/function/custom-path-resolver-sync/_config.js

@ -5,7 +5,7 @@ module.exports = {
description: 'uses a custom path resolver (synchronous)',
options: {
resolveId: function ( importee, importer ) {
if ( importee === path.resolve( __dirname, 'main.js' ) ) return importee;
if ( path.normalize(importee) === path.resolve( __dirname, 'main.js' ) ) return importee;
if ( importee === 'foo' ) return path.resolve( __dirname, 'bar.js' );
return false;

2
test/function/duplicate-import-fails/_config.js

@ -4,7 +4,7 @@ var assert = require( 'assert' );
module.exports = {
description: 'disallows duplicate imports',
error: function ( err ) {
assert.equal( err.file, path.resolve( __dirname, 'main.js' ) );
assert.equal( path.normalize(err.file), path.resolve( __dirname, 'main.js' ) );
assert.deepEqual( err.loc, { line: 2, column: 9 });
assert.ok( /Duplicated import/.test( err.message ) );
}

2
test/function/duplicate-import-specifier-fails/_config.js

@ -4,7 +4,7 @@ var assert = require( 'assert' );
module.exports = {
description: 'disallows duplicate import specifiers',
error: function ( err ) {
assert.equal( err.file, path.resolve( __dirname, 'main.js' ) );
assert.equal( path.normalize(err.file), path.resolve( __dirname, 'main.js' ) );
assert.deepEqual( err.loc, { line: 1, column: 12 });
assert.ok( /Duplicated import/.test( err.message ) );
}

3
test/function/dynamic-namespace-lookup/_config.js

@ -0,0 +1,3 @@
module.exports = {
description: 'does namespace optimization when possible, but not for dynamic lookups'
};

2
test/function/dynamic-namespace-lookup/foo.js

@ -0,0 +1,2 @@
export var bar = 'bar';
export var baz = 'baz';

8
test/function/dynamic-namespace-lookup/main.js

@ -0,0 +1,8 @@
import * as foo from './foo';
var bar = 'baz';
assert.equal( foo.bar, 'bar' );
assert.equal( foo.baz, 'baz' );
assert.equal( foo[ bar ], 'baz' );

2
test/function/export-not-at-top-level-fails/_config.js

@ -4,7 +4,7 @@ var assert = require( 'assert' );
module.exports = {
description: 'disallows non-top-level exports',
error: function ( err ) {
assert.equal( err.file, path.resolve( __dirname, 'main.js' ) );
assert.equal( path.normalize(err.file), path.resolve( __dirname, 'main.js' ) );
assert.deepEqual( err.loc, { line: 2, column: 2 });
assert.ok( /may only appear at the top level/.test( err.message ) );
}

11
test/function/export-type-mismatch-b/_config.js

@ -0,0 +1,11 @@
var assert = require( 'assert' );
module.exports = {
description: 'export type must be auto, default, named or none',
bundleOptions: {
exports: 'blah'
},
generateError: function ( err ) {
assert.ok( /options\.exports must be 'default', 'named', 'none', 'auto', or left unspecified/.test( err.message ) );
}
};

1
test/function/export-type-mismatch-b/main.js

@ -0,0 +1 @@
export default 42;

11
test/function/export-type-mismatch-c/_config.js

@ -0,0 +1,11 @@
var assert = require( 'assert' );
module.exports = {
description: 'cannot have named exports if explicit export type is default',
bundleOptions: {
exports: 'none'
},
generateError: function ( err ) {
assert.ok( /'none' was specified for options\.exports/.test( err.message ) );
}
};

1
test/function/export-type-mismatch-c/main.js

@ -0,0 +1 @@
export default 42;

11
test/function/export-type-mismatch/_config.js

@ -0,0 +1,11 @@
var assert = require( 'assert' );
module.exports = {
description: 'cannot have named exports if explicit export type is default',
bundleOptions: {
exports: 'default'
},
generateError: function ( err ) {
assert.ok( /'default' was specified for options\.exports/.test( err.message ) );
}
};

1
test/function/export-type-mismatch/main.js

@ -0,0 +1 @@
export var foo = 42;

3
test/function/globally-called-modifying-function/_config.js

@ -0,0 +1,3 @@
module.exports = {
description: 'globally called function should be included if it modifies an exported value (#112)'
};

3
test/function/globally-called-modifying-function/main.js

@ -0,0 +1,3 @@
import value from './module.js';
assert.equal( value, 3 );

17
test/function/globally-called-modifying-function/module.js

@ -0,0 +1,17 @@
var value = 1;
function change () {
value = 2;
}
function changeAgain () {
value += 1;
}
change();
if ( true ) {
changeAgain();
}
export default value;

3
test/function/handles-multiple-declarations/_config.js

@ -0,0 +1,3 @@
module.exports = {
description: 'handles multiple declaration blocks with multiple declarations (#105)'
};

2
test/function/handles-multiple-declarations/main.js

@ -0,0 +1,2 @@
var a, b;
var c, d;

12
test/function/has-modules-array/_config.js

@ -0,0 +1,12 @@
var path = require( 'path' );
var assert = require( 'assert' );
module.exports = {
description: 'user-facing bundle has modules array',
bundle: function ( bundle ) {
assert.ok( bundle.modules );
assert.equal( bundle.modules.length, 2 );
assert.equal( path.relative(bundle.modules[0].id, path.resolve(__dirname, 'foo.js')), '' );
assert.equal( path.relative(bundle.modules[1].id, path.resolve(__dirname, 'main.js')), '' );
}
};

1
test/function/has-modules-array/foo.js

@ -0,0 +1 @@
export default 42;

2
test/function/has-modules-array/main.js

@ -0,0 +1,2 @@
import foo from './foo';
assert.equal( foo, 42 );

2
test/function/import-default-from-external/main.js

@ -4,4 +4,4 @@ import path from 'path';
var path1 = 'foo/bar/baz';
var path2 = 'foo/baz/bar';
assert.equal( path.relative( path1, path2 ), '../../baz/bar' );
assert.equal( path.relative( path1, path2 ), path.normalize('../../baz/bar') );

4
test/function/import-from-external-subdirectory/_config.js

@ -0,0 +1,4 @@
module.exports = {
description: 'default resolver imports from a subdirectory of an external module',
babel: true
};

5
test/function/import-from-external-subdirectory/main.js

@ -0,0 +1,5 @@
// this test is brittle, it relies on this dependency continuing
// to be structured in a certain way
import btoa from 'magic-string/src/utils/btoa';
assert.equal( btoa( 'it works' ), new Buffer( 'it works' ).toString( 'base64' ) );

4
test/function/import-named-from-external/main.js

@ -1,6 +1,6 @@
import { relative } from 'path';
import { relative, normalize } from 'path';
var path = 'foo/bar/baz';
var path2 = 'foo/baz/bar';
assert.equal( relative( path, path2 ), '../../baz/bar' );
assert.equal( relative( path, path2 ), normalize('../../baz/bar') );

2
test/function/import-namespace-from-external-module-renamed/main.js

@ -3,4 +3,4 @@ import * as node_path from 'path';
var path1 = 'foo/bar/baz';
var path2 = 'foo/baz/bar';
assert.equal( node_path.relative( path1, path2 ), '../../baz/bar' );
assert.equal( node_path.relative( path1, path2 ), node_path.normalize('../../baz/bar') );

2
test/function/import-namespace-from-external-module/main.js

@ -3,4 +3,4 @@ import * as path from 'path';
var path1 = 'foo/bar/baz';
var path2 = 'foo/baz/bar';
assert.equal( path.relative( path1, path2 ), '../../baz/bar' );
assert.equal( path.relative( path1, path2 ), path.normalize('../../baz/bar') );

2
test/function/import-not-at-top-level-fails/_config.js

@ -4,7 +4,7 @@ var assert = require( 'assert' );
module.exports = {
description: 'disallows non-top-level imports',
error: function ( err ) {
assert.equal( err.file, path.resolve( __dirname, 'main.js' ) );
assert.equal( path.normalize(err.file), path.resolve( __dirname, 'main.js' ) );
assert.deepEqual( err.loc, { line: 2, column: 2 });
assert.ok( /may only appear at the top level/.test( err.message ) );
}

8
test/function/import-of-unexported-fails/_config.js

@ -0,0 +1,8 @@
var assert = require( 'assert' );
module.exports = {
description: 'marking an imported, but unexported, identifier should throw',
error: function ( err ) {
assert.ok( /Module .+empty\.js does not export default \(imported by .+main\.js\)/.test( err.message ) );
}
};

0
test/function/import-of-unexported-fails/empty.js

3
test/function/import-of-unexported-fails/main.js

@ -0,0 +1,3 @@
import a from './empty.js';
a();

3
test/function/imports-are-deconflicted-b/main.js

@ -1,5 +1,6 @@
import foo from './foo';
import bar from './bar';
import { normalize } from 'path';
assert.equal( foo, 'foo' );
assert.equal( bar(), '../../baz/bar' );
assert.equal( bar(), normalize('../../baz/bar') );

3
test/function/imports-are-deconflicted/main.js

@ -1,5 +1,6 @@
import foo from './foo';
import bar from './bar';
import { normalize } from 'path';
assert.equal( foo, 'foo' );
assert.equal( bar(), '../../baz/bar' );
assert.equal( bar(), normalize('../../baz/bar') );

14
test/function/modify-assumed-global/_config.js

@ -0,0 +1,14 @@
var assert = require( 'assert' );
var Math = {};
module.exports = {
description: 'side-effects to assumed globals are included',
context: {
Math: Math
},
exports: function ( exports ) {
assert.equal( Math.square( 3 ), 9 );
assert.equal( Math.cube( 3 ), 27 );
}
};

3
test/function/modify-assumed-global/main.js

@ -0,0 +1,3 @@
import { square } from './math';
assert.equal( square( 2 ), 4 );

15
test/function/modify-assumed-global/math.js

@ -0,0 +1,15 @@
function square ( x ) {
return x * x;
}
function cube ( x ) {
return x * x * x;
}
Math.square = square;
if ( true ) {
Math.cube = cube;
}
export { square };

5
test/function/module-sort-order/_config.js

@ -0,0 +1,5 @@
module.exports = {
// solo: true,
// show: true,
description: 'module sorter is not confused by top-level call expressions'
};

20
test/function/module-sort-order/a.js

@ -0,0 +1,20 @@
import { b } from './b';
import z from './z';
z();
const p = {
q: function () {
b.nope();
}
};
(function () {
const p = {
q: function () {
b.nope();
}
};
})();
export default 42;

1
test/function/module-sort-order/b.js

@ -0,0 +1 @@
export const b = function () {};

3
test/function/module-sort-order/c.js

@ -0,0 +1,3 @@
import { b } from './b';
export const c = function () {};

4
test/function/module-sort-order/main.js

@ -0,0 +1,4 @@
import a from './a';
import z from './z';
z();

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save