版博士V2.0程序
Вы не можете выбрать более 25 тем Темы должны начинаться с буквы или цифры, могут содержать дефисы(-) и должны содержать не более 35 символов.
 
 
 
 

1592 строки
38 KiB

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