@@ -17,6 +17,7 @@ namespace ts {
17
17
18
18
const names : string [ ] = [ ] ;
19
19
let nameToNameIndexMap : ESMap < string , number > | undefined ;
20
+ const mappingCharCodes : number [ ] = [ ] ;
20
21
let mappings = "" ;
21
22
22
23
// Last recorded and encoded mappings
@@ -210,6 +211,15 @@ namespace ts {
210
211
|| lastNameIndex !== pendingNameIndex ;
211
212
}
212
213
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
+
213
223
function commitPendingMapping ( ) {
214
224
if ( ! hasPending || ! shouldCommitMapping ( ) ) {
215
225
return ;
@@ -221,40 +231,41 @@ namespace ts {
221
231
if ( lastGeneratedLine < pendingGeneratedLine ) {
222
232
// Emit line delimiters
223
233
do {
224
- mappings += ";" ;
234
+ appendMappingCharCode ( CharacterCodes . semicolon ) ;
225
235
lastGeneratedLine ++ ;
226
- lastGeneratedCharacter = 0 ;
227
236
}
228
237
while ( lastGeneratedLine < pendingGeneratedLine ) ;
238
+ // Only need to set this once
239
+ lastGeneratedCharacter = 0 ;
229
240
}
230
241
else {
231
242
Debug . assertEqual ( lastGeneratedLine , pendingGeneratedLine , "generatedLine cannot backtrack" ) ;
232
243
// Emit comma to separate the entry
233
244
if ( hasLast ) {
234
- mappings += "," ;
245
+ appendMappingCharCode ( CharacterCodes . comma ) ;
235
246
}
236
247
}
237
248
238
249
// 1. Relative generated character
239
- mappings += base64VLQFormatEncode ( pendingGeneratedCharacter - lastGeneratedCharacter ) ;
250
+ appendBase64VLQ ( pendingGeneratedCharacter - lastGeneratedCharacter ) ;
240
251
lastGeneratedCharacter = pendingGeneratedCharacter ;
241
252
242
253
if ( hasPendingSource ) {
243
254
// 2. Relative sourceIndex
244
- mappings += base64VLQFormatEncode ( pendingSourceIndex - lastSourceIndex ) ;
255
+ appendBase64VLQ ( pendingSourceIndex - lastSourceIndex ) ;
245
256
lastSourceIndex = pendingSourceIndex ;
246
257
247
258
// 3. Relative source line
248
- mappings += base64VLQFormatEncode ( pendingSourceLine - lastSourceLine ) ;
259
+ appendBase64VLQ ( pendingSourceLine - lastSourceLine ) ;
249
260
lastSourceLine = pendingSourceLine ;
250
261
251
262
// 4. Relative source character
252
- mappings += base64VLQFormatEncode ( pendingSourceCharacter - lastSourceCharacter ) ;
263
+ appendBase64VLQ ( pendingSourceCharacter - lastSourceCharacter ) ;
253
264
lastSourceCharacter = pendingSourceCharacter ;
254
265
255
266
if ( hasPendingName ) {
256
267
// 5. Relative nameIndex
257
- mappings += base64VLQFormatEncode ( pendingNameIndex - lastNameIndex ) ;
268
+ appendBase64VLQ ( pendingNameIndex - lastNameIndex ) ;
258
269
lastNameIndex = pendingNameIndex ;
259
270
}
260
271
}
@@ -263,8 +274,16 @@ namespace ts {
263
274
exit ( ) ;
264
275
}
265
276
277
+ function flushMappingBuffer ( ) : void {
278
+ if ( mappingCharCodes . length > 0 ) {
279
+ mappings += String . fromCharCode . apply ( undefined , mappingCharCodes ) ;
280
+ mappingCharCodes . length = 0 ;
281
+ }
282
+ }
283
+
266
284
function toJSON ( ) : RawSourceMap {
267
285
commitPendingMapping ( ) ;
286
+ flushMappingBuffer ( ) ;
268
287
return {
269
288
version : 3 ,
270
289
file,
@@ -275,6 +294,31 @@ namespace ts {
275
294
sourcesContent,
276
295
} ;
277
296
}
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
+ }
278
322
}
279
323
280
324
// 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 {
544
588
- 1 ;
545
589
}
546
590
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
-
575
591
interface MappedPosition {
576
592
generatedPosition : number ;
577
593
source : string | undefined ;
0 commit comments