Skip to content

Commit

Permalink
Merge branch 'master' into gh-438-b
Browse files Browse the repository at this point in the history
  • Loading branch information
Rich-Harris committed Jan 21, 2016
2 parents caa6576 + c750730 commit f543f3e
Show file tree
Hide file tree
Showing 20 changed files with 134 additions and 18 deletions.
9 changes: 9 additions & 0 deletions CHANGELOG.md
@@ -1,5 +1,14 @@
# rollup changelog

## 0.25.1

* Throw error if namespace is called ([#446](https://github.com/rollup/rollup/issues/446))
* Prevent shadowing bug in ES6 output ([#441](https://github.com/rollup/rollup/pull/441))
* Prevent `var exports.foo` ([#426](https://github.com/rollup/rollup/issues/426))
* Prevent double export of aliased symbols ([#438](https://github.com/rollup/rollup/issues/438))
* Provide more informative error if Rollup is used in-browser without appropriate `resolveId`/`load` hooks ([#275](https://github.com/rollup/rollup/issues/275))
* Use `_interopDefault` function to DRY out code with many external dependencies, in CommonJS output ([#458](https://github.com/rollup/rollup/pull/458))

## 0.25.0

* **breaking** Module order is determined according to spec, rather than in a way designed to prevent runtime errors. Rollup will warn if it detects runtime errors are likely ([#435](https://github.com/rollup/rollup/issues/435))
Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "rollup",
"version": "0.25.0",
"version": "0.25.1",
"description": "Next-generation ES6 module bundler",
"main": "dist/rollup.js",
"jsnext:main": "src/rollup.js",
Expand Down
3 changes: 1 addition & 2 deletions src/Bundle.js
Expand Up @@ -63,7 +63,7 @@ export default class Bundle {
this.onwarn = options.onwarn || makeOnwarn();

// TODO strictly speaking, this only applies with non-ES6, non-default-only bundles
[ 'module', 'exports' ].forEach( global => this.assumedGlobals[ global ] = true );
[ 'module', 'exports', '_interopDefault' ].forEach( global => this.assumedGlobals[ global ] = true );
}

build () {
Expand Down Expand Up @@ -360,7 +360,6 @@ export default class Bundle {
});
}


return ordered;
}
}
4 changes: 3 additions & 1 deletion src/Declaration.js
Expand Up @@ -135,6 +135,7 @@ export class SyntheticDefaultDeclaration {

export class SyntheticNamespaceDeclaration {
constructor ( module ) {
this.isNamespace = true;
this.module = module;
this.name = null;

Expand Down Expand Up @@ -221,9 +222,10 @@ export class ExternalDeclaration {
constructor ( module, name ) {
this.module = module;
this.name = name;
this.safeName = null;
this.isExternal = true;

this.safeName = null;
this.isNamespace = name === '*';
}

addAlias () {
Expand Down
20 changes: 14 additions & 6 deletions src/finalisers/cjs.js
Expand Up @@ -3,17 +3,25 @@ import getExportBlock from './shared/getExportBlock.js';
export default function cjs ( bundle, magicString, { exportMode }, options ) {
let intro = options.useStrict === false ? `` : `'use strict';\n\n`;

const hasDefaultImport = bundle.externalModules.some( mod => mod.declarations.default);

if (hasDefaultImport) {
intro += `function _interopDefault (ex) { return 'default' in ex ? ex['default'] : ex; }\n\n`;
}

// TODO handle empty imports, once they're supported
const importBlock = bundle.externalModules
.map( module => {
let requireStatement = `var ${module.name} = require('${module.id}');`;

if ( module.declarations.default ) {
requireStatement += '\n' + ( module.exportsNames ? `var ${module.name}__default = ` : `${module.name} = ` ) +
`'default' in ${module.name} ? ${module.name}['default'] : ${module.name};`;
if (module.exportsNames) {
return `var ${module.name} = require('${module.id}');` +
`\nvar ${module.name}__default = _interopDefault(${module.name});`;
} else {
return `var ${module.name} = _interopDefault(require('${module.id}'));`;
}
} else {
return `var ${module.name} = require('${module.id}');`;
}

return requireStatement;
})
.join( '\n' );

Expand Down
2 changes: 2 additions & 0 deletions src/utils/defaults.js
Expand Up @@ -16,6 +16,8 @@ function addJsExtensionIfNecessary ( file ) {
}

export function resolveId ( importee, importer ) {
if ( typeof process === 'undefined' ) throw new Error( `It looks like you're using Rollup in a non-Node.js environment. This means you must supply a plugin with custom resolveId and load functions. See https://github.com/rollup/rollup/wiki/Plugins for more information` );

// absolute paths are left untouched
if ( isAbsolute( importee ) ) return addJsExtensionIfNecessary( importee );

Expand Down
9 changes: 9 additions & 0 deletions src/utils/error.js
@@ -0,0 +1,9 @@
export default function error ( props ) {
const err = new Error( props.message );

Object.keys( props ).forEach( key => {
err[ key ] = props[ key ];
});

throw err;
}
16 changes: 15 additions & 1 deletion src/utils/run.js
Expand Up @@ -3,6 +3,8 @@ import modifierNodes, { isModifierNode } from '../ast/modifierNodes.js';
import isReference from '../ast/isReference.js';
import flatten from '../ast/flatten';
import pureFunctions from './pureFunctions.js';
import getLocation from './getLocation.js';
import error from './error.js';

function call ( callee, scope, statement, strongDependencies ) {
while ( callee.type === 'ParenthesizedExpression' ) callee = callee.expression;
Expand All @@ -11,7 +13,19 @@ function call ( callee, scope, statement, strongDependencies ) {
const declaration = scope.findDeclaration( callee.name ) ||
statement.module.trace( callee.name );

if ( declaration ) return declaration.run( strongDependencies );
if ( declaration ) {
if ( declaration.isNamespace ) {
error({
message: `Cannot call a namespace ('${callee.name}')`,
file: statement.module.id,
pos: callee.start,
loc: getLocation( statement.module.code, callee.start )
});
}

return declaration.run( strongDependencies );
}

return !pureFunctions[ callee.name ];
}

Expand Down
7 changes: 4 additions & 3 deletions test/form/external-imports-custom-names/_expected/cjs.js
@@ -1,8 +1,9 @@
'use strict';

var $ = require('jquery');
$ = 'default' in $ ? $['default'] : $;
function _interopDefault (ex) { return 'default' in ex ? ex['default'] : ex; }

var $ = _interopDefault(require('jquery'));

$( function () {
$( 'body' ).html( '<h1>hello world!</h1>' );
});
});
9 changes: 5 additions & 4 deletions test/form/external-imports/_expected/cjs.js
@@ -1,14 +1,15 @@
'use strict';

var factory = require('factory');
factory = 'default' in factory ? factory['default'] : factory;
function _interopDefault (ex) { return 'default' in ex ? ex['default'] : ex; }

var factory = _interopDefault(require('factory'));
var baz = require('baz');
var containers = require('shipping-port');
var alphabet = require('alphabet');
var alphabet__default = 'default' in alphabet ? alphabet['default'] : alphabet;
var alphabet__default = _interopDefault(alphabet);

factory( null );
baz.foo( baz.bar, containers.port );
containers.forEach( console.log, console );
console.log( alphabet.a );
console.log( alphabet__default.length );
console.log( alphabet__default.length );
12 changes: 12 additions & 0 deletions test/function/cannot-call-external-namespace/_config.js
@@ -0,0 +1,12 @@
var path = require( 'path' );
var assert = require( 'assert' );

module.exports = {
description: 'errors if code calls an external namespace',
error: function ( err ) {
assert.equal( err.message, 'Cannot call a namespace (\'foo\')' );
assert.equal( err.file.replace( /\//g, path.sep ), path.resolve( __dirname, 'main.js' ) );
assert.equal( err.pos, 28 );
assert.deepEqual( err.loc, { line: 2, column: 0 });
}
};
2 changes: 2 additions & 0 deletions test/function/cannot-call-external-namespace/main.js
@@ -0,0 +1,2 @@
import * as foo from 'foo';
foo();
12 changes: 12 additions & 0 deletions test/function/cannot-call-internal-namespace/_config.js
@@ -0,0 +1,12 @@
var path = require( 'path' );
var assert = require( 'assert' );

module.exports = {
description: 'errors if code calls an internal namespace',
error: function ( err ) {
assert.equal( err.message, 'Cannot call a namespace (\'foo\')' );
assert.equal( err.file.replace( /\//g, path.sep ), path.resolve( __dirname, 'main.js' ) );
assert.equal( err.pos, 33 );
assert.deepEqual( err.loc, { line: 2, column: 0 });
}
};
1 change: 1 addition & 0 deletions test/function/cannot-call-internal-namespace/foo.js
@@ -0,0 +1 @@
export const a = 1;
2 changes: 2 additions & 0 deletions test/function/cannot-call-internal-namespace/main.js
@@ -0,0 +1,2 @@
import * as foo from './foo.js';
foo();
3 changes: 3 additions & 0 deletions test/function/cycles-stack-overflow/_config.js
@@ -0,0 +1,3 @@
module.exports = {
description: 'does not stack overflow on crazy cyclical dependencies'
};
11 changes: 11 additions & 0 deletions test/function/cycles-stack-overflow/b.js
@@ -0,0 +1,11 @@
import { C } from './c.js';

export function B () {};

B.prototype = {
c: function () {
return function () {
new C();
};
}()
};
13 changes: 13 additions & 0 deletions test/function/cycles-stack-overflow/c.js
@@ -0,0 +1,13 @@
import { D } from './d.js';

export function C () {
this.x = 'x';
}

C.prototype = {
d: function () {
return function () {
new D();
};
}()
};
12 changes: 12 additions & 0 deletions test/function/cycles-stack-overflow/d.js
@@ -0,0 +1,12 @@
import { B } from './b.js';
import { C } from './c.js';

export function D () {};

D.prototype = {
c: function () {
return function () {
new C();
};
}()
};
3 changes: 3 additions & 0 deletions test/function/cycles-stack-overflow/main.js
@@ -0,0 +1,3 @@
import { C } from './c.js';

assert.equal( new C().x, 'x' );

0 comments on commit f543f3e

Please sign in to comment.