Browse Source

sourcemaps

contingency-plan
Rich-Harris 10 years ago
parent
commit
04ab791dd6
  1. 20
      src/Bundle.js
  2. 8
      src/Module.js
  3. 7
      src/rollup.js
  4. 39
      test/sourcemaps/basic-support/_config.js
  5. 3
      test/sourcemaps/basic-support/bar.js
  6. 3
      test/sourcemaps/basic-support/foo.js
  7. 7
      test/sourcemaps/basic-support/main.js
  8. 44
      test/test.js
  9. 20
      test/utils/getLocation.js

20
src/Bundle.js

@ -1,4 +1,4 @@
import { basename, dirname, extname, resolve } from 'path'; import { basename, dirname, extname, relative, resolve } from 'path';
import { readFile, Promise } from 'sander'; import { readFile, Promise } from 'sander';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import { keys, has } from './utils/object'; import { keys, has } from './utils/object';
@ -273,14 +273,20 @@ export default class Bundle {
magicString = finalise( this, magicString.trim(), exportMode, options ); magicString = finalise( this, magicString.trim(), exportMode, options );
return { const code = magicString.toString();
code: magicString.toString(), let map = magicString.generateMap({
map: magicString.generateMap({
includeContent: true, includeContent: true,
file: options.dest file: options.sourceMapFile || options.dest
// TODO // TODO
}) });
};
// make sources relative. TODO fix this upstream?
const dir = dirname( map.file );
map.sources = map.sources.map( source => {
return source ? relative( dir, source ) : null
});
return { code, map };
} }
getExportMode ( exportMode ) { getExportMode ( exportMode ) {

8
src/Module.js

@ -3,6 +3,7 @@ import { Promise } from 'sander';
import { parse } from 'acorn'; import { parse } from 'acorn';
import MagicString from 'magic-string'; import MagicString from 'magic-string';
import Statement from './Statement'; import Statement from './Statement';
import walk from './ast/walk';
import analyse from './ast/analyse'; import analyse from './ast/analyse';
import { blank, has, keys } from './utils/object'; import { blank, has, keys } from './utils/object';
import { sequence } from './utils/promise'; import { sequence } from './utils/promise';
@ -36,11 +37,18 @@ export default class Module {
onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end }) onComment: ( block, text, start, end ) => this.comments.push({ block, text, start, end })
}); });
walk( ast, {
enter: node => {
this.magicString.addSourcemapLocation( node.start );
}
});
this.statements = ast.body.map( node => { this.statements = ast.body.map( node => {
const magicString = this.magicString.snip( node.start, node.end ); const magicString = this.magicString.snip( node.start, node.end );
return new Statement( node, magicString, this ); return new Statement( node, magicString, this );
}); });
} catch ( err ) { } catch ( err ) {
err.code = 'PARSE_ERROR';
err.file = path; err.file = path;
throw err; throw err;
} }

7
src/rollup.js

@ -18,7 +18,12 @@ export function rollup ( entry, options = {} ) {
let { code, map } = bundle.generate({ let { code, map } = bundle.generate({
dest, dest,
format: options.format, format: options.format,
globalName: options.globalName globalName: options.globalName,
// sourcemap options
sourceMap: options.sourceMap,
sourceMapFile: options.sourceMapFile,
sourceMapRoot: options.sourceMapRoot
}); });
code += `\n//# ${SOURCEMAPPING_URL}=${basename( dest )}.map`; code += `\n//# ${SOURCEMAPPING_URL}=${basename( dest )}.map`;

39
test/sourcemaps/basic-support/_config.js

@ -0,0 +1,39 @@
var path = require( 'path' );
var assert = require( 'assert' );
var getLocation = require( '../../utils/getLocation' );
var SourceMapConsumer = require( 'source-map' ).SourceMapConsumer;
module.exports = {
description: 'basic sourcemap support',
test: function ( code, map ) {
assert.equal( map.version, 3 );
assert.equal( map.file, 'bundle.js' );
var smc = new SourceMapConsumer( map );
var generatedLoc, originalLoc;
// main.js
generatedLoc = getLocation( code, code.indexOf( "console.log( 'hello from main.js' )" ) );
originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.line, 4 );
assert.equal( originalLoc.column, 0 );
assert.equal( path.resolve( originalLoc.source ), path.resolve( __dirname, 'main.js' ) );
// foo.js
generatedLoc = getLocation( code, code.indexOf( "console.log( 'hello from foo.js' )" ) );
originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.line, 2 );
assert.equal( originalLoc.column, 1 );
assert.equal( path.resolve( originalLoc.source ), path.resolve( __dirname, 'foo.js' ) );
// bar.js
generatedLoc = getLocation( code, code.indexOf( "console.log( 'hello from bar.js' )" ) );
originalLoc = smc.originalPositionFor( generatedLoc );
assert.equal( originalLoc.line, 2 );
assert.equal( originalLoc.column, 1 );
assert.equal( path.resolve( originalLoc.source ), path.resolve( __dirname, 'bar.js' ) );
}
};

3
test/sourcemaps/basic-support/bar.js

@ -0,0 +1,3 @@
export default function bar () {
console.log( 'hello from bar.js' );
}

3
test/sourcemaps/basic-support/foo.js

@ -0,0 +1,3 @@
export default function foo () {
console.log( 'hello from foo.js' );
}

7
test/sourcemaps/basic-support/main.js

@ -0,0 +1,7 @@
import foo from './foo';
import bar from './bar';
console.log( 'hello from main.js' );
foo();
bar();

44
test/test.js

@ -10,6 +10,15 @@ var rollup = require( '../dist/rollup' );
var FUNCTION = path.resolve( __dirname, 'function' ); var FUNCTION = path.resolve( __dirname, 'function' );
var FORM = path.resolve( __dirname, 'form' ); var FORM = path.resolve( __dirname, 'form' );
var SOURCEMAPS = path.resolve( __dirname, 'sourcemaps' );
var PROFILES = [
{ format: 'amd' },
{ format: 'cjs' },
{ format: 'es6' },
{ format: 'iife' },
{ format: 'umd' }
];
function extend ( target ) { function extend ( target ) {
[].slice.call( arguments, 1 ).forEach( function ( source ) { [].slice.call( arguments, 1 ).forEach( function ( source ) {
@ -121,14 +130,6 @@ describe( 'rollup', function () {
}); });
describe( 'form', function () { describe( 'form', function () {
var profiles = [
{ format: 'amd' },
{ format: 'cjs' },
{ format: 'es6' },
{ format: 'iife' },
{ format: 'umd' }
];
sander.readdirSync( FORM ).sort().forEach( function ( dir ) { sander.readdirSync( FORM ).sort().forEach( function ( dir ) {
if ( dir[0] === '.' ) return; // .DS_Store... if ( dir[0] === '.' ) return; // .DS_Store...
@ -143,7 +144,7 @@ describe( 'rollup', function () {
var bundlePromise = rollup.rollup( FORM + '/' + dir + '/main.js', extend( {}, config.options ) ); var bundlePromise = rollup.rollup( FORM + '/' + dir + '/main.js', extend( {}, config.options ) );
profiles.forEach( function ( profile ) { PROFILES.forEach( function ( profile ) {
( config.skip ? it.skip : config.solo ? it.only : it )( 'generates ' + profile.format, function () { ( config.skip ? it.skip : config.solo ? it.only : it )( 'generates ' + profile.format, function () {
return bundlePromise.then( function ( bundle ) { return bundlePromise.then( function ( bundle ) {
var actual = bundle.generate({ var actual = bundle.generate({
@ -163,4 +164,29 @@ describe( 'rollup', function () {
}); });
}); });
}); });
describe( 'sourcemaps', function () {
sander.readdirSync( SOURCEMAPS ).sort().forEach( function ( dir ) {
if ( dir[0] === '.' ) return; // .DS_Store...
describe( dir, function () {
var config = require( SOURCEMAPS + '/' + dir + '/_config' );
var bundlePromise = rollup.rollup( SOURCEMAPS + '/' + dir + '/main.js', extend( {}, config.options ) );
PROFILES.forEach( function ( profile ) {
( config.skip ? it.skip : config.solo ? it.only : it )( 'generates ' + profile.format, function () {
return bundlePromise.then( function ( bundle ) {
var result = bundle.generate({
format: profile.format,
sourceMapFile: 'bundle.js'
});
config.test( result.code, result.map );
});
});
});
});
});
});
}); });

20
test/utils/getLocation.js

@ -0,0 +1,20 @@
module.exports = 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' );
}
Loading…
Cancel
Save