magic-string.umd.js 33KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353
  1. (function (global, factory) {
  2. typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory() :
  3. typeof define === 'function' && define.amd ? define(factory) :
  4. (global.MagicString = factory());
  5. }(this, (function () { 'use strict';
  6. function Chunk ( start, end, content ) {
  7. this.start = start;
  8. this.end = end;
  9. this.original = content;
  10. this.intro = '';
  11. this.outro = '';
  12. this.content = content;
  13. this.storeName = false;
  14. this.edited = false;
  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. Chunk.prototype = {
  22. appendLeft: function appendLeft ( content ) {
  23. this.outro += content;
  24. },
  25. appendRight: function appendRight ( content ) {
  26. this.intro = this.intro + content;
  27. },
  28. clone: function clone () {
  29. var chunk = new Chunk( this.start, this.end, this.original );
  30. chunk.intro = this.intro;
  31. chunk.outro = this.outro;
  32. chunk.content = this.content;
  33. chunk.storeName = this.storeName;
  34. chunk.edited = this.edited;
  35. return chunk;
  36. },
  37. contains: function contains ( index ) {
  38. return this.start < index && index < this.end;
  39. },
  40. eachNext: function eachNext ( fn ) {
  41. var chunk = this;
  42. while ( chunk ) {
  43. fn( chunk );
  44. chunk = chunk.next;
  45. }
  46. },
  47. eachPrevious: function eachPrevious ( fn ) {
  48. var chunk = this;
  49. while ( chunk ) {
  50. fn( chunk );
  51. chunk = chunk.previous;
  52. }
  53. },
  54. edit: function edit ( content, storeName, contentOnly ) {
  55. this.content = content;
  56. if ( !contentOnly ) {
  57. this.intro = '';
  58. this.outro = '';
  59. }
  60. this.storeName = storeName;
  61. this.edited = true;
  62. return this;
  63. },
  64. prependLeft: function prependLeft ( content ) {
  65. this.outro = content + this.outro;
  66. },
  67. prependRight: function prependRight ( content ) {
  68. this.intro = content + this.intro;
  69. },
  70. split: function split ( index ) {
  71. var sliceIndex = index - this.start;
  72. var originalBefore = this.original.slice( 0, sliceIndex );
  73. var originalAfter = this.original.slice( sliceIndex );
  74. this.original = originalBefore;
  75. var newChunk = new Chunk( index, this.end, originalAfter );
  76. newChunk.outro = this.outro;
  77. this.outro = '';
  78. this.end = index;
  79. if ( this.edited ) {
  80. // TODO is this block necessary?...
  81. newChunk.edit( '', false );
  82. this.content = '';
  83. } else {
  84. this.content = originalBefore;
  85. }
  86. newChunk.next = this.next;
  87. if ( newChunk.next ) { newChunk.next.previous = newChunk; }
  88. newChunk.previous = this;
  89. this.next = newChunk;
  90. return newChunk;
  91. },
  92. toString: function toString () {
  93. return this.intro + this.content + this.outro;
  94. },
  95. trimEnd: function trimEnd ( rx ) {
  96. this.outro = this.outro.replace( rx, '' );
  97. if ( this.outro.length ) { return true; }
  98. var trimmed = this.content.replace( rx, '' );
  99. if ( trimmed.length ) {
  100. if ( trimmed !== this.content ) {
  101. this.split( this.start + trimmed.length ).edit( '', false );
  102. }
  103. return true;
  104. } else {
  105. this.edit( '', false );
  106. this.intro = this.intro.replace( rx, '' );
  107. if ( this.intro.length ) { return true; }
  108. }
  109. },
  110. trimStart: function trimStart ( rx ) {
  111. this.intro = this.intro.replace( rx, '' );
  112. if ( this.intro.length ) { return true; }
  113. var trimmed = this.content.replace( rx, '' );
  114. if ( trimmed.length ) {
  115. if ( trimmed !== this.content ) {
  116. this.split( this.end - trimmed.length );
  117. this.edit( '', false );
  118. }
  119. return true;
  120. } else {
  121. this.edit( '', false );
  122. this.outro = this.outro.replace( rx, '' );
  123. if ( this.outro.length ) { return true; }
  124. }
  125. }
  126. };
  127. var _btoa;
  128. if ( typeof window !== 'undefined' && typeof window.btoa === 'function' ) {
  129. _btoa = window.btoa;
  130. } else if ( typeof Buffer === 'function' ) {
  131. _btoa = function (str) { return new Buffer( str ).toString( 'base64' ); };
  132. } else {
  133. _btoa = function () {
  134. throw new Error( 'Unsupported environment: `window.btoa` or `Buffer` should be supported.' );
  135. };
  136. }
  137. var btoa = _btoa;
  138. function SourceMap ( properties ) {
  139. this.version = 3;
  140. this.file = properties.file;
  141. this.sources = properties.sources;
  142. this.sourcesContent = properties.sourcesContent;
  143. this.names = properties.names;
  144. this.mappings = properties.mappings;
  145. }
  146. SourceMap.prototype = {
  147. toString: function toString () {
  148. return JSON.stringify( this );
  149. },
  150. toUrl: function toUrl () {
  151. return 'data:application/json;charset=utf-8;base64,' + btoa( this.toString() );
  152. }
  153. };
  154. function guessIndent ( code ) {
  155. var lines = code.split( '\n' );
  156. var tabbed = lines.filter( function (line) { return /^\t+/.test( line ); } );
  157. var spaced = lines.filter( function (line) { return /^ {2,}/.test( line ); } );
  158. if ( tabbed.length === 0 && spaced.length === 0 ) {
  159. return null;
  160. }
  161. // More lines tabbed than spaced? Assume tabs, and
  162. // default to tabs in the case of a tie (or nothing
  163. // to go on)
  164. if ( tabbed.length >= spaced.length ) {
  165. return '\t';
  166. }
  167. // Otherwise, we need to guess the multiple
  168. var min = spaced.reduce( function ( previous, current ) {
  169. var numSpaces = /^ +/.exec( current )[0].length;
  170. return Math.min( numSpaces, previous );
  171. }, Infinity );
  172. return new Array( min + 1 ).join( ' ' );
  173. }
  174. function getRelativePath ( from, to ) {
  175. var fromParts = from.split( /[\/\\]/ );
  176. var toParts = to.split( /[\/\\]/ );
  177. fromParts.pop(); // get dirname
  178. while ( fromParts[0] === toParts[0] ) {
  179. fromParts.shift();
  180. toParts.shift();
  181. }
  182. if ( fromParts.length ) {
  183. var i = fromParts.length;
  184. while ( i-- ) { fromParts[i] = '..'; }
  185. }
  186. return fromParts.concat( toParts ).join( '/' );
  187. }
  188. var toString = Object.prototype.toString;
  189. function isObject ( thing ) {
  190. return toString.call( thing ) === '[object Object]';
  191. }
  192. function getLocator ( source ) {
  193. var originalLines = source.split( '\n' );
  194. var start = 0;
  195. var lineRanges = originalLines.map( function ( line, i ) {
  196. var end = start + line.length + 1;
  197. var range = { start: start, end: end, line: i };
  198. start = end;
  199. return range;
  200. });
  201. var i = 0;
  202. function rangeContains ( range, index ) {
  203. return range.start <= index && index < range.end;
  204. }
  205. function getLocation ( range, index ) {
  206. return { line: range.line, column: index - range.start };
  207. }
  208. return function locate ( index ) {
  209. var range = lineRanges[i];
  210. var d = index >= range.end ? 1 : -1;
  211. while ( range ) {
  212. if ( rangeContains( range, index ) ) { return getLocation( range, index ); }
  213. i += d;
  214. range = lineRanges[i];
  215. }
  216. };
  217. }
  218. var charToInteger = {};
  219. var integerToChar = {};
  220. 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='.split( '' ).forEach( function ( char, i ) {
  221. charToInteger[ char ] = i;
  222. integerToChar[ i ] = char;
  223. });
  224. function encode ( value ) {
  225. var result;
  226. if ( typeof value === 'number' ) {
  227. result = encodeInteger( value );
  228. } else {
  229. result = '';
  230. for ( var i = 0; i < value.length; i += 1 ) {
  231. result += encodeInteger( value[i] );
  232. }
  233. }
  234. return result;
  235. }
  236. function encodeInteger ( num ) {
  237. var result = '';
  238. if ( num < 0 ) {
  239. num = ( -num << 1 ) | 1;
  240. } else {
  241. num <<= 1;
  242. }
  243. do {
  244. var clamped = num & 31;
  245. num >>= 5;
  246. if ( num > 0 ) {
  247. clamped |= 32;
  248. }
  249. result += integerToChar[ clamped ];
  250. } while ( num > 0 );
  251. return result;
  252. }
  253. function Mappings ( hires ) {
  254. var this$1 = this;
  255. var offsets = {
  256. generatedCodeColumn: 0,
  257. sourceIndex: 0,
  258. sourceCodeLine: 0,
  259. sourceCodeColumn: 0,
  260. sourceCodeName: 0
  261. };
  262. var generatedCodeLine = 0;
  263. var generatedCodeColumn = 0;
  264. this.raw = [];
  265. var rawSegments = this.raw[ generatedCodeLine ] = [];
  266. var pending = null;
  267. this.addEdit = function ( sourceIndex, content, original, loc, nameIndex ) {
  268. if ( content.length ) {
  269. rawSegments.push([
  270. generatedCodeColumn,
  271. sourceIndex,
  272. loc.line,
  273. loc.column,
  274. nameIndex ]);
  275. } else if ( pending ) {
  276. rawSegments.push( pending );
  277. }
  278. this$1.advance( content );
  279. pending = null;
  280. };
  281. this.addUneditedChunk = function ( sourceIndex, chunk, original, loc, sourcemapLocations ) {
  282. var originalCharIndex = chunk.start;
  283. var first = true;
  284. while ( originalCharIndex < chunk.end ) {
  285. if ( hires || first || sourcemapLocations[ originalCharIndex ] ) {
  286. rawSegments.push([
  287. generatedCodeColumn,
  288. sourceIndex,
  289. loc.line,
  290. loc.column,
  291. -1
  292. ]);
  293. }
  294. if ( original[ originalCharIndex ] === '\n' ) {
  295. loc.line += 1;
  296. loc.column = 0;
  297. generatedCodeLine += 1;
  298. this$1.raw[ generatedCodeLine ] = rawSegments = [];
  299. generatedCodeColumn = 0;
  300. } else {
  301. loc.column += 1;
  302. generatedCodeColumn += 1;
  303. }
  304. originalCharIndex += 1;
  305. first = false;
  306. }
  307. pending = [
  308. generatedCodeColumn,
  309. sourceIndex,
  310. loc.line,
  311. loc.column,
  312. -1 ];
  313. };
  314. this.advance = function (str) {
  315. if ( !str ) { return; }
  316. var lines = str.split( '\n' );
  317. var lastLine = lines.pop();
  318. if ( lines.length ) {
  319. generatedCodeLine += lines.length;
  320. this$1.raw[ generatedCodeLine ] = rawSegments = [];
  321. generatedCodeColumn = lastLine.length;
  322. } else {
  323. generatedCodeColumn += lastLine.length;
  324. }
  325. };
  326. this.encode = function () {
  327. return this$1.raw.map( function (segments) {
  328. var generatedCodeColumn = 0;
  329. return segments.map( function (segment) {
  330. var arr = [
  331. segment[0] - generatedCodeColumn,
  332. segment[1] - offsets.sourceIndex,
  333. segment[2] - offsets.sourceCodeLine,
  334. segment[3] - offsets.sourceCodeColumn
  335. ];
  336. generatedCodeColumn = segment[0];
  337. offsets.sourceIndex = segment[1];
  338. offsets.sourceCodeLine = segment[2];
  339. offsets.sourceCodeColumn = segment[3];
  340. if ( ~segment[4] ) {
  341. arr.push( segment[4] - offsets.sourceCodeName );
  342. offsets.sourceCodeName = segment[4];
  343. }
  344. return encode( arr );
  345. }).join( ',' );
  346. }).join( ';' );
  347. };
  348. }
  349. var Stats = function Stats () {
  350. Object.defineProperties( this, {
  351. startTimes: { value: {} }
  352. });
  353. };
  354. Stats.prototype.time = function time ( label ) {
  355. this.startTimes[ label ] = process.hrtime();
  356. };
  357. Stats.prototype.timeEnd = function timeEnd ( label ) {
  358. var elapsed = process.hrtime( this.startTimes[ label ] );
  359. if ( !this[ label ] ) { this[ label ] = 0; }
  360. this[ label ] += elapsed[0] * 1e3 + elapsed[1] * 1e-6;
  361. };
  362. var warned = {
  363. insertLeft: false,
  364. insertRight: false,
  365. storeName: false
  366. };
  367. function MagicString$1 ( string, options ) {
  368. if ( options === void 0 ) options = {};
  369. var chunk = new Chunk( 0, string.length, string );
  370. Object.defineProperties( this, {
  371. original: { writable: true, value: string },
  372. outro: { writable: true, value: '' },
  373. intro: { writable: true, value: '' },
  374. firstChunk: { writable: true, value: chunk },
  375. lastChunk: { writable: true, value: chunk },
  376. lastSearchedChunk: { writable: true, value: chunk },
  377. byStart: { writable: true, value: {} },
  378. byEnd: { writable: true, value: {} },
  379. filename: { writable: true, value: options.filename },
  380. indentExclusionRanges: { writable: true, value: options.indentExclusionRanges },
  381. sourcemapLocations: { writable: true, value: {} },
  382. storedNames: { writable: true, value: {} },
  383. indentStr: { writable: true, value: guessIndent( string ) }
  384. });
  385. this.byStart[ 0 ] = chunk;
  386. this.byEnd[ string.length ] = chunk;
  387. }
  388. MagicString$1.prototype = {
  389. addSourcemapLocation: function addSourcemapLocation ( char ) {
  390. this.sourcemapLocations[ char ] = true;
  391. },
  392. append: function append ( content ) {
  393. if ( typeof content !== 'string' ) { throw new TypeError( 'outro content must be a string' ); }
  394. this.outro += content;
  395. return this;
  396. },
  397. appendLeft: function appendLeft ( index, content ) {
  398. if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
  399. this._split( index );
  400. var chunk = this.byEnd[ index ];
  401. if ( chunk ) {
  402. chunk.appendLeft( content );
  403. } else {
  404. this.intro += content;
  405. }
  406. return this;
  407. },
  408. appendRight: function appendRight ( index, content ) {
  409. if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
  410. this._split( index );
  411. var chunk = this.byStart[ index ];
  412. if ( chunk ) {
  413. chunk.appendRight( content );
  414. } else {
  415. this.outro += content;
  416. }
  417. return this;
  418. },
  419. clone: function clone () {
  420. var cloned = new MagicString$1( this.original, { filename: this.filename });
  421. var originalChunk = this.firstChunk;
  422. var clonedChunk = cloned.firstChunk = cloned.lastSearchedChunk = originalChunk.clone();
  423. while ( originalChunk ) {
  424. cloned.byStart[ clonedChunk.start ] = clonedChunk;
  425. cloned.byEnd[ clonedChunk.end ] = clonedChunk;
  426. var nextOriginalChunk = originalChunk.next;
  427. var nextClonedChunk = nextOriginalChunk && nextOriginalChunk.clone();
  428. if ( nextClonedChunk ) {
  429. clonedChunk.next = nextClonedChunk;
  430. nextClonedChunk.previous = clonedChunk;
  431. clonedChunk = nextClonedChunk;
  432. }
  433. originalChunk = nextOriginalChunk;
  434. }
  435. cloned.lastChunk = clonedChunk;
  436. if ( this.indentExclusionRanges ) {
  437. cloned.indentExclusionRanges = this.indentExclusionRanges.slice();
  438. }
  439. Object.keys( this.sourcemapLocations ).forEach( function (loc) {
  440. cloned.sourcemapLocations[ loc ] = true;
  441. });
  442. return cloned;
  443. },
  444. generateMap: function generateMap ( options ) {
  445. var this$1 = this;
  446. options = options || {};
  447. var sourceIndex = 0;
  448. var names = Object.keys( this.storedNames );
  449. var mappings = new Mappings( options.hires );
  450. var locate = getLocator( this.original );
  451. if ( this.intro ) {
  452. mappings.advance( this.intro );
  453. }
  454. this.firstChunk.eachNext( function (chunk) {
  455. var loc = locate( chunk.start );
  456. if ( chunk.intro.length ) { mappings.advance( chunk.intro ); }
  457. if ( chunk.edited ) {
  458. mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
  459. } else {
  460. mappings.addUneditedChunk( sourceIndex, chunk, this$1.original, loc, this$1.sourcemapLocations );
  461. }
  462. if ( chunk.outro.length ) { mappings.advance( chunk.outro ); }
  463. });
  464. var map = new SourceMap({
  465. file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
  466. sources: [ options.source ? getRelativePath( options.file || '', options.source ) : null ],
  467. sourcesContent: options.includeContent ? [ this.original ] : [ null ],
  468. names: names,
  469. mappings: mappings.encode()
  470. });
  471. return map;
  472. },
  473. getIndentString: function getIndentString () {
  474. return this.indentStr === null ? '\t' : this.indentStr;
  475. },
  476. indent: function indent ( indentStr, options ) {
  477. var this$1 = this;
  478. var pattern = /^[^\r\n]/gm;
  479. if ( isObject( indentStr ) ) {
  480. options = indentStr;
  481. indentStr = undefined;
  482. }
  483. indentStr = indentStr !== undefined ? indentStr : ( this.indentStr || '\t' );
  484. if ( indentStr === '' ) { return this; } // noop
  485. options = options || {};
  486. // Process exclusion ranges
  487. var isExcluded = {};
  488. if ( options.exclude ) {
  489. var exclusions = typeof options.exclude[0] === 'number' ? [ options.exclude ] : options.exclude;
  490. exclusions.forEach( function (exclusion) {
  491. for ( var i = exclusion[0]; i < exclusion[1]; i += 1 ) {
  492. isExcluded[i] = true;
  493. }
  494. });
  495. }
  496. var shouldIndentNextCharacter = options.indentStart !== false;
  497. var replacer = function (match) {
  498. if ( shouldIndentNextCharacter ) { return ("" + indentStr + match); }
  499. shouldIndentNextCharacter = true;
  500. return match;
  501. };
  502. this.intro = this.intro.replace( pattern, replacer );
  503. var charIndex = 0;
  504. var chunk = this.firstChunk;
  505. while ( chunk ) {
  506. var end = chunk.end;
  507. if ( chunk.edited ) {
  508. if ( !isExcluded[ charIndex ] ) {
  509. chunk.content = chunk.content.replace( pattern, replacer );
  510. if ( chunk.content.length ) {
  511. shouldIndentNextCharacter = chunk.content[ chunk.content.length - 1 ] === '\n';
  512. }
  513. }
  514. } else {
  515. charIndex = chunk.start;
  516. while ( charIndex < end ) {
  517. if ( !isExcluded[ charIndex ] ) {
  518. var char = this$1.original[ charIndex ];
  519. if ( char === '\n' ) {
  520. shouldIndentNextCharacter = true;
  521. } else if ( char !== '\r' && shouldIndentNextCharacter ) {
  522. shouldIndentNextCharacter = false;
  523. if ( charIndex === chunk.start ) {
  524. chunk.prependRight( indentStr );
  525. } else {
  526. this$1._splitChunk( chunk, charIndex );
  527. chunk = chunk.next;
  528. chunk.prependRight( indentStr );
  529. }
  530. }
  531. }
  532. charIndex += 1;
  533. }
  534. }
  535. charIndex = chunk.end;
  536. chunk = chunk.next;
  537. }
  538. this.outro = this.outro.replace( pattern, replacer );
  539. return this;
  540. },
  541. insert: function insert () {
  542. throw new Error( 'magicString.insert(...) is deprecated. Use prependRight(...) or appendLeft(...)' );
  543. },
  544. insertLeft: function insertLeft ( index, content ) {
  545. if ( !warned.insertLeft ) {
  546. console.warn( 'magicString.insertLeft(...) is deprecated. Use magicString.appendLeft(...) instead' ); // eslint-disable-line no-console
  547. warned.insertLeft = true;
  548. }
  549. return this.appendLeft( index, content );
  550. },
  551. insertRight: function insertRight ( index, content ) {
  552. if ( !warned.insertRight ) {
  553. console.warn( 'magicString.insertRight(...) is deprecated. Use magicString.prependRight(...) instead' ); // eslint-disable-line no-console
  554. warned.insertRight = true;
  555. }
  556. return this.prependRight( index, content );
  557. },
  558. move: function move ( start, end, index ) {
  559. if ( index >= start && index <= end ) { throw new Error( 'Cannot move a selection inside itself' ); }
  560. this._split( start );
  561. this._split( end );
  562. this._split( index );
  563. var first = this.byStart[ start ];
  564. var last = this.byEnd[ end ];
  565. var oldLeft = first.previous;
  566. var oldRight = last.next;
  567. var newRight = this.byStart[ index ];
  568. if ( !newRight && last === this.lastChunk ) { return this; }
  569. var newLeft = newRight ? newRight.previous : this.lastChunk;
  570. if ( oldLeft ) { oldLeft.next = oldRight; }
  571. if ( oldRight ) { oldRight.previous = oldLeft; }
  572. if ( newLeft ) { newLeft.next = first; }
  573. if ( newRight ) { newRight.previous = last; }
  574. if ( !first.previous ) { this.firstChunk = last.next; }
  575. if ( !last.next ) {
  576. this.lastChunk = first.previous;
  577. this.lastChunk.next = null;
  578. }
  579. first.previous = newLeft;
  580. last.next = newRight || null;
  581. if ( !newLeft ) { this.firstChunk = first; }
  582. if ( !newRight ) { this.lastChunk = last; }
  583. return this;
  584. },
  585. overwrite: function overwrite ( start, end, content, options ) {
  586. var this$1 = this;
  587. if ( typeof content !== 'string' ) { throw new TypeError( 'replacement content must be a string' ); }
  588. while ( start < 0 ) { start += this$1.original.length; }
  589. while ( end < 0 ) { end += this$1.original.length; }
  590. if ( end > this.original.length ) { throw new Error( 'end is out of bounds' ); }
  591. if ( start === end ) { throw new Error( 'Cannot overwrite a zero-length range – use appendLeft or prependRight instead' ); }
  592. this._split( start );
  593. this._split( end );
  594. if ( options === true ) {
  595. if ( !warned.storeName ) {
  596. 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
  597. warned.storeName = true;
  598. }
  599. options = { storeName: true };
  600. }
  601. var storeName = options !== undefined ? options.storeName : false;
  602. var contentOnly = options !== undefined ? options.contentOnly : false;
  603. if ( storeName ) {
  604. var original = this.original.slice( start, end );
  605. this.storedNames[ original ] = true;
  606. }
  607. var first = this.byStart[ start ];
  608. var last = this.byEnd[ end ];
  609. if ( first ) {
  610. if ( end > first.end && first.next !== this.byStart[ first.end ] ) {
  611. throw new Error( 'Cannot overwrite across a split point' );
  612. }
  613. first.edit( content, storeName, contentOnly );
  614. if ( first !== last ) {
  615. var chunk = first.next;
  616. while ( chunk !== last ) {
  617. chunk.edit( '', false );
  618. chunk = chunk.next;
  619. }
  620. chunk.edit( '', false );
  621. }
  622. }
  623. else {
  624. // must be inserting at the end
  625. var newChunk = new Chunk( start, end, '' ).edit( content, storeName );
  626. // TODO last chunk in the array may not be the last chunk, if it's moved...
  627. last.next = newChunk;
  628. newChunk.previous = last;
  629. }
  630. return this;
  631. },
  632. prepend: function prepend ( content ) {
  633. if ( typeof content !== 'string' ) { throw new TypeError( 'outro content must be a string' ); }
  634. this.intro = content + this.intro;
  635. return this;
  636. },
  637. prependLeft: function prependLeft ( index, content ) {
  638. if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
  639. this._split( index );
  640. var chunk = this.byEnd[ index ];
  641. if ( chunk ) {
  642. chunk.prependLeft( content );
  643. } else {
  644. this.intro = content + this.intro;
  645. }
  646. return this;
  647. },
  648. prependRight: function prependRight ( index, content ) {
  649. if ( typeof content !== 'string' ) { throw new TypeError( 'inserted content must be a string' ); }
  650. this._split( index );
  651. var chunk = this.byStart[ index ];
  652. if ( chunk ) {
  653. chunk.prependRight( content );
  654. } else {
  655. this.outro = content + this.outro;
  656. }
  657. return this;
  658. },
  659. remove: function remove ( start, end ) {
  660. var this$1 = this;
  661. while ( start < 0 ) { start += this$1.original.length; }
  662. while ( end < 0 ) { end += this$1.original.length; }
  663. if ( start === end ) { return this; }
  664. if ( start < 0 || end > this.original.length ) { throw new Error( 'Character is out of bounds' ); }
  665. if ( start > end ) { throw new Error( 'end must be greater than start' ); }
  666. this._split( start );
  667. this._split( end );
  668. var chunk = this.byStart[ start ];
  669. while ( chunk ) {
  670. chunk.intro = '';
  671. chunk.outro = '';
  672. chunk.edit( '' );
  673. chunk = end > chunk.end ? this$1.byStart[ chunk.end ] : null;
  674. }
  675. return this;
  676. },
  677. slice: function slice ( start, end ) {
  678. var this$1 = this;
  679. if ( start === void 0 ) start = 0;
  680. if ( end === void 0 ) end = this.original.length;
  681. while ( start < 0 ) { start += this$1.original.length; }
  682. while ( end < 0 ) { end += this$1.original.length; }
  683. var result = '';
  684. // find start chunk
  685. var chunk = this.firstChunk;
  686. while ( chunk && ( chunk.start > start || chunk.end <= start ) ) {
  687. // found end chunk before start
  688. if ( chunk.start < end && chunk.end >= end ) {
  689. return result;
  690. }
  691. chunk = chunk.next;
  692. }
  693. if ( chunk && chunk.edited && chunk.start !== start ) { throw new Error(("Cannot use replaced character " + start + " as slice start anchor.")); }
  694. var startChunk = chunk;
  695. while ( chunk ) {
  696. if ( chunk.intro && ( startChunk !== chunk || chunk.start === start ) ) {
  697. result += chunk.intro;
  698. }
  699. var containsEnd = chunk.start < end && chunk.end >= end;
  700. if ( containsEnd && chunk.edited && chunk.end !== end ) { throw new Error(("Cannot use replaced character " + end + " as slice end anchor.")); }
  701. var sliceStart = startChunk === chunk ? start - chunk.start : 0;
  702. var sliceEnd = containsEnd ? chunk.content.length + end - chunk.end : chunk.content.length;
  703. result += chunk.content.slice( sliceStart, sliceEnd );
  704. if ( chunk.outro && ( !containsEnd || chunk.end === end ) ) {
  705. result += chunk.outro;
  706. }
  707. if ( containsEnd ) {
  708. break;
  709. }
  710. chunk = chunk.next;
  711. }
  712. return result;
  713. },
  714. // TODO deprecate this? not really very useful
  715. snip: function snip ( start, end ) {
  716. var clone = this.clone();
  717. clone.remove( 0, start );
  718. clone.remove( end, clone.original.length );
  719. return clone;
  720. },
  721. _split: function _split ( index ) {
  722. var this$1 = this;
  723. if ( this.byStart[ index ] || this.byEnd[ index ] ) { return; }
  724. var chunk = this.lastSearchedChunk;
  725. var searchForward = index > chunk.end;
  726. while ( true ) {
  727. if ( chunk.contains( index ) ) { return this$1._splitChunk( chunk, index ); }
  728. chunk = searchForward ?
  729. this$1.byStart[ chunk.end ] :
  730. this$1.byEnd[ chunk.start ];
  731. }
  732. },
  733. _splitChunk: function _splitChunk ( chunk, index ) {
  734. if ( chunk.edited && chunk.content.length ) { // zero-length edited chunks are a special case (overlapping replacements)
  735. var loc = getLocator( this.original )( index );
  736. throw new Error( ("Cannot split a chunk that has already been edited (" + (loc.line) + ":" + (loc.column) + " – \"" + (chunk.original) + "\")") );
  737. }
  738. var newChunk = chunk.split( index );
  739. this.byEnd[ index ] = chunk;
  740. this.byStart[ index ] = newChunk;
  741. this.byEnd[ newChunk.end ] = newChunk;
  742. if ( chunk === this.lastChunk ) { this.lastChunk = newChunk; }
  743. this.lastSearchedChunk = chunk;
  744. return true;
  745. },
  746. toString: function toString () {
  747. var str = this.intro;
  748. var chunk = this.firstChunk;
  749. while ( chunk ) {
  750. str += chunk.toString();
  751. chunk = chunk.next;
  752. }
  753. return str + this.outro;
  754. },
  755. trimLines: function trimLines () {
  756. return this.trim('[\\r\\n]');
  757. },
  758. trim: function trim ( charType ) {
  759. return this.trimStart( charType ).trimEnd( charType );
  760. },
  761. trimEnd: function trimEnd ( charType ) {
  762. var this$1 = this;
  763. var rx = new RegExp( ( charType || '\\s' ) + '+$' );
  764. this.outro = this.outro.replace( rx, '' );
  765. if ( this.outro.length ) { return this; }
  766. var chunk = this.lastChunk;
  767. do {
  768. var end = chunk.end;
  769. var aborted = chunk.trimEnd( rx );
  770. // if chunk was trimmed, we have a new lastChunk
  771. if ( chunk.end !== end ) {
  772. if ( this$1.lastChunk === chunk ) {
  773. this$1.lastChunk = chunk.next;
  774. }
  775. this$1.byEnd[ chunk.end ] = chunk;
  776. this$1.byStart[ chunk.next.start ] = chunk.next;
  777. this$1.byEnd[ chunk.next.end ] = chunk.next;
  778. }
  779. if ( aborted ) { return this$1; }
  780. chunk = chunk.previous;
  781. } while ( chunk );
  782. return this;
  783. },
  784. trimStart: function trimStart ( charType ) {
  785. var this$1 = this;
  786. var rx = new RegExp( '^' + ( charType || '\\s' ) + '+' );
  787. this.intro = this.intro.replace( rx, '' );
  788. if ( this.intro.length ) { return this; }
  789. var chunk = this.firstChunk;
  790. do {
  791. var end = chunk.end;
  792. var aborted = chunk.trimStart( rx );
  793. if ( chunk.end !== end ) {
  794. // special case...
  795. if ( chunk === this$1.lastChunk ) { this$1.lastChunk = chunk.next; }
  796. this$1.byEnd[ chunk.end ] = chunk;
  797. this$1.byStart[ chunk.next.start ] = chunk.next;
  798. this$1.byEnd[ chunk.next.end ] = chunk.next;
  799. }
  800. if ( aborted ) { return this$1; }
  801. chunk = chunk.next;
  802. } while ( chunk );
  803. return this;
  804. }
  805. };
  806. var hasOwnProp = Object.prototype.hasOwnProperty;
  807. function Bundle ( options ) {
  808. if ( options === void 0 ) options = {};
  809. this.intro = options.intro || '';
  810. this.separator = options.separator !== undefined ? options.separator : '\n';
  811. this.sources = [];
  812. this.uniqueSources = [];
  813. this.uniqueSourceIndexByFilename = {};
  814. }
  815. Bundle.prototype = {
  816. addSource: function addSource ( source ) {
  817. if ( source instanceof MagicString$1 ) {
  818. return this.addSource({
  819. content: source,
  820. filename: source.filename,
  821. separator: this.separator
  822. });
  823. }
  824. if ( !isObject( source ) || !source.content ) {
  825. throw new Error( 'bundle.addSource() takes an object with a `content` property, which should be an instance of MagicString, and an optional `filename`' );
  826. }
  827. [ 'filename', 'indentExclusionRanges', 'separator' ].forEach( function (option) {
  828. if ( !hasOwnProp.call( source, option ) ) { source[ option ] = source.content[ option ]; }
  829. });
  830. if ( source.separator === undefined ) { // TODO there's a bunch of this sort of thing, needs cleaning up
  831. source.separator = this.separator;
  832. }
  833. if ( source.filename ) {
  834. if ( !hasOwnProp.call( this.uniqueSourceIndexByFilename, source.filename ) ) {
  835. this.uniqueSourceIndexByFilename[ source.filename ] = this.uniqueSources.length;
  836. this.uniqueSources.push({ filename: source.filename, content: source.content.original });
  837. } else {
  838. var uniqueSource = this.uniqueSources[ this.uniqueSourceIndexByFilename[ source.filename ] ];
  839. if ( source.content.original !== uniqueSource.content ) {
  840. throw new Error( ("Illegal source: same filename (" + (source.filename) + "), different contents") );
  841. }
  842. }
  843. }
  844. this.sources.push( source );
  845. return this;
  846. },
  847. append: function append ( str, options ) {
  848. this.addSource({
  849. content: new MagicString$1( str ),
  850. separator: ( options && options.separator ) || ''
  851. });
  852. return this;
  853. },
  854. clone: function clone () {
  855. var bundle = new Bundle({
  856. intro: this.intro,
  857. separator: this.separator
  858. });
  859. this.sources.forEach( function (source) {
  860. bundle.addSource({
  861. filename: source.filename,
  862. content: source.content.clone(),
  863. separator: source.separator
  864. });
  865. });
  866. return bundle;
  867. },
  868. generateMap: function generateMap ( options ) {
  869. var this$1 = this;
  870. if ( options === void 0 ) options = {};
  871. var names = [];
  872. this.sources.forEach( function (source) {
  873. Object.keys( source.content.storedNames ).forEach( function (name) {
  874. if ( !~names.indexOf( name ) ) { names.push( name ); }
  875. });
  876. });
  877. var mappings = new Mappings( options.hires );
  878. if ( this.intro ) {
  879. mappings.advance( this.intro );
  880. }
  881. this.sources.forEach( function ( source, i ) {
  882. if ( i > 0 ) {
  883. mappings.advance( this$1.separator );
  884. }
  885. var sourceIndex = source.filename ? this$1.uniqueSourceIndexByFilename[ source.filename ] : -1;
  886. var magicString = source.content;
  887. var locate = getLocator( magicString.original );
  888. if ( magicString.intro ) {
  889. mappings.advance( magicString.intro );
  890. }
  891. magicString.firstChunk.eachNext( function (chunk) {
  892. var loc = locate( chunk.start );
  893. if ( chunk.intro.length ) { mappings.advance( chunk.intro ); }
  894. if ( source.filename ) {
  895. if ( chunk.edited ) {
  896. mappings.addEdit( sourceIndex, chunk.content, chunk.original, loc, chunk.storeName ? names.indexOf( chunk.original ) : -1 );
  897. } else {
  898. mappings.addUneditedChunk( sourceIndex, chunk, magicString.original, loc, magicString.sourcemapLocations );
  899. }
  900. }
  901. else {
  902. mappings.advance( chunk.content );
  903. }
  904. if ( chunk.outro.length ) { mappings.advance( chunk.outro ); }
  905. });
  906. if ( magicString.outro ) {
  907. mappings.advance( magicString.outro );
  908. }
  909. });
  910. return new SourceMap({
  911. file: ( options.file ? options.file.split( /[\/\\]/ ).pop() : null ),
  912. sources: this.uniqueSources.map( function (source) {
  913. return options.file ? getRelativePath( options.file, source.filename ) : source.filename;
  914. }),
  915. sourcesContent: this.uniqueSources.map( function (source) {
  916. return options.includeContent ? source.content : null;
  917. }),
  918. names: names,
  919. mappings: mappings.encode()
  920. });
  921. },
  922. getIndentString: function getIndentString () {
  923. var indentStringCounts = {};
  924. this.sources.forEach( function (source) {
  925. var indentStr = source.content.indentStr;
  926. if ( indentStr === null ) { return; }
  927. if ( !indentStringCounts[ indentStr ] ) { indentStringCounts[ indentStr ] = 0; }
  928. indentStringCounts[ indentStr ] += 1;
  929. });
  930. return ( Object.keys( indentStringCounts ).sort( function ( a, b ) {
  931. return indentStringCounts[a] - indentStringCounts[b];
  932. })[0] ) || '\t';
  933. },
  934. indent: function indent ( indentStr ) {
  935. var this$1 = this;
  936. if ( !arguments.length ) {
  937. indentStr = this.getIndentString();
  938. }
  939. if ( indentStr === '' ) { return this; } // noop
  940. var trailingNewline = !this.intro || this.intro.slice( -1 ) === '\n';
  941. this.sources.forEach( function ( source, i ) {
  942. var separator = source.separator !== undefined ? source.separator : this$1.separator;
  943. var indentStart = trailingNewline || ( i > 0 && /\r?\n$/.test( separator ) );
  944. source.content.indent( indentStr, {
  945. exclude: source.indentExclusionRanges,
  946. indentStart: indentStart//: trailingNewline || /\r?\n$/.test( separator ) //true///\r?\n/.test( separator )
  947. });
  948. // TODO this is a very slow way to determine this
  949. trailingNewline = source.content.toString().slice( 0, -1 ) === '\n';
  950. });
  951. if ( this.intro ) {
  952. this.intro = indentStr + this.intro.replace( /^[^\n]/gm, function ( match, index ) {
  953. return index > 0 ? indentStr + match : match;
  954. });
  955. }
  956. return this;
  957. },
  958. prepend: function prepend ( str ) {
  959. this.intro = str + this.intro;
  960. return this;
  961. },
  962. toString: function toString () {
  963. var this$1 = this;
  964. var body = this.sources.map( function ( source, i ) {
  965. var separator = source.separator !== undefined ? source.separator : this$1.separator;
  966. var str = ( i > 0 ? separator : '' ) + source.content.toString();
  967. return str;
  968. }).join( '' );
  969. return this.intro + body;
  970. },
  971. trimLines: function trimLines () {
  972. return this.trim('[\\r\\n]');
  973. },
  974. trim: function trim ( charType ) {
  975. return this.trimStart( charType ).trimEnd( charType );
  976. },
  977. trimStart: function trimStart ( charType ) {
  978. var this$1 = this;
  979. var rx = new RegExp( '^' + ( charType || '\\s' ) + '+' );
  980. this.intro = this.intro.replace( rx, '' );
  981. if ( !this.intro ) {
  982. var source;
  983. var i = 0;
  984. do {
  985. source = this$1.sources[i];
  986. if ( !source ) {
  987. break;
  988. }
  989. source.content.trimStart( charType );
  990. i += 1;
  991. } while ( source.content.toString() === '' ); // TODO faster way to determine non-empty source?
  992. }
  993. return this;
  994. },
  995. trimEnd: function trimEnd ( charType ) {
  996. var this$1 = this;
  997. var rx = new RegExp( ( charType || '\\s' ) + '+$' );
  998. var source;
  999. var i = this.sources.length - 1;
  1000. do {
  1001. source = this$1.sources[i];
  1002. if ( !source ) {
  1003. this$1.intro = this$1.intro.replace( rx, '' );
  1004. break;
  1005. }
  1006. source.content.trimEnd( charType );
  1007. i -= 1;
  1008. } while ( source.content.toString() === '' ); // TODO faster way to determine non-empty source?
  1009. return this;
  1010. }
  1011. };
  1012. MagicString$1.Bundle = Bundle;
  1013. MagicString$1.default = MagicString$1; // work around TypeScript bug https://github.com/Rich-Harris/magic-string/pull/121
  1014. return MagicString$1;
  1015. })));
  1016. //# sourceMappingURL=magic-string.umd.js.map