Skip to content
This repository has been archived by the owner on Aug 4, 2021. It is now read-only.

Make transform stateless #71

Merged
merged 6 commits into from
Jun 7, 2016
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
28 changes: 13 additions & 15 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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",
Expand Down
4 changes: 2 additions & 2 deletions rollup.config.js
Original file line number Diff line number Diff line change
@@ -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
};
61 changes: 34 additions & 27 deletions src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand All @@ -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 );
Expand All @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 )
Expand All @@ -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' );
}
};
}
3 changes: 0 additions & 3 deletions test/.babelrc

This file was deleted.

7 changes: 5 additions & 2 deletions test/samples/__esModule/main.js
Original file line number Diff line number Diff line change
@@ -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 ) );
2 changes: 2 additions & 0 deletions test/samples/deconflict-helpers/main.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
var commonjsHelpers = { commonjsGlobal: 'nope' };
module.exports = global;
61 changes: 41 additions & 20 deletions test/test.js
Original file line number Diff line number Diff line change
@@ -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 );

Expand All @@ -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({
Expand Down Expand Up @@ -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 );
Expand Down Expand Up @@ -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', () => {
Expand Down Expand Up @@ -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' );
});
})
});