mirror of https://github.com/lukechilds/rollup.git
Rich Harris
9 years ago
17 changed files with 260 additions and 57 deletions
@ -1,72 +1,108 @@ |
|||
import { encode, decode } from 'sourcemap-codec'; |
|||
|
|||
function traceSegment ( loc, mappings ) { |
|||
const line = loc[0]; |
|||
const column = loc[1]; |
|||
function Source ( map, sources ) { |
|||
if ( !map ) throw new Error( 'Cannot generate a sourcemap if non-sourcemap-generating transformers are used' ); |
|||
|
|||
const segments = mappings[ line ]; |
|||
this.sources = sources; |
|||
this.names = map.names; |
|||
this.mappings = decode( map.mappings ); |
|||
} |
|||
|
|||
if ( !segments ) return null; |
|||
Source.prototype = { // TODO bring into line with others post-https://github.com/rollup/rollup/pull/386
|
|||
traceMappings () { |
|||
let names = []; |
|||
|
|||
const mappings = this.mappings.map( line => { |
|||
let tracedLine = []; |
|||
|
|||
line.forEach( segment => { |
|||
const source = this.sources[ segment[1] ]; |
|||
const traced = source.traceSegment( segment[2], segment[3], this.names[ segment[4] ] ); |
|||
|
|||
if ( traced ) { |
|||
let nameIndex = null; |
|||
segment = [ |
|||
segment[0], |
|||
traced.index, |
|||
traced.line, |
|||
traced.column |
|||
]; |
|||
|
|||
if ( traced.name ) { |
|||
nameIndex = names.indexOf( traced.name ); |
|||
if ( nameIndex === -1 ) { |
|||
nameIndex = names.length; |
|||
names.push( traced.name ); |
|||
} |
|||
|
|||
segment[4] = nameIndex; |
|||
} |
|||
|
|||
tracedLine.push( segment ); |
|||
} |
|||
}); |
|||
|
|||
return tracedLine; |
|||
}); |
|||
|
|||
for ( let i = 0; i < segments.length; i += 1 ) { |
|||
const segment = segments[i]; |
|||
return { names, mappings }; |
|||
}, |
|||
|
|||
if ( segment[0] > column ) return null; |
|||
traceSegment ( line, column, name ) { |
|||
const segments = this.mappings[ line ]; |
|||
|
|||
if ( segment[0] === column ) { |
|||
if ( segment[1] !== 0 ) { |
|||
throw new Error( 'Bad sourcemap' ); |
|||
} |
|||
|
|||
return [ segment[2], segment[3] ]; |
|||
} |
|||
} |
|||
if ( !segments ) return null; |
|||
|
|||
return null; |
|||
} |
|||
for ( let i = 0; i < segments.length; i += 1 ) { |
|||
const segment = segments[i]; |
|||
|
|||
export default function collapseSourcemaps ( map, modules ) { |
|||
const chains = modules.map( module => { |
|||
return module.sourceMapChain.map( map => { |
|||
if ( !map ) throw new Error( 'Cannot generate a sourcemap if non-sourcemap-generating transformers are used' ); |
|||
return decode( map.mappings ); |
|||
}); |
|||
}); |
|||
if ( segment[0] > column ) return null; |
|||
|
|||
const decodedMappings = decode( map.mappings ); |
|||
if ( segment[0] === column ) { |
|||
const source = this.sources[ segment[1] ]; |
|||
|
|||
const tracedMappings = decodedMappings.map( line => { |
|||
let tracedLine = []; |
|||
if ( !source ) throw new Error( 'Bad sourcemap' ); |
|||
|
|||
line.forEach( segment => { |
|||
const sourceIndex = segment[1]; |
|||
const sourceCodeLine = segment[2]; |
|||
const sourceCodeColumn = segment[3]; |
|||
if ( source.isOriginal ) { |
|||
return { |
|||
index: source.index, |
|||
line: segment[2], |
|||
column: segment[3], |
|||
name: this.names[ segment[4] ] || name |
|||
}; |
|||
} |
|||
|
|||
const chain = chains[ sourceIndex ]; |
|||
return source.traceSegment( segment[2], segment[3], name ); |
|||
} |
|||
} |
|||
|
|||
let i = chain.length; |
|||
let traced = [ sourceCodeLine, sourceCodeColumn ]; |
|||
return null; |
|||
} |
|||
}; |
|||
|
|||
while ( i-- && traced ) { |
|||
traced = traceSegment( traced, chain[i] ); |
|||
} |
|||
export default function collapseSourcemaps ( map, modules, bundleSourcemapChain ) { |
|||
const sources = modules.map( ( module, i ) => { |
|||
let source = { isOriginal: true, index: i }; |
|||
|
|||
if ( traced ) { |
|||
tracedLine.push([ |
|||
segment[0], |
|||
segment[1], |
|||
traced[0], |
|||
traced[1] |
|||
// TODO name?
|
|||
]); |
|||
} |
|||
module.sourceMapChain.forEach( map => { |
|||
source = new Source( map, [ source ]); |
|||
}); |
|||
|
|||
return tracedLine; |
|||
return source; |
|||
}); |
|||
|
|||
let source = new Source( map, sources ); |
|||
|
|||
bundleSourcemapChain.forEach( map => { |
|||
source = new Source( map, [ source ] ); |
|||
}); |
|||
|
|||
const { names, mappings } = source.traceMappings(); |
|||
|
|||
// we re-use the `map` object because it has convenient toString/toURL methods
|
|||
map.sourcesContent = modules.map( module => module.originalCode ); |
|||
map.mappings = encode( tracedMappings ); |
|||
map.mappings = encode( mappings ); |
|||
map.names = names; |
|||
|
|||
return map; |
|||
} |
|||
|
@ -0,0 +1,19 @@ |
|||
export default function transformBundle ( code, transformers, sourceMapChain ) { |
|||
return transformers.reduce( ( code, transformer ) => { |
|||
let result = transformer( code ); |
|||
|
|||
if ( result == null ) return code; |
|||
|
|||
if ( typeof result === 'string' ) { |
|||
result = { |
|||
code: result, |
|||
map: null |
|||
}; |
|||
} |
|||
|
|||
const map = typeof result.map === 'string' ? JSON.parse( result.map ) : map; |
|||
sourceMapChain.push( map ); |
|||
|
|||
return result.code; |
|||
}, code ); |
|||
} |
@ -0,0 +1,17 @@ |
|||
module.exports = { |
|||
description: 'allows plugins to transform bundle', |
|||
options: { |
|||
plugins: [ |
|||
{ |
|||
transformBundle: function (code) { |
|||
return '/* first plugin */'; |
|||
} |
|||
}, |
|||
{ |
|||
transformBundle: function (code) { |
|||
return code + '\n/* second plugin */'; |
|||
} |
|||
} |
|||
] |
|||
} |
|||
} |
@ -0,0 +1,2 @@ |
|||
/* first plugin */ |
|||
/* second plugin */ |
@ -0,0 +1,2 @@ |
|||
/* first plugin */ |
|||
/* second plugin */ |
@ -0,0 +1,2 @@ |
|||
/* first plugin */ |
|||
/* second plugin */ |
@ -0,0 +1,2 @@ |
|||
/* first plugin */ |
|||
/* second plugin */ |
@ -0,0 +1,2 @@ |
|||
/* first plugin */ |
|||
/* second plugin */ |
@ -0,0 +1 @@ |
|||
console.log( 1 + 1 ); |
@ -0,0 +1,58 @@ |
|||
var assert = require( 'assert' ); |
|||
var uglify = require( 'uglify-js' ); |
|||
var MagicString = require( 'magic-string' ); |
|||
var getLocation = require( '../../utils/getLocation' ); |
|||
var SourceMapConsumer = require( 'source-map' ).SourceMapConsumer; |
|||
|
|||
module.exports = { |
|||
description: 'names are recovered if transforms are used', |
|||
options: { |
|||
plugins: [ |
|||
{ |
|||
transform: function ( code ) { |
|||
var s = new MagicString( code ); |
|||
var pattern = /mangleMe/g; |
|||
var match; |
|||
|
|||
while ( match = pattern.exec( code ) ) { |
|||
s.overwrite( match.index, match.index + match[0].length, 'mangleMePlease', true ); |
|||
} |
|||
|
|||
return { |
|||
code: s.toString(), |
|||
map: s.generateMap({ hires: true }) |
|||
}; |
|||
}, |
|||
transformBundle: function ( code ) { |
|||
return uglify.minify( code, { |
|||
fromString: true, |
|||
outSourceMap: 'x' |
|||
}); |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
test: function ( code, map ) { |
|||
var smc = new SourceMapConsumer( map ); |
|||
|
|||
var generatedLoc = getLocation( code, /\w+=1/.exec( code ).index ); |
|||
var originalLoc = smc.originalPositionFor( generatedLoc ); |
|||
|
|||
assert.deepEqual( originalLoc, { |
|||
source: '../a.js', |
|||
line: 1, |
|||
column: 4, |
|||
name: 'mangleMe' |
|||
}); |
|||
|
|||
generatedLoc = getLocation( code, /\w+=2/.exec( code ).index ); |
|||
originalLoc = smc.originalPositionFor( generatedLoc ); |
|||
|
|||
assert.deepEqual( originalLoc, { |
|||
source: '../b.js', |
|||
line: 1, |
|||
column: 4, |
|||
name: 'mangleMe' |
|||
}); |
|||
} |
|||
}; |
@ -0,0 +1,4 @@ |
|||
var mangleMe = 1; |
|||
export default function () { |
|||
assert.equal( mangleMe, 1 ); |
|||
} |
@ -0,0 +1,4 @@ |
|||
var mangleMe = 2; |
|||
export default function () { |
|||
assert.equal( mangleMe, 2 ); |
|||
} |
@ -0,0 +1,5 @@ |
|||
import a from './a.js'; |
|||
import b from './b.js'; |
|||
|
|||
a(); |
|||
b(); |
@ -0,0 +1,38 @@ |
|||
var uglify = require( 'uglify-js' ); |
|||
var assert = require( 'assert' ); |
|||
var getLocation = require( '../../utils/getLocation' ); |
|||
var SourceMapConsumer = require( 'source-map' ).SourceMapConsumer; |
|||
|
|||
module.exports = { |
|||
description: 'preserves sourcemap chains when transforming', |
|||
options: { |
|||
plugins: [ |
|||
{ |
|||
transformBundle: function ( code ) { |
|||
var options = { |
|||
fromString: true, |
|||
outSourceMap: 'x' // trigger sourcemap generation
|
|||
}; |
|||
|
|||
return uglify.minify( code, options ); |
|||
} |
|||
} |
|||
] |
|||
}, |
|||
test: function ( code, map ) { |
|||
var smc = new SourceMapConsumer( map ); |
|||
|
|||
var generatedLoc = getLocation( code, code.indexOf( '42' ) ); |
|||
var originalLoc = smc.originalPositionFor( generatedLoc ); |
|||
|
|||
assert.ok( /main/.test( originalLoc.source ) ); |
|||
assert.equal( originalLoc.line, 1 ); |
|||
assert.equal( originalLoc.column, 13 ); |
|||
|
|||
generatedLoc = getLocation( code, code.indexOf( 'log' ) ); |
|||
originalLoc = smc.originalPositionFor( generatedLoc ); |
|||
|
|||
assert.equal( originalLoc.line, 1 ); |
|||
assert.equal( originalLoc.column, 8 ); |
|||
} |
|||
}; |
@ -0,0 +1 @@ |
|||
console.log( 42 ); |
Loading…
Reference in new issue