Skip to content
Permalink
Browse files

Merge pull request #71 from rollup/stateless

Make transform stateless
  • Loading branch information...
Rich-Harris committed Jun 7, 2016
2 parents 60958c6 + a18bbc7 commit 6e8b598558058b8a1e25ddf8ccf1a16f61bd9a41
Showing with 97 additions and 69 deletions.
  1. +13 −15 package.json
  2. +2 −2 rollup.config.js
  3. +34 −27 src/index.js
  4. +0 −3 test/.babelrc
  5. +5 −2 test/samples/__esModule/main.js
  6. +2 −0 test/samples/deconflict-helpers/main.js
  7. +41 −20 test/test.js
@@ -3,20 +3,18 @@
"version": "2.2.1",
"description": "Convert CommonJS modules to ES2015",
"devDependencies": {
"babel-preset-es2015": "^6.3.13",
"babel-preset-es2015-rollup": "^1.0.0",
"babel-register": "^6.3.13",
"eslint": "^1.7.3",
"mocha": "^2.3.3",
"rollup": "^0.25.8",
"rollup-plugin-babel": "^2.2.0",
"rollup-plugin-node-resolve": "^1.1.0",
"source-map": "^0.5.3"
"buble": "^0.10.6",
"eslint": "^2.11.1",
"mocha": "^2.5.3",
"rollup": "^0.26.7",
"rollup-plugin-buble": "^0.10.0",
"rollup-plugin-node-resolve": "^1.6.0",
"source-map": "^0.5.6"
},
"main": "dist/rollup-plugin-commonjs.cjs.js",
"jsnext:main": "dist/rollup-plugin-commonjs.es6.js",
"scripts": {
"test": "mocha --compilers js:babel-register",
"test": "mocha --compilers js:buble/register",
"pretest": "npm run build",
"build": "rm -rf dist/* && rollup -c -f cjs -o dist/rollup-plugin-commonjs.cjs.js && rollup -c -f es6 -o dist/rollup-plugin-commonjs.es6.js",
"prepublish": "npm test"
@@ -27,11 +25,11 @@
"README.md"
],
"dependencies": {
"acorn": "^2.4.0",
"estree-walker": "^0.2.0",
"magic-string": "^0.10.0",
"resolve": "^1.1.6",
"rollup-pluginutils": "^1.2.0"
"acorn": "^3.1.0",
"estree-walker": "^0.2.1",
"magic-string": "^0.15.0",
"resolve": "^1.1.7",
"rollup-pluginutils": "^1.5.0"
},
"repository": {
"type": "git",
@@ -1,9 +1,9 @@
import babel from 'rollup-plugin-babel';
import buble from 'rollup-plugin-buble';

var external = Object.keys( require( './package.json' ).dependencies ).concat([ 'fs', 'path' ]);

export default {
entry: 'src/index.js',
plugins: [ babel() ],
plugins: [ buble() ],
external: external
};
@@ -37,13 +37,27 @@ function getCandidates ( resolved, extensions ) {
);
}

function deconflict ( identifier, code ) {
let i = 1;
let deconflicted = identifier;

while ( ~code.indexOf( deconflicted ) ) deconflicted = `${identifier}_${i++}`;
return deconflicted;
}

const HELPERS_ID = '\0commonjsHelpers';
const HELPERS = `
export var commonjsGlobal = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}
export function createCommonjsModule(fn, module) {
return module = { exports: {} }, fn(module, module.exports), module.exports;
}`;

export default function commonjs ( options = {} ) {
const extensions = options.extensions || ['.js'];
const filter = createFilter( options.include, options.exclude );
const ignoreGlobal = options.ignoreGlobal;
const firstpass = ignoreGlobal ? firstpassNoGlobal : firstpassGlobal;
let bundleUsesGlobal = false;
let bundleRequiresWrappers = false;

const sourceMap = options.sourceMap !== false;

@@ -64,6 +78,8 @@ export default function commonjs ( options = {} ) {

return {
resolveId ( importee, importer ) {
if ( importee === HELPERS_ID ) return importee;

if ( importee[0] !== '.' ) return; // not our problem

const resolved = resolve( dirname( importer ), importee );
@@ -77,6 +93,10 @@ export default function commonjs ( options = {} ) {
}
},

load ( id ) {
if ( id === HELPERS_ID ) return HELPERS;
},

transform ( code, id ) {
if ( !filter( id ) ) return null;
if ( extensions.indexOf( extname( id ) ) === -1 ) return null;
@@ -109,6 +129,8 @@ export default function commonjs ( options = {} ) {

let scopeDepth = 0;

const HELPERS_NAME = deconflict( 'commonjsHelpers', code );

walk( ast, {
enter ( node, parent ) {
if ( node.scope ) scope = node.scope;
@@ -145,13 +167,16 @@ export default function commonjs ( options = {} ) {
}

if ( node.type === 'Identifier' ) {
if ( ( node.name in uses && !uses[ node.name ] ) && isReference( node, parent ) && !scope.contains( node.name ) ) uses[ node.name ] = true;
if ( ( node.name in uses && !uses[ node.name ] ) && isReference( node, parent ) && !scope.contains( node.name ) ) {
uses[ node.name ] = true;
if ( node.name === 'global' ) magicString.overwrite( node.start, node.end, `${HELPERS_NAME}.commonjsGlobal` );
}
return;
}

if ( node.type === 'ThisExpression' && scopeDepth === 0 && !ignoreGlobal ) {
uses.global = true;
magicString.overwrite( node.start, node.end, `__commonjs_global`, true );
magicString.overwrite( node.start, node.end, `${HELPERS_NAME}.commonjsGlobal`, true );
return;
}

@@ -195,20 +220,18 @@ export default function commonjs ( options = {} ) {
return null; // not a CommonJS module
}

bundleRequiresWrappers = true;

const name = getName( id );

const importBlock = sources.length ?
const importBlock = [ `import * as ${HELPERS_NAME} from '${HELPERS_ID}';` ].concat(
sources.map( source => {
const { name, importsDefault } = required[ source ];
return `import ${importsDefault ? `${name} from ` : ``}'${source}';`;
}).join( '\n' ) :
'';
})
).join( '\n' );

const args = `module${uses.exports || uses.global ? ', exports' : ''}${uses.global ? ', global' : ''}`;
const args = `module${uses.exports ? ', exports' : ''}`;

const intro = `\n\nvar ${name} = __commonjs(function (${args}) {\n`;
const intro = `\n\nvar ${name} = ${HELPERS_NAME}.createCommonjsModule(function (${args}) {\n`;
let outro = `\n});\n\nexport default (${name} && typeof ${name} === 'object' && 'default' in ${name} ? ${name}['default'] : ${name});\n`;

outro += Object.keys( namedExports )
@@ -224,23 +247,7 @@ export default function commonjs ( options = {} ) {
code = magicString.toString();
const map = sourceMap ? magicString.generateMap() : null;

if ( uses.global ) bundleUsesGlobal = true;

return { code, map };
},

intro () {
var intros = [];

if ( bundleUsesGlobal ) {
intros.push( `var __commonjs_global = typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : typeof self !== 'undefined' ? self : {}` );
}

if ( bundleRequiresWrappers ) {
intros.push( `function __commonjs(fn, module) { return module = { exports: {} }, fn(module, module.exports${bundleUsesGlobal ? ', __commonjs_global' : ''}), module.exports; }\n` );
}

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

This file was deleted.

@@ -1,2 +1,5 @@
exports.__esModule = true;
exports.answer = 42;
import * as x from './answer';

assert.ok( 'answer' in x );
assert.ok( 'default' in x ); // TODO is this right?
assert.ok( !( '__esModule' in x ) );
@@ -0,0 +1,2 @@
var commonjsHelpers = { commonjsGlobal: 'nope' };
module.exports = global;
@@ -1,9 +1,9 @@
import * as path from 'path';
import * as assert from 'assert';
import { SourceMapConsumer } from 'source-map';
import { rollup } from 'rollup';
import nodeResolve from 'rollup-plugin-node-resolve';
import commonjs from '..';
const path = require( 'path' );
const assert = require( 'assert' );
const { SourceMapConsumer } = require( 'source-map' );
const { rollup } = require( 'rollup' );
const nodeResolve = require( 'rollup-plugin-node-resolve' );
const commonjs = require( '..' );

process.chdir( __dirname );

@@ -20,6 +20,27 @@ function executeBundle ( bundle ) {
return module;
}

function getLocation ( source, charIndex ) {
var lines = source.split( '\n' );
var len = lines.length;

var lineStart = 0;
var i;

for ( i = 0; i < len; i += 1 ) {
var line = lines[i];
var lineEnd = lineStart + line.length + 1; // +1 for newline

if ( lineEnd > charIndex ) {
return { line: i + 1, column: charIndex - lineStart };
}

lineStart = lineEnd;
}

throw new Error( 'Could not determine location of character' );
}

describe( 'rollup-plugin-commonjs', () => {
it( 'converts a basic CommonJS module', () => {
return rollup({
@@ -61,12 +82,14 @@ describe( 'rollup-plugin-commonjs', () => {

const smc = new SourceMapConsumer( generated.map );

let loc = smc.originalPositionFor({ line: 5, column: 17 }); // 42
let generatedLoc = getLocation( generated.code, generated.code.indexOf( '42' ) );
let loc = smc.originalPositionFor( generatedLoc ); // 42
assert.equal( loc.source, 'samples/sourcemap/foo.js' );
assert.equal( loc.line, 1 );
assert.equal( loc.column, 15 );

loc = smc.originalPositionFor({ line: 9, column: 8 }); // log
generatedLoc = getLocation( generated.code, generated.code.indexOf( 'log' ) );
loc = smc.originalPositionFor( generatedLoc ); // log
assert.equal( loc.source, 'samples/sourcemap/main.js' );
assert.equal( loc.line, 2 );
assert.equal( loc.column, 8 );
@@ -176,18 +199,7 @@ describe( 'rollup-plugin-commonjs', () => {
return rollup({
entry: 'samples/__esModule/main.js',
plugins: [ commonjs() ]
}).then( bundle => {
const generated = bundle.generate({
format: 'cjs'
});

const fn = new Function ( 'module', 'exports', generated.code );
let module = { exports: {} };

fn( module, module.exports );

assert.ok( !module.exports.__esModule );
});
}).then( executeBundle );
});

it( 'allows named exports to be added explicitly via config', () => {
@@ -254,4 +266,13 @@ describe( 'rollup-plugin-commonjs', () => {
assert.equal( global.setImmediate, mod.immediate, generated.code );
});
});

it( 'deconflicts helper name', () => {
return rollup({
entry: 'samples/deconflict-helpers/main.js',
plugins: [ commonjs() ]
}).then( executeBundle ).then( module => {
assert.notEqual( module.exports, 'nope' );
});
})
});

0 comments on commit 6e8b598

Please sign in to comment.
You can’t perform that action at this time.