@@ -17,6 +17,7 @@ namespace ts {
1717
1818 const names : string [ ] = [ ] ;
1919 let nameToNameIndexMap : ESMap < string , number > | undefined ;
20+ const mappingCharCodes : number [ ] = [ ] ;
2021 let mappings = "" ;
2122
2223 // Last recorded and encoded mappings
@@ -210,6 +211,15 @@ namespace ts {
210211 || lastNameIndex !== pendingNameIndex ;
211212 }
212213
214+ function appendMappingCharCode ( charCode : number ) {
215+ mappingCharCodes . push ( charCode ) ;
216+ // String.fromCharCode accepts its arguments on the stack, so we have to chunk the input,
217+ // otherwise we can get stack overflows for large source maps
218+ if ( mappingCharCodes . length >= 1024 ) {
219+ flushMappingBuffer ( ) ;
220+ }
221+ }
222+
213223 function commitPendingMapping ( ) {
214224 if ( ! hasPending || ! shouldCommitMapping ( ) ) {
215225 return ;
@@ -221,40 +231,41 @@ namespace ts {
221231 if ( lastGeneratedLine < pendingGeneratedLine ) {
222232 // Emit line delimiters
223233 do {
224- mappings += ";" ;
234+ appendMappingCharCode ( CharacterCodes . semicolon ) ;
225235 lastGeneratedLine ++ ;
226- lastGeneratedCharacter = 0 ;
227236 }
228237 while ( lastGeneratedLine < pendingGeneratedLine ) ;
238+ // Only need to set this once
239+ lastGeneratedCharacter = 0 ;
229240 }
230241 else {
231242 Debug . assertEqual ( lastGeneratedLine , pendingGeneratedLine , "generatedLine cannot backtrack" ) ;
232243 // Emit comma to separate the entry
233244 if ( hasLast ) {
234- mappings += "," ;
245+ appendMappingCharCode ( CharacterCodes . comma ) ;
235246 }
236247 }
237248
238249 // 1. Relative generated character
239- mappings += base64VLQFormatEncode ( pendingGeneratedCharacter - lastGeneratedCharacter ) ;
250+ appendBase64VLQ ( pendingGeneratedCharacter - lastGeneratedCharacter ) ;
240251 lastGeneratedCharacter = pendingGeneratedCharacter ;
241252
242253 if ( hasPendingSource ) {
243254 // 2. Relative sourceIndex
244- mappings += base64VLQFormatEncode ( pendingSourceIndex - lastSourceIndex ) ;
255+ appendBase64VLQ ( pendingSourceIndex - lastSourceIndex ) ;
245256 lastSourceIndex = pendingSourceIndex ;
246257
247258 // 3. Relative source line
248- mappings += base64VLQFormatEncode ( pendingSourceLine - lastSourceLine ) ;
259+ appendBase64VLQ ( pendingSourceLine - lastSourceLine ) ;
249260 lastSourceLine = pendingSourceLine ;
250261
251262 // 4. Relative source character
252- mappings += base64VLQFormatEncode ( pendingSourceCharacter - lastSourceCharacter ) ;
263+ appendBase64VLQ ( pendingSourceCharacter - lastSourceCharacter ) ;
253264 lastSourceCharacter = pendingSourceCharacter ;
254265
255266 if ( hasPendingName ) {
256267 // 5. Relative nameIndex
257- mappings += base64VLQFormatEncode ( pendingNameIndex - lastNameIndex ) ;
268+ appendBase64VLQ ( pendingNameIndex - lastNameIndex ) ;
258269 lastNameIndex = pendingNameIndex ;
259270 }
260271 }
@@ -263,8 +274,16 @@ namespace ts {
263274 exit ( ) ;
264275 }
265276
277+ function flushMappingBuffer ( ) : void {
278+ if ( mappingCharCodes . length > 0 ) {
279+ mappings += String . fromCharCode . apply ( undefined , mappingCharCodes ) ;
280+ mappingCharCodes . length = 0 ;
281+ }
282+ }
283+
266284 function toJSON ( ) : RawSourceMap {
267285 commitPendingMapping ( ) ;
286+ flushMappingBuffer ( ) ;
268287 return {
269288 version : 3 ,
270289 file,
@@ -275,6 +294,31 @@ namespace ts {
275294 sourcesContent,
276295 } ;
277296 }
297+
298+ function appendBase64VLQ ( inValue : number ) : void {
299+ // Add a new least significant bit that has the sign of the value.
300+ // if negative number the least significant bit that gets added to the number has value 1
301+ // else least significant bit value that gets added is 0
302+ // eg. -1 changes to binary : 01 [1] => 3
303+ // +1 changes to binary : 01 [0] => 2
304+ if ( inValue < 0 ) {
305+ inValue = ( ( - inValue ) << 1 ) + 1 ;
306+ }
307+ else {
308+ inValue = inValue << 1 ;
309+ }
310+
311+ // Encode 5 bits at a time starting from least significant bits
312+ do {
313+ let currentDigit = inValue & 31 ; // 11111
314+ inValue = inValue >> 5 ;
315+ if ( inValue > 0 ) {
316+ // There are still more digits to decode, set the msb (6th bit)
317+ currentDigit = currentDigit | 32 ;
318+ }
319+ appendMappingCharCode ( base64FormatEncode ( currentDigit ) ) ;
320+ } while ( inValue > 0 ) ;
321+ }
278322 }
279323
280324 // Sometimes tools can see the following line as a source mapping url comment, so we mangle it a bit (the [M])
@@ -544,34 +588,6 @@ namespace ts {
544588 - 1 ;
545589 }
546590
547- function base64VLQFormatEncode ( inValue : number ) {
548- // Add a new least significant bit that has the sign of the value.
549- // if negative number the least significant bit that gets added to the number has value 1
550- // else least significant bit value that gets added is 0
551- // eg. -1 changes to binary : 01 [1] => 3
552- // +1 changes to binary : 01 [0] => 2
553- if ( inValue < 0 ) {
554- inValue = ( ( - inValue ) << 1 ) + 1 ;
555- }
556- else {
557- inValue = inValue << 1 ;
558- }
559-
560- // Encode 5 bits at a time starting from least significant bits
561- let encodedStr = "" ;
562- do {
563- let currentDigit = inValue & 31 ; // 11111
564- inValue = inValue >> 5 ;
565- if ( inValue > 0 ) {
566- // There are still more digits to decode, set the msb (6th bit)
567- currentDigit = currentDigit | 32 ;
568- }
569- encodedStr = encodedStr + String . fromCharCode ( base64FormatEncode ( currentDigit ) ) ;
570- } while ( inValue > 0 ) ;
571-
572- return encodedStr ;
573- }
574-
575591 interface MappedPosition {
576592 generatedPosition : number ;
577593 source : string | undefined ;
0 commit comments