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