11import fs = require( 'fs' ) ;
22import path = require( 'path' ) ;
33import SourceMapModule = require( "source-map" ) ;
4- import Merger = require( './merge_utils' ) ;
54const mappingUrlPrefix = "# sourceMappingURL=" ;
65const dataURLPrefix = "data:application/json;base64," ;
76
@@ -52,7 +51,7 @@ export class SourceFile {
5251 mapPath = path . resolve ( path . dirname ( this . _path ) , url ) ;
5352 mapContents = fs . readFileSync ( mapPath ) . toString ( ) ;
5453 }
55- return new SourceMap ( this , mapContents , mapPath ) ;
54+ return new SourceMap ( this , JSON . parse ( mapContents ) , mapPath ) ;
5655 }
5756
5857 public getPath ( ) : string { return this . _path ; }
@@ -68,6 +67,18 @@ export class SourceFile {
6867 return path . relative ( path . dirname ( this . _path ) , aPath ) ;
6968 }
7069
70+ public findOriginal ( line : number , col : number , shouldIgnoreMissingRanges : boolean ) : SourceMapModule . MappedPosition {
71+ if ( this . _map ) {
72+ return this . _map . findOriginal ( line , col , shouldIgnoreMissingRanges ) ;
73+ } else {
74+ return {
75+ line : line ,
76+ column : col ,
77+ source : this . _path
78+ } ;
79+ }
80+ }
81+
7182 /**
7283 * Flush changes to disk.
7384 */
@@ -83,7 +94,6 @@ export class SourceFile {
8394
8495/**
8596 * Represents a SourceMap.
86- * @param generatedFilePath The path to a generated JavaScript file that contains a sourceMappingURL.
8797 */
8898export class SourceMap {
8999 // The source map's corresponding file.
@@ -92,15 +102,26 @@ export class SourceMap {
92102 private _map : SourceMapModule . RawSourceMap ;
93103 // The path to the SourceMap.
94104 private _path : string ;
95- // The next file in the compilation chain.
96105 private _sourceFiles : SourceFile [ ] ;
106+ private _sourceFileMap : { [ p : string ] : SourceFile } ;
107+ private _consumer : SourceMapModule . SourceMapConsumer ;
97108
98- constructor ( file : SourceFile , rawContents : string , mapPath : string ) {
109+ constructor ( file : SourceFile , map : SourceMapModule . RawSourceMap , mapPath : string ) {
99110 this . _file = file ;
100- this . _map = JSON . parse ( rawContents ) ;
101111 this . _path = mapPath ;
102- // Get the source files
103- this . _sourceFiles = this . getAbsoluteSourcePaths ( ) . map ( ( sourcePath ) => new SourceFile ( sourcePath ) ) ;
112+ this . _updateMap ( map ) ;
113+ }
114+
115+ private _updateMap ( map : SourceMapModule . RawSourceMap ) : void {
116+ this . _map = map ;
117+ this . _consumer = new SourceMapModule . SourceMapConsumer ( map ) ;
118+ this . _sourceFileMap = { } ;
119+ this . _sourceFiles = this . getAbsoluteSourcePaths ( ) . map ( ( sourcePath ) => {
120+ const m = new SourceFile ( sourcePath ) ;
121+ // Map relative path to sourcefile.
122+ this . _sourceFileMap [ sourcePath ] = m ;
123+ return m ;
124+ } ) ;
104125 }
105126
106127 public getFile ( ) : SourceFile {
@@ -127,6 +148,10 @@ export class SourceMap {
127148 return path . resolve ( path . dirname ( this . _path ) , aPath ) ;
128149 }
129150
151+ public getRelativePath ( p : string ) : string {
152+ return path . relative ( path . dirname ( this . _path ) , p ) ;
153+ }
154+
130155 /**
131156 * Retrieve an absolute path to the SourceMap's sourceRoot.
132157 */
@@ -147,28 +172,72 @@ export class SourceMap {
147172 return this . _map ;
148173 }
149174
150- protected getParentMap ( ) : SourceMap {
151- if ( this . _sourceFiles . length > 1 ) {
152- throw new Error ( `Error: Source map for ${ this . _file . getPath ( ) } has multiple source files.` ) ;
153- } else if ( this . _sourceFiles . length === 0 ) {
175+ protected getParentMaps ( ) : SourceMap [ ] {
176+ if ( this . _sourceFiles . length === 0 ) {
154177 return null ;
155178 }
156- return this . _sourceFiles [ 0 ] . getMap ( ) ;
179+ return this . _sourceFiles . map ( ( f ) => f . getMap ( ) ) ;
180+ }
181+
182+ public findOriginal ( line : number , col : number , shouldIgnoreMissingRanges : boolean ) : SourceMapModule . MappedPosition {
183+ const pos = this . _consumer . originalPositionFor ( { line : line , column : col } ) ;
184+ if ( ! pos || pos . line === null || pos . line === undefined ) {
185+ if ( shouldIgnoreMissingRanges ) {
186+ return pos ;
187+ } else {
188+ throw new Error ( `Could not find original location of ${ this . _file . getPath ( ) } :${ line } :${ col } ` ) ;
189+ }
190+ }
191+ // Normalize source file.
192+ pos . source = this . resolveRelativePath ( pos . source ) ;
193+ if ( this . _sourceFiles . length > 0 ) {
194+ const sf = this . _sourceFileMap [ pos . source ] ;
195+ if ( ! sf ) {
196+ if ( shouldIgnoreMissingRanges ) {
197+ return pos ;
198+ } else {
199+ throw new Error ( `Could not find original location of ${ this . _file . getPath ( ) } :${ line } :${ col } ` ) ;
200+ }
201+ } else {
202+ return sf . findOriginal ( pos . line , pos . column , shouldIgnoreMissingRanges ) ;
203+ }
204+ } else {
205+ return pos ;
206+ }
157207 }
158208
159209 /**
160- * Merges all parents into this source map.
210+ * Merges all parents into a new source map.
161211 */
162- public merge ( ) : void {
163- let nextMap : SourceMap = this ,
164- maps : SourceMapModule . RawSourceMap [ ] = [ ] ;
165- while ( nextMap !== null ) {
166- maps . push ( nextMap . getMap ( ) )
167- nextMap = nextMap . getParentMap ( ) ;
168- }
169- this . _map = JSON . parse ( Merger . createMergedSourceMap ( maps . reverse ( ) , true ) ) ;
170- // Update SourceFiles.
171- this . _sourceFiles = this . getAbsoluteSourcePaths ( ) . map ( ( sourcePath ) => new SourceFile ( sourcePath ) ) ;
212+ public merge ( shouldIgnoreMissingRanges : boolean = true ) : void {
213+ let generator = new SourceMapModule . SourceMapGenerator ( {
214+ file : this . _path
215+ } ) ;
216+
217+ this . _consumer . eachMapping ( ( mapping ) => {
218+ const original = this . findOriginal ( mapping . generatedLine , mapping . generatedColumn , shouldIgnoreMissingRanges ) ;
219+ // source-map uses nulled fields to indicate that it did not find a match.
220+ if ( original . line === null && shouldIgnoreMissingRanges ) {
221+ return ;
222+ }
223+
224+ generator . addMapping ( {
225+ generated : {
226+ line : mapping . generatedLine ,
227+ column : mapping . generatedColumn
228+ } ,
229+ original : {
230+ line : original . line ,
231+ column : original . column
232+ } ,
233+ source : original . source ,
234+ name : original . name
235+ } ) ;
236+ } ) ;
237+
238+ const newMap = generator . toJSON ( ) ;
239+ newMap . sources = newMap . sources . map ( ( s ) => this . getRelativePath ( s ) ) ;
240+ this . _updateMap ( newMap ) ;
172241 }
173242
174243 public inlineSources ( ) : void {
0 commit comments