UNPKG

33.8 kBJavaScriptView Raw
1'use strict';
2
3function Chunk ( start, end, content ) {
4 this.start = start;
5 this.end = end;
6 this.original = content;
7
8 this.intro = '';
9 this.outro = '';
10
11 this.content = content;
12 this.storeName = false;
13 this.edited = false;
14
15 // we make these non-enumerable, for sanity while debugging
16 Object.defineProperties( this, {
17 previous: { writable: true, value: null },
18 next: { writable: true, value: null }
19 });
20}
21
22Chunk.prototype = {
23 appendLeft: function appendLeft ( content ) {
24 this.outro += content;
25 },
26
27 appendRight: function appendRight ( content ) {
28 this.intro = this.intro + content;
29 },
30
31 clone: function clone () {
32 var chunk = new Chunk( this.start, this.end, this.original );
33
34 chunk.intro = this.intro;
35 chunk.outro = this.outro;
36 chunk.content = this.content;
37 chunk.storeName = this.storeName;
38 chunk.edited = this.edited;
39
40 return chunk;
41 },
42
43 contains: function contains ( index ) {
44 return this.start < index && index < this.end;
45 },
46
47 eachNext: function eachNext ( fn ) {
48 var chunk = this;
49 while ( chunk ) {
50 fn( chunk );
51 chunk = chunk.next;
52 }
53 },
54
55 eachPrevious: function eachPrevious ( fn ) {
56 var chunk = this;
57 while ( chunk ) {
58 fn( chunk );
59 chunk = chunk.previous;
60 }
61 },
62
63 edit: function edit ( content, storeName, contentOnly ) {
64 this.content = content;
65 if ( !contentOnly ) {
66 this.intro = '';
67 this.outro = '';
68 }
69 this.storeName = storeName;
70
71 this.edited = true;
72
73 return this;
74 },
75
76 prependLeft: function prependLeft ( content ) {
77 this.outro = content + this.outro;
78 },
79
80 prependRight: function prependRight ( content ) {
81 this.intro = content + this.intro;
82 },
83
84 split: function split ( index ) {
85 var sliceIndex = index - this.start;
86
87 var originalBefore = this.original.slice( 0, sliceIndex );
88 var originalAfter = this.original.slice( sliceIndex );
89
90 this.original = originalBefore;
91
92 var newChunk = new Chunk( index, this.end, originalAfter );
93 newChunk.outro = this.outro;
94 this.outro = '';
95
96 this.end = index;
97
98 if ( this.edited ) {
99 // TODO is this block necessary?...
100 newChunk.edit( '', false );
101 this.content = '';
102 } else {
103 this.content = originalBefore;
104 }
105
106 newChunk.next = this.next;
107 if ( newChunk.next ) { newChunk.next.previous = newChunk; }
108 newChunk.previous = this;
109 this.next = newChunk;
110
111 return newChunk;
112 },
113
114 toString: function toString () {
115 return this.intro + this.content + this.outro;
116 },
117
118 trimEnd: function trimEnd ( rx ) {
119 this.outro = this.outro.replace( rx, '' );
120 if ( this.outro.length ) { return true; }
121
122 var trimmed = this.content.replace( rx, '' );
123
124 if ( trimmed.length ) {
125 if ( trimmed !== this.content ) {
126 this.split( this.start + trimmed.length ).edit( '', false );
127 }
128
129 return true;
130 } else {
131 this.edit( '', false );
132
133 this.intro = this.intro.replace( rx, '' );
134 if ( this.intro.length ) { return true; }
135 }
136 },
137
138 trimStart: function trimStart ( rx ) {
139 this.intro = this.intro.replace( rx, '' );
140 if ( this.intro.length ) { return true; }
141
142 var trimmed = this.content.replace( rx, '' );
143
144 if ( trimmed.length ) {
145 if ( trimmed !== this.content ) {
146 this.split( this.end - trimmed.length );
147 this.edit( '', false );
148 }
149
150 return true;
151 } else {
152 this.edit( '', false );
153
154 this.outro = this.outro.replace( rx, '' );
155 if ( this.outro.length ) { return true; }
156 }
157 }
158};
159
160var _btoa;
161
162if ( typeof window !== 'undefined' && typeof window.btoa === 'function' ) {
163 _btoa = window.btoa;
164} else if ( typeof Buffer === 'function' ) {
165 _btoa = function (str) { return new Buffer( str ).toString( 'base64' ); };
166} else {
167 _btoa = function () {
168 throw new Error( 'Unsupported environment: `window.btoa` or `Buffer` should be supported.' );
169 };
170}
171
172var btoa = _btoa;
173
174function SourceMap ( properties ) {
175 this.version = 3;
176
177 this.file = properties.file;
178 this.sources = properties.sources;
179 this.sourcesContent = properties.sourcesContent;
180 this.names = properties.names;
181 this.mappings = properties.mappings;
182}
183
184SourceMap.prototype = {
185 toString: function toString () {
186 return JSON.stringify( this );
187 },
188
189 toUrl: function toUrl () {
190 return 'data:application/json;charset=utf-8;base64,' + btoa( this.toString() );
191 }
192};
193
194function guessIndent ( code ) {
195 var lines = code.split( '\n' );
196
197 var tabbed = lines.filter( function (line) { return /^\t+/.test( line ); } );
198 var spaced = lines.filter( function (line) { return /^ {2,}/.test( line ); } );
199
200 if ( tabbed.length === 0 && spaced.length === 0 ) {
201 return null;
202 }
203
204 // More lines tabbed than spaced? Assume tabs, and
205 // default to tabs in the case of a tie (or nothing
206 // to go on)
207 if ( tabbed.length >= spaced.length ) {
208 return '\t';
209 }
210
211 // Otherwise, we need to guess the multiple
212 var min = spaced.reduce( function ( previous, current ) {
213 var numSpaces = /^ +/.exec( current )[0].length;
214 return Math.min( numSpaces, previous );
215 }, Infinity );
216
217 return new Array( min + 1 ).join( ' ' );
218}
219
220function getRelativePath ( from, to ) {
221 var fromParts = from.split( /[\/\\]/ );
222 var toParts = to.split( /[\/\\]/ );
223
224 fromParts.pop(); // get dirname
225
226 while ( fromParts[0] === toParts[0] ) {
227 fromParts.shift();
228 toParts.shift();
229 }
230
231 if ( fromParts.length ) {
232 var i = fromParts.length;
233 while ( i-- ) { fromParts[i] = '..'; }
234 }
235
236 return fromParts.concat( toParts ).join( '/' );
237}
238
239var toString = Object.prototype.toString;
240
241function isObject ( thing ) {
242 return toString.call( thing ) === '[object Object]';
243}
244
245function getLocator ( source ) {
246 var originalLines = source.split( '\n' );
247 var lineOffsets = [];
248
249 for ( var i = 0, pos = 0; i < originalLines.length; i++ ) {
250 lineOffsets.push( pos );
251 pos += originalLines[i].length + 1;
252 }
253
254 return function locate ( index ) {
255 var i = 0;
256 var j = lineOffsets.length;
257 while ( i < j ) {
258 var m = ( i + j ) >> 1;
259 if ( index < lineOffsets[m] ) {
260 j = m;
261 } else {
262 i = m + 1;
263 }
264 }
265 var line = i - 1;
266 var column = index - lineOffsets[line];
267 return { line: line, column: column };
268 };
269}
270
271var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
272function encode(decoded) {
273 var sourceFileIndex = 0; // second field
274 var sourceCodeLine = 0; // third field
275 var sourceCodeColumn = 0; // fourth field
276 var nameIndex = 0; // fifth field
277 var mappings = '';
278 for (var i = 0; i < decoded.length; i++) {
279 var line = decoded[i];
280 if (i > 0)
281 mappings += ';';
282 if (line.length === 0)
283 continue;
284 var generatedCodeColumn = 0; // first field
285 var lineMappings = [];
286 for (var _i = 0, line_1 = line; _i < line_1.length; _i++) {
287 var segment = line_1[_i];
288 var segmentMappings = encodeInteger(segment[0] - generatedCodeColumn);
289 generatedCodeColumn = segment[0];
290 if (segment.length > 1) {
291 segmentMappings +=
292 encodeInteger(segment[1] - sourceFileIndex) +
293 encodeInteger(segment[2] - sourceCodeLine) +
294 encodeInteger(segment[3] - sourceCodeColumn);
295 sourceFileIndex = segment[1];
296 sourceCodeLine = segment[2];
297 sourceCodeColumn = segment[3];
298 }
299 if (segment.length === 5) {
300 segmentMappings += encodeInteger(segment[4] - nameIndex);
301 nameIndex = segment[4];
302 }
303 lineMappings.push(segmentMappings);
304 }
305 mappings += lineMappings.join(',');
306 }
307 return mappings;
308}
309function encodeInteger(num) {
310 var result = '';
311 num = num < 0 ? (-num << 1) | 1 : num << 1;
312 do {
313 var clamped = num & 31;
314 num >>= 5;
315 if (num > 0) {
316 clamped |= 32;
317 }
318 result += chars[clamped];
319 } while (num > 0);
320 return result;
321}
322
323function Mappings ( hires ) {
324 var this$1 = this;
325
326 var generatedCodeLine = 0;
327 var generatedCodeColumn = 0;
328
329 this.raw = [];
330 var rawSegments = this.raw[ generatedCodeLine ] = [];
331
332 var pending = null;
333
334 this.addEdit = function ( sourceIndex, content, original, loc, nameIndex ) {
335 if ( content.length ) {
336 var segment = [
337 generatedCodeColumn,
338 sourceIndex,
339 loc.line,
340 loc.column
341 ];
342 if ( nameIndex >= 0 ) {
343 segment.push( nameIndex );
344 }
345 rawSegments.push( segment );
346 } else if ( pending ) {
347 rawSegments.push( pending );
348 }
349
350 this$1.advance( content );
351 pending = null;
352 };
353
354 this.addUneditedChunk = function ( sourceIndex, chunk, original, loc, sourcemapLocations ) {
355 var originalCharIndex = chunk.start;
356 var first = true;
357
358 while ( originalCharIndex < chunk.end ) {
359 if ( hires || first || sourcemapLocations[ originalCharIndex ] ) {
360 rawSegments.push([
361 generatedCodeColumn,
362 sourceIndex,
363 loc.line,
364 loc.column
365 ]);
366 }
367
368 if ( original[ originalCharIndex ] === '\n' ) {
369 loc.line += 1;
370 loc.column = 0;
371 generatedCodeLine += 1;
372 this$1.raw[ generatedCodeLine ] = rawSegments = [];
373 generatedCodeColumn = 0;
374 } else {
375 loc.column += 1;
376 generatedCodeColumn += 1;
377 }
378
379 originalCharIndex += 1;
380 first = false;
381 }
382
383 pending = [
384 generatedCodeColumn,
385 sourceIndex,
386 loc.line,
387 loc.column
388 ];
389 };
390
391 this.advance = function (str) {
392 if ( !str ) { return; }
393
394 var lines = str.split( '\n' );
395
396 if ( lines.length > 1 ) {
397 for ( var i = 0; i < lines.length - 1; i++ ) {
398 generatedCodeLine++;
399 this$1.raw[generatedCodeLine] = rawSegments = [];
400 }
401 generatedCodeColumn = 0;
402 }
403
404 generatedCodeColumn += lines[lines.length - 1].length;
405 };
406
407 this.encode = function () {
408 return encode(this$1.raw);
409 };
410}
411
412var Stats = function Stats () {
413 Object.defineProperties( this, {
414 startTimes: { value: {} }
415 });
416};
417
418Stats.prototype.time = function time ( label ) {
419 this.startTimes[ label ] = process.hrtime();
420};
421
422Stats.prototype.timeEnd = function timeEnd ( label ) {
423 var elapsed = process.hrtime( this.startTimes[ label ] );
424
425 if ( !this[ label ] ) { this[ label ] = 0; }
426 this[ label ] += elapsed[0] * 1e3 + elapsed[1] * 1e-6;
427};
428
429var warned = {
430 insertLeft: false,
431 insertRight: false,
432 storeName: false
433};
434
435function MagicString$1 ( string, options ) {
436 if ( options === void 0 ) options = {};
437
438 var chunk = new Chunk( 0, string.length, string );
439
440 Object.defineProperties( this, {
441 original: { writable: true, value: string },
442 outro: { writable: true, value: '' },
443 intro: { writable: true, value: '' },
444 firstChunk: { writable: true, value: chunk },
445 lastChunk: { writable: true, value: chunk },
446 lastSearchedChunk: { writable: true, value: chunk },
447 byStart: { writable: true, value: {} },
448 byEnd: { writable: true, value: {} },
449 filename: { writable: true, value: options.filename },
450 indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },
451 sourcemapLocations: { writable: true, value: {} },
452 storedNames: { writable: true, value: {} },
453 indentStr: { writable: true, value: guessIndent( string ) }
454 });
455
456 this.byStart[ 0 ] = chunk;
457 this.byEnd[ string.length ] = chunk;
458}
459
460MagicString$1.prototype = {
461 addSourcemapLocation: function addSourcemapLocation ( char ) {
462 this.sourcemapLocations[ char ] = true;
463 },
464
465 append: function append ( content ) {
466 if ( typeof content !== 'string' ) { throw new TypeError( 'outro content must be a string' ); }
467
468 this.outro += content;
469 return this;
470 },
471
472 appendLeft: function appendLeft ( index, content ) {
473 if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
474
475 this._split( index );
476
477 var chunk = this.byEnd[ index ];
478
479 if ( chunk ) {
480 chunk.appendLeft( content );
481 } else {
482 this.intro += content;
483 }
484
485 return this;
486 },
487
488 appendRight: function appendRight ( index, content ) {
489 if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
490
491 this._split( index );
492
493 var chunk = this.byStart[ index ];
494
495 if ( chunk ) {
496 chunk.appendRight( content );
497 } else {
498 this.outro += content;
499 }
500
501 return this;
502 },
503
504 clone: function clone () {
505 var cloned = new MagicString$1( this.original, { filename: this.filename });
506
507 var originalChunk = this.firstChunk;
508 var clonedChunk = cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone();
509
510 while ( originalChunk ) {
511 cloned.byStart[ clonedChunk.start ] = clonedChunk;
512 cloned.byEnd[ clonedChunk.end ] = clonedChunk;
513
514 var nextOriginalChunk = originalChunk.next;
515 var nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();
516
517 if ( nextClonedChunk ) {
518 clonedChunk.next = nextClonedChunk;
519 nextClonedChunk.previous = clonedChunk;
520
521 clonedChunk = nextClonedChunk;
522 }
523
524 originalChunk = nextOriginalChunk;
525 }
526
527 cloned.lastChunk = clonedChunk;
528
529 if ( this.indentExclusionRanges ) {
530 cloned.indentExclusionRanges = this.indentExclusionRanges.slice();
531 }
532
533 Object.keys( this.sourcemapLocations ).forEach( function (loc) {
534 cloned.sourcemapLocations[ loc ] = true;
535 });
536
537 return cloned;
538 },
539
540 generateMap: function generateMap ( options ) {
541 var this$1 = this;
542
543 options = options || {};
544
545 var sourceIndex = 0;
546 var names = Object.keys( this.storedNames );
547 var mappings = new Mappings( options.hires );
548
549 var locate = getLocator( this.original );
550
551 if ( this.intro ) {
552 mappings.advance( this.intro );
553 }
554
555 this.firstChunk.eachNext( function (chunk) {
556 var loc = locate( chunk.start );
557
558 if ( chunk.intro.length ) { mappings.advance( chunk.intro ); }
559
560 if ( chunk.edited ) {
561 mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
562 } else {
563 mappings.addUneditedChunk( sourceIndex, chunk, this$1.original, loc, this$1.sourcemapLocations );
564 }
565
566 if ( chunk.outro.length ) { mappings.advance( chunk.outro ); }
567 });
568
569 var map = new SourceMap({
570 file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
571 sources: [ options.source ? getRelativePath( options.file || '', options.source ) : null ],
572 sourcesContent: options.includeContent ? [ this.original ] : [ null ],
573 names: names,
574 mappings: mappings.encode()
575 });
576 return map;
577 },
578
579 getIndentString: function getIndentString () {
580 return this.indentStr === null ? '\t' : this.indentStr;
581 },
582
583 indent: function indent ( indentStr, options ) {
584 var this$1 = this;
585
586 var pattern = /^[^\r\n]/gm;
587
588 if ( isObject( indentStr ) ) {
589 options = indentStr;
590 indentStr = undefined;
591 }
592
593 indentStr = indentStr !== undefined ? indentStr : ( this.indentStr || '\t' );
594
595 if ( indentStr === '' ) { return this; } // noop
596
597 options = options || {};
598
599 // Process exclusion ranges
600 var isExcluded = {};
601
602 if ( options.exclude ) {
603 var exclusions = typeof options.exclude[0] === 'number' ? [ options.exclude ] : options.exclude;
604 exclusions.forEach( function (exclusion) {
605 for ( var i = exclusion[0]; i < exclusion[1]; i += 1 ) {
606 isExcluded[i] = true;
607 }
608 });
609 }
610
611 var shouldIndentNextCharacter = options.indentStart !== false;
612 var replacer = function (match) {
613 if ( shouldIndentNextCharacter ) { return ("" + indentStr + match); }
614 shouldIndentNextCharacter = true;
615 return match;
616 };
617
618 this.intro = this.intro.replace( pattern, replacer );
619
620 var charIndex = 0;
621
622 var chunk = this.firstChunk;
623
624 while ( chunk ) {
625 var end = chunk.end;
626
627 if ( chunk.edited ) {
628 if ( !isExcluded[ charIndex ] ) {
629 chunk.content = chunk.content.replace( pattern, replacer );
630
631 if ( chunk.content.length ) {
632 shouldIndentNextCharacter = chunk.content[ chunk.content.length - 1 ] === '\n';
633 }
634 }
635 } else {
636 charIndex = chunk.start;
637
638 while ( charIndex < end ) {
639 if ( !isExcluded[ charIndex ] ) {
640 var char = this$1.original[ charIndex ];
641
642 if ( char === '\n' ) {
643 shouldIndentNextCharacter = true;
644 } else if ( char !== '\r' && shouldIndentNextCharacter ) {
645 shouldIndentNextCharacter = false;
646
647 if ( charIndex === chunk.start ) {
648 chunk.prependRight( indentStr );
649 } else {
650 this$1._splitChunk( chunk, charIndex );
651 chunk = chunk.next;
652 chunk.prependRight( indentStr );
653 }
654 }
655 }
656
657 charIndex += 1;
658 }
659 }
660
661 charIndex = chunk.end;
662 chunk = chunk.next;
663 }
664
665 this.outro = this.outro.replace( pattern, replacer );
666
667 return this;
668 },
669
670 insert: function insert () {
671 throw new Error( 'magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)' );
672 },
673
674 insertLeft: function insertLeft ( index, content ) {
675 if ( !warned.insertLeft ) {
676 console.warn( 'magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead' ); // eslint-disable-line no-console
677 warned.insertLeft = true;
678 }
679
680 return this.appendLeft( index, content );
681 },
682
683 insertRight: function insertRight ( index, content ) {
684 if ( !warned.insertRight ) {
685 console.warn( 'magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead' ); // eslint-disable-line no-console
686 warned.insertRight = true;
687 }
688
689 return this.prependRight( index, content );
690 },
691
692 move: function move ( start, end, index ) {
693 if ( index >= start && index <= end ) { throw new Error( 'Cannot move a selection inside itself' ); }
694
695 this._split( start );
696 this._split( end );
697 this._split( index );
698
699 var first = this.byStart[ start ];
700 var last = this.byEnd[ end ];
701
702 var oldLeft = first.previous;
703 var oldRight = last.next;
704
705 var newRight = this.byStart[ index ];
706 if ( !newRight && last === this.lastChunk ) { return this; }
707 var newLeft = newRight ? newRight.previous : this.lastChunk;
708
709 if ( oldLeft ) { oldLeft.next = oldRight; }
710 if ( oldRight ) { oldRight.previous = oldLeft; }
711
712 if ( newLeft ) { newLeft.next = first; }
713 if ( newRight ) { newRight.previous = last; }
714
715 if ( !first.previous ) { this.firstChunk = last.next; }
716 if ( !last.next ) {
717 this.lastChunk = first.previous;
718 this.lastChunk.next = null;
719 }
720
721 first.previous = newLeft;
722 last.next = newRight || null;
723
724 if ( !newLeft ) { this.firstChunk = first; }
725 if ( !newRight ) { this.lastChunk = last; }
726
727 return this;
728 },
729
730 overwrite: function overwrite ( start, end, content, options ) {
731 var this$1 = this;
732
733 if ( typeof content !== 'string' ) { throw new TypeError( 'replacement content must be a string' ); }
734
735 while ( start < 0 ) { start += this$1.original.length; }
736 while ( end < 0 ) { end += this$1.original.length; }
737
738 if ( end > this.original.length ) { throw new Error( 'end is out of bounds' ); }
739 if ( start === end ) { throw new Error( 'Cannot overwrite a zero-length range – use appendLeft or prependRight instead' ); }
740
741 this._split( start );
742 this._split( end );
743
744 if ( options === true ) {
745 if ( !warned.storeName ) {
746 console.warn( 'The final argument to magicString.overwrite(...) should be an options object. See https://github.com/rich-harris/magic-string' ); // eslint-disable-line no-console
747 warned.storeName = true;
748 }
749
750 options = { storeName: true };
751 }
752 var storeName = options !== undefined ? options.storeName : false;
753 var contentOnly = options !== undefined ? options.contentOnly : false;
754
755 if ( storeName ) {
756 var original = this.original.slice( start, end );
757 this.storedNames[ original ] = true;
758 }
759
760 var first = this.byStart[ start ];
761 var last = this.byEnd[ end ];
762
763 if ( first ) {
764 if ( end > first.end && first.next !== this.byStart[ first.end ] ) {
765 throw new Error( 'Cannot overwrite across a split point' );
766 }
767
768 first.edit( content, storeName, contentOnly );
769
770 if ( first !== last ) {
771 var chunk = first.next;
772 while ( chunk !== last ) {
773 chunk.edit( '', false );
774 chunk = chunk.next;
775 }
776
777 chunk.edit( '', false );
778 }
779 }
780
781 else {
782 // must be inserting at the end
783 var newChunk = new Chunk( start, end, '' ).edit( content, storeName );
784
785 // TODO last chunk in the array may not be the last chunk, if it's moved...
786 last.next = newChunk;
787 newChunk.previous = last;
788 }
789
790 return this;
791 },
792
793 prepend: function prepend ( content ) {
794 if ( typeof content !== 'string' ) { throw new TypeError( 'outro content must be a string' ); }
795
796 this.intro = content + this.intro;
797 return this;
798 },
799
800 prependLeft: function prependLeft ( index, content ) {
801 if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
802
803 this._split( index );
804
805 var chunk = this.byEnd[ index ];
806
807 if ( chunk ) {
808 chunk.prependLeft( content );
809 } else {
810 this.intro = content + this.intro;
811 }
812
813 return this;
814 },
815
816 prependRight: function prependRight ( index, content ) {
817 if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
818
819 this._split( index );
820
821 var chunk = this.byStart[ index ];
822
823 if ( chunk ) {
824 chunk.prependRight( content );
825 } else {
826 this.outro = content + this.outro;
827 }
828
829 return this;
830 },
831
832 remove: function remove ( start, end ) {
833 var this$1 = this;
834
835 while ( start < 0 ) { start += this$1.original.length; }
836 while ( end < 0 ) { end += this$1.original.length; }
837
838 if ( start === end ) { return this; }
839
840 if ( start < 0 || end > this.original.length ) { throw new Error( 'Character is out of bounds' ); }
841 if ( start > end ) { throw new Error( 'end must be greater than start' ); }
842
843 this._split( start );
844 this._split( end );
845
846 var chunk = this.byStart[ start ];
847
848 while ( chunk ) {
849 chunk.intro = '';
850 chunk.outro = '';
851 chunk.edit( '' );
852
853 chunk = end > chunk.end ? this$1.byStart[ chunk.end ] : null;
854 }
855
856 return this;
857 },
858
859 slice: function slice ( start, end ) {
860 var this$1 = this;
861 if ( start === void 0 ) start = 0;
862 if ( end === void 0 ) end = this.original.length;
863
864 while ( start < 0 ) { start += this$1.original.length; }
865 while ( end < 0 ) { end += this$1.original.length; }
866
867 var result = '';
868
869 // find start chunk
870 var chunk = this.firstChunk;
871 while ( chunk && ( chunk.start > start || chunk.end <= start ) ) {
872
873 // found end chunk before start
874 if ( chunk.start < end && chunk.end >= end ) {
875 return result;
876 }
877
878 chunk = chunk.next;
879 }
880
881 if ( chunk && chunk.edited && chunk.start !== start ) { throw new Error(("Cannot use replaced character " + start + " as slice start anchor.")); }
882
883 var startChunk = chunk;
884 while ( chunk ) {
885 if ( chunk.intro && ( startChunk !== chunk || chunk.start === start ) ) {
886 result += chunk.intro;
887 }
888
889 var containsEnd = chunk.start < end && chunk.end >= end;
890 if ( containsEnd && chunk.edited && chunk.end !== end ) { throw new Error(("Cannot use replaced character " + end + " as slice end anchor.")); }
891
892 var sliceStart = startChunk === chunk ? start - chunk.start : 0;
893 var sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;
894
895 result += chunk.content.slice( sliceStart, sliceEnd );
896
897 if ( chunk.outro && ( !containsEnd || chunk.end === end ) ) {
898 result += chunk.outro;
899 }
900
901 if ( containsEnd ) {
902 break;
903 }
904
905 chunk = chunk.next;
906 }
907
908 return result;
909 },
910
911 // TODO deprecate this? not really very useful
912 snip: function snip ( start, end ) {
913 var clone = this.clone();
914 clone.remove( 0, start );
915 clone.remove( end, clone.original.length );
916
917 return clone;
918 },
919
920 _split: function _split ( index ) {
921 var this$1 = this;
922
923 if ( this.byStart[ index ] || this.byEnd[ index ] ) { return; }
924
925 var chunk = this.lastSearchedChunk;
926 var searchForward = index > chunk.end;
927
928 while ( true ) {
929 if ( chunk.contains( index ) ) { return this$1._splitChunk( chunk, index ); }
930
931 chunk = searchForward ?
932 this$1.byStart[ chunk.end ] :
933 this$1.byEnd[ chunk.start ];
934 }
935 },
936
937 _splitChunk: function _splitChunk ( chunk, index ) {
938 if ( chunk.edited && chunk.content.length ) { // zero-length edited chunks are a special case (overlapping replacements)
939 var loc = getLocator( this.original )( index );
940 throw new Error( ("Cannot split a chunk that has already been edited (" + (loc.line) + ":" + (loc.column) + " – \"" + (chunk.original) + "\")") );
941 }
942
943 var newChunk = chunk.split( index );
944
945 this.byEnd[ index ] = chunk;
946 this.byStart[ index ] = newChunk;
947 this.byEnd[ newChunk.end ] = newChunk;
948
949 if ( chunk === this.lastChunk ) { this.lastChunk = newChunk; }
950
951 this.lastSearchedChunk = chunk;
952 return true;
953 },
954
955 toString: function toString () {
956 var str = this.intro;
957
958 var chunk = this.firstChunk;
959 while ( chunk ) {
960 str += chunk.toString();
961 chunk = chunk.next;
962 }
963
964 return str + this.outro;
965 },
966
967 trimLines: function trimLines () {
968 return this.trim('[\\r\\n]');
969 },
970
971 trim: function trim ( charType ) {
972 return this.trimStart( charType ).trimEnd( charType );
973 },
974
975 trimEnd: function trimEnd ( charType ) {
976 var this$1 = this;
977
978 var rx = new RegExp( ( charType || '\\s' ) + '+$' );
979
980 this.outro = this.outro.replace( rx, '' );
981 if ( this.outro.length ) { return this; }
982
983 var chunk = this.lastChunk;
984
985 do {
986 var end = chunk.end;
987 var aborted = chunk.trimEnd( rx );
988
989 // if chunk was trimmed, we have a new lastChunk
990 if ( chunk.end !== end ) {
991 if ( this$1.lastChunk === chunk ) {
992 this$1.lastChunk = chunk.next;
993 }
994
995 this$1.byEnd[ chunk.end ] = chunk;
996 this$1.byStart[ chunk.next.start ] = chunk.next;
997 this$1.byEnd[ chunk.next.end ] = chunk.next;
998 }
999
1000 if ( aborted ) { return this$1; }
1001 chunk = chunk.previous;
1002 } while ( chunk );
1003
1004 return this;
1005 },
1006
1007 trimStart: function trimStart ( charType ) {
1008 var this$1 = this;
1009
1010 var rx = new RegExp( '^' + ( charType || '\\s' ) + '+' );
1011
1012 this.intro = this.intro.replace( rx, '' );
1013 if ( this.intro.length ) { return this; }
1014
1015 var chunk = this.firstChunk;
1016
1017 do {
1018 var end = chunk.end;
1019 var aborted = chunk.trimStart( rx );
1020
1021 if ( chunk.end !== end ) {
1022 // special case...
1023 if ( chunk === this$1.lastChunk ) { this$1.lastChunk = chunk.next; }
1024
1025 this$1.byEnd[ chunk.end ] = chunk;
1026 this$1.byStart[ chunk.next.start ] = chunk.next;
1027 this$1.byEnd[ chunk.next.end ] = chunk.next;
1028 }
1029
1030 if ( aborted ) { return this$1; }
1031 chunk = chunk.next;
1032 } while ( chunk );
1033
1034 return this;
1035 }
1036};
1037
1038var hasOwnProp = Object.prototype.hasOwnProperty;
1039
1040function Bundle ( options ) {
1041 if ( options === void 0 ) options = {};
1042
1043 this.intro = options.intro || '';
1044 this.separator = options.separator !== undefined ? options.separator : '\n';
1045
1046 this.sources = [];
1047
1048 this.uniqueSources = [];
1049 this.uniqueSourceIndexByFilename = {};
1050}
1051
1052Bundle.prototype = {
1053 addSource: function addSource ( source ) {
1054 if ( source instanceof MagicString$1 ) {
1055 return this.addSource({
1056 content: source,
1057 filename: source.filename,
1058 separator: this.separator
1059 });
1060 }
1061
1062 if ( !isObject( source ) || !source.content ) {
1063 throw new Error( 'bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`' );
1064 }
1065
1066 [ 'filename', 'indentExclusionRanges', 'separator' ].forEach( function (option) {
1067 if ( !hasOwnProp.call( source, option ) ) { source[ option ] = source.content[ option ]; }
1068 });
1069
1070 if ( source.separator === undefined ) { // TODO there's a bunch of this sort of thing, needs cleaning up
1071 source.separator = this.separator;
1072 }
1073
1074 if ( source.filename ) {
1075 if ( !hasOwnProp.call( this.uniqueSourceIndexByFilename, source.filename ) ) {
1076 this.uniqueSourceIndexByFilename[ source.filename ] = this.uniqueSources.length;
1077 this.uniqueSources.push({ filename: source.filename, content: source.content.original });
1078 } else {
1079 var uniqueSource = this.uniqueSources[ this.uniqueSourceIndexByFilename[ source.filename ] ];
1080 if ( source.content.original !== uniqueSource.content ) {
1081 throw new Error( ("Illegal source: same filename (" + (source.filename) + "), different contents") );
1082 }
1083 }
1084 }
1085
1086 this.sources.push( source );
1087 return this;
1088 },
1089
1090 append: function append ( str, options ) {
1091 this.addSource({
1092 content: new MagicString$1( str ),
1093 separator: ( options && options.separator ) || ''
1094 });
1095
1096 return this;
1097 },
1098
1099 clone: function clone () {
1100 var bundle = new Bundle({
1101 intro: this.intro,
1102 separator: this.separator
1103 });
1104
1105 this.sources.forEach( function (source) {
1106 bundle.addSource({
1107 filename: source.filename,
1108 content: source.content.clone(),
1109 separator: source.separator
1110 });
1111 });
1112
1113 return bundle;
1114 },
1115
1116 generateMap: function generateMap ( options ) {
1117 var this$1 = this;
1118 if ( options === void 0 ) options = {};
1119
1120 var names = [];
1121 this.sources.forEach( function (source) {
1122 Object.keys( source.content.storedNames ).forEach( function (name) {
1123 if ( !~names.indexOf( name ) ) { names.push( name ); }
1124 });
1125 });
1126
1127 var mappings = new Mappings( options.hires );
1128
1129 if ( this.intro ) {
1130 mappings.advance( this.intro );
1131 }
1132
1133 this.sources.forEach( function ( source, i ) {
1134 if ( i > 0 ) {
1135 mappings.advance( this$1.separator );
1136 }
1137
1138 var sourceIndex = source.filename ? this$1.uniqueSourceIndexByFilename[ source.filename ] : -1;
1139 var magicString = source.content;
1140 var locate = getLocator( magicString.original );
1141
1142 if ( magicString.intro ) {
1143 mappings.advance( magicString.intro );
1144 }
1145
1146 magicString.firstChunk.eachNext( function (chunk) {
1147 var loc = locate( chunk.start );
1148
1149 if ( chunk.intro.length ) { mappings.advance( chunk.intro ); }
1150
1151 if ( source.filename ) {
1152 if ( chunk.edited ) {
1153 mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
1154 } else {
1155 mappings.addUneditedChunk( sourceIndex, chunk, magicString.original, loc, magicString.sourcemapLocations );
1156 }
1157 }
1158
1159 else {
1160 mappings.advance( chunk.content );
1161 }
1162
1163 if ( chunk.outro.length ) { mappings.advance( chunk.outro ); }
1164 });
1165
1166 if ( magicString.outro ) {
1167 mappings.advance( magicString.outro );
1168 }
1169 });
1170
1171 return new SourceMap({
1172 file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
1173 sources: this.uniqueSources.map( function (source) {
1174 return options.file ? getRelativePath( options.file, source.filename ) : source.filename;
1175 }),
1176 sourcesContent: this.uniqueSources.map( function (source) {
1177 return options.includeContent ? source.content : null;
1178 }),
1179 names: names,
1180 mappings: mappings.encode()
1181 });
1182 },
1183
1184 getIndentString: function getIndentString () {
1185 var indentStringCounts = {};
1186
1187 this.sources.forEach( function (source) {
1188 var indentStr = source.content.indentStr;
1189
1190 if ( indentStr === null ) { return; }
1191
1192 if ( !indentStringCounts[ indentStr ] ) { indentStringCounts[ indentStr ] = 0; }
1193 indentStringCounts[ indentStr ] += 1;
1194 });
1195
1196 return ( Object.keys( indentStringCounts ).sort( function ( a, b ) {
1197 return indentStringCounts[a] - indentStringCounts[b];
1198 })[0] ) || '\t';
1199 },
1200
1201 indent: function indent ( indentStr ) {
1202 var this$1 = this;
1203
1204 if ( !arguments.length ) {
1205 indentStr = this.getIndentString();
1206 }
1207
1208 if ( indentStr === '' ) { return this; } // noop
1209
1210 var trailingNewline = !this.intro || this.intro.slice( -1 ) === '\n';
1211
1212 this.sources.forEach( function ( source, i ) {
1213 var separator = source.separator !== undefined ? source.separator : this$1.separator;
1214 var indentStart = trailingNewline || ( i > 0 && /\r?\n$/.test( separator ) );
1215
1216 source.content.indent( indentStr, {
1217 exclude: source.indentExclusionRanges,
1218 indentStart: indentStart//: trailingNewline || /\r?\n$/.test( separator ) //true///\r?\n/.test( separator )
1219 });
1220
1221 // TODO this is a very slow way to determine this
1222 trailingNewline = source.content.toString().slice( 0, -1 ) === '\n';
1223 });
1224
1225 if ( this.intro ) {
1226 this.intro = indentStr + this.intro.replace( /^[^\n]/gm, function ( match, index ) {
1227 return index > 0 ? indentStr + match : match;
1228 });
1229 }
1230
1231 return this;
1232 },
1233
1234 prepend: function prepend ( str ) {
1235 this.intro = str + this.intro;
1236 return this;
1237 },
1238
1239 toString: function toString () {
1240 var this$1 = this;
1241
1242 var body = this.sources.map( function ( source, i ) {
1243 var separator = source.separator !== undefined ? source.separator : this$1.separator;
1244 var str = ( i > 0 ? separator : '' ) + source.content.toString();
1245
1246 return str;
1247 }).join( '' );
1248
1249 return this.intro + body;
1250 },
1251
1252 trimLines: function trimLines () {
1253 return this.trim('[\\r\\n]');
1254 },
1255
1256 trim: function trim ( charType ) {
1257 return this.trimStart( charType ).trimEnd( charType );
1258 },
1259
1260 trimStart: function trimStart ( charType ) {
1261 var this$1 = this;
1262
1263 var rx = new RegExp( '^' + ( charType || '\\s' ) + '+' );
1264 this.intro = this.intro.replace( rx, '' );
1265
1266 if ( !this.intro ) {
1267 var source;
1268 var i = 0;
1269
1270 do {
1271 source = this$1.sources[i];
1272
1273 if ( !source ) {
1274 break;
1275 }
1276
1277 source.content.trimStart( charType );
1278 i += 1;
1279 } while ( source.content.toString() === '' ); // TODO faster way to determine non-empty source?
1280 }
1281
1282 return this;
1283 },
1284
1285 trimEnd: function trimEnd ( charType ) {
1286 var this$1 = this;
1287
1288 var rx = new RegExp( ( charType || '\\s' ) + '+$' );
1289
1290 var source;
1291 var i = this.sources.length - 1;
1292
1293 do {
1294 source = this$1.sources[i];
1295
1296 if ( !source ) {
1297 this$1.intro = this$1.intro.replace( rx, '' );
1298 break;
1299 }
1300
1301 source.content.trimEnd( charType );
1302 i -= 1;
1303 } while ( source.content.toString() === '' ); // TODO faster way to determine non-empty source?
1304
1305 return this;
1306 }
1307};
1308
1309MagicString$1.Bundle = Bundle;
1310MagicString$1.default = MagicString$1; // work around TypeScript bug https://github.com/Rich-Harris/magic-string/pull/121
1311
1312module.exports = MagicString$1;
1313//# sourceMappingURL=magic-string.cjs.js.map