@openclaw/diffs 2026.5.25-beta.1 → 2026.5.26-beta.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -19,7 +19,7 @@ A full release may be completed by first updating the `"version"` property in pa
19
19
  ```
20
20
  yarn clean
21
21
  yarn build
22
- yarn publish
22
+ yarn npm publish
23
23
  ```
24
24
 
25
25
  After releasing, remember to:
@@ -368,7 +368,46 @@
368
368
  function hasOnlyUnixLineEndings(string) {
369
369
  return !string.includes('\r\n') && string.includes('\n');
370
370
  }
371
- function trailingWs(string) {
371
+ /**
372
+ * Split a string into segments using a word segmenter, merging consecutive
373
+ * segments if they are both whitespace segments. Whitespace segments can
374
+ * appear adjacent to one another for two reasons:
375
+ * - newlines always get their own segment
376
+ * - where a diacritic is attached to a whitespace character in the text, the
377
+ * segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
378
+ * This function therefore runs the segmenter's .segment() method and then
379
+ * merges consecutive segments of whitespace into a single part.
380
+ */
381
+ function segment(string, segmenter) {
382
+ const parts = [];
383
+ for (const segmentObj of Array.from(segmenter.segment(string))) {
384
+ const segment = segmentObj.segment;
385
+ if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment)) {
386
+ parts[parts.length - 1] += segment;
387
+ }
388
+ else {
389
+ parts.push(segment);
390
+ }
391
+ }
392
+ return parts;
393
+ }
394
+ // The functions below take a `segmenter` argument so that, when called from
395
+ // diffWords when it is using a segmenter, they can use a notion of what
396
+ // constitutes "whitespace" that is consistent with the segmenter.
397
+ //
398
+ // USUALLY this will be identical to the result of the non-segmenter-based
399
+ // logic, but it differs in at least one case: when whitespace characters are
400
+ // modified by diacritics. A word segmenter considers these diacritics to be
401
+ // part of the whitespace, whereas our non-segmenter-based logic does not.
402
+ //
403
+ // Because the segmenter-based approach necessarily requires segmenting the
404
+ // entire string, we offer a leadingAndTrailingWs function to allow getting the
405
+ // whitespace prefix AND whitespace suffix with a single call to the segmenter,
406
+ // for efficiency's sake.
407
+ function trailingWs(string, segmenter) {
408
+ if (segmenter) {
409
+ return leadingAndTrailingWs(string, segmenter)[1];
410
+ }
372
411
  // Yes, this looks overcomplicated and dumb - why not replace the whole function with
373
412
  // return string.match(/\s*$/)[0]
374
413
  // you ask? Because:
@@ -388,11 +427,28 @@
388
427
  }
389
428
  return string.substring(i + 1);
390
429
  }
391
- function leadingWs(string) {
430
+ function leadingWs(string, segmenter) {
431
+ if (segmenter) {
432
+ return leadingAndTrailingWs(string, segmenter)[0];
433
+ }
392
434
  // Thankfully the annoying considerations described in trailingWs don't apply here:
393
435
  const match = string.match(/^\s*/);
394
436
  return match ? match[0] : '';
395
437
  }
438
+ function leadingAndTrailingWs(string, segmenter) {
439
+ if (!segmenter) {
440
+ return [leadingWs(string), trailingWs(string)];
441
+ }
442
+ if (segmenter.resolvedOptions().granularity != 'word') {
443
+ throw new Error('The segmenter passed must have a granularity of "word"');
444
+ }
445
+ const segments = segment(string, segmenter);
446
+ const firstSeg = segments[0];
447
+ const lastSeg = segments[segments.length - 1];
448
+ const head = (/\s/).test(firstSeg) ? firstSeg : '';
449
+ const tail = (/\s/).test(lastSeg) ? lastSeg : '';
450
+ return [head, tail];
451
+ }
396
452
 
397
453
  // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode
398
454
  //
@@ -458,22 +514,9 @@
458
514
  // We want `parts` to be an array whose elements alternate between being
459
515
  // pure whitespace and being pure non-whitespace. This is ALMOST what the
460
516
  // segments returned by a word-based Intl.Segmenter already look like,
461
- // and therefore we can ALMOST get what we want by simply doing...
462
- // parts = Array.from(segmenter.segment(value), segment => segment.segment);
463
- // ... but not QUITE, because there's of one annoying special case: every
464
- // newline character gets its own segment, instead of sharing a segment
465
- // with other surrounding whitespace. We therefore need to manually merge
466
- // consecutive segments of whitespace into a single part:
467
- parts = [];
468
- for (const segmentObj of Array.from(segmenter.segment(value))) {
469
- const segment = segmentObj.segment;
470
- if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment)) {
471
- parts[parts.length - 1] += segment;
472
- }
473
- else {
474
- parts.push(segment);
475
- }
476
- }
517
+ // but not quite - see explanation in the docs of our custom segment()
518
+ // function.
519
+ parts = segment(value, segmenter);
477
520
  }
478
521
  else {
479
522
  parts = value.match(tokenizeIncludingWhitespace) || [];
@@ -537,7 +580,7 @@
537
580
  }
538
581
  else {
539
582
  if (insertion || deletion) { // May be false at start of text
540
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
583
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter);
541
584
  }
542
585
  lastKeep = change;
543
586
  insertion = null;
@@ -545,7 +588,7 @@
545
588
  }
546
589
  });
547
590
  if (insertion || deletion) {
548
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
591
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
549
592
  }
550
593
  return changes;
551
594
  }
@@ -561,7 +604,7 @@
561
604
  }
562
605
  return wordDiff.diff(oldStr, newStr, options);
563
606
  }
564
- function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
607
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
565
608
  // Before returning, we tidy up the leading and trailing whitespace of the
566
609
  // change objects to eliminate cases where trailing whitespace in one object
567
610
  // is repeated as leading whitespace in the next.
@@ -604,10 +647,8 @@
604
647
  // * Just a "delete"
605
648
  // We handle the three cases separately.
606
649
  if (deletion && insertion) {
607
- const oldWsPrefix = leadingWs(deletion.value);
608
- const oldWsSuffix = trailingWs(deletion.value);
609
- const newWsPrefix = leadingWs(insertion.value);
610
- const newWsSuffix = trailingWs(insertion.value);
650
+ const [oldWsPrefix, oldWsSuffix] = leadingAndTrailingWs(deletion.value, segmenter);
651
+ const [newWsPrefix, newWsSuffix] = leadingAndTrailingWs(insertion.value, segmenter);
611
652
  if (startKeep) {
612
653
  const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
613
654
  startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
@@ -629,17 +670,17 @@
629
670
  // whitespace and deleting duplicate leading whitespace where
630
671
  // present.
631
672
  if (startKeep) {
632
- const ws = leadingWs(insertion.value);
673
+ const ws = leadingWs(insertion.value, segmenter);
633
674
  insertion.value = insertion.value.substring(ws.length);
634
675
  }
635
676
  if (endKeep) {
636
- const ws = leadingWs(endKeep.value);
677
+ const ws = leadingWs(endKeep.value, segmenter);
637
678
  endKeep.value = endKeep.value.substring(ws.length);
638
679
  }
639
680
  // otherwise we've got a deletion and no insertion
640
681
  }
641
682
  else if (startKeep && endKeep) {
642
- const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);
683
+ const newWsFull = leadingWs(endKeep.value, segmenter), [delWsStart, delWsEnd] = leadingAndTrailingWs(deletion.value, segmenter);
643
684
  // Any whitespace that comes straight after startKeep in both the old and
644
685
  // new texts, assign to startKeep and remove from the deletion.
645
686
  const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
@@ -658,8 +699,8 @@
658
699
  // We are at the start of the text. Preserve all the whitespace on
659
700
  // endKeep, and just remove whitespace from the end of deletion to the
660
701
  // extent that it overlaps with the start of endKeep.
661
- const endKeepWsPrefix = leadingWs(endKeep.value);
662
- const deletionWsSuffix = trailingWs(deletion.value);
702
+ const endKeepWsPrefix = leadingWs(endKeep.value, segmenter);
703
+ const deletionWsSuffix = trailingWs(deletion.value, segmenter);
663
704
  const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
664
705
  deletion.value = removeSuffix(deletion.value, overlap);
665
706
  }
@@ -667,8 +708,8 @@
667
708
  // We are at the END of the text. Preserve all the whitespace on
668
709
  // startKeep, and just remove whitespace from the start of deletion to
669
710
  // the extent that it overlaps with the end of startKeep.
670
- const startKeepWsSuffix = trailingWs(startKeep.value);
671
- const deletionWsPrefix = leadingWs(deletion.value);
711
+ const startKeepWsSuffix = trailingWs(startKeep.value, segmenter);
712
+ const deletionWsPrefix = leadingWs(deletion.value, segmenter);
672
713
  const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
673
714
  deletion.value = removePrefix(deletion.value, overlap);
674
715
  }
@@ -1 +1 @@
1
- ((global,factory)=>{"object"==typeof exports&&"undefined"!=typeof module?factory(exports):"function"==typeof define&&define.amd?define(["exports"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).Diff={})})(this,function(exports){class Diff{diff(oldStr,newStr,options={}){let callback;"function"==typeof options?(callback=options,options={}):"callback"in options&&(callback=options.callback);oldStr=this.castInput(oldStr,options),newStr=this.castInput(newStr,options),oldStr=this.removeEmpty(this.tokenize(oldStr,options)),newStr=this.removeEmpty(this.tokenize(newStr,options));return this.diffWithOptionsObj(oldStr,newStr,options,callback)}diffWithOptionsObj(oldTokens,newTokens,options,callback){let _a,done=value=>{if(value=this.postProcess(value,options),!callback)return value;setTimeout(function(){callback(value)},0)},newLen=newTokens.length,oldLen=oldTokens.length,editLength=1,maxEditLength=newLen+oldLen;null!=options.maxEditLength&&(maxEditLength=Math.min(maxEditLength,options.maxEditLength));var maxExecutionTime=null!=(_a=options.timeout)?_a:1/0;let abortAfterTimestamp=Date.now()+maxExecutionTime,bestPath=[{oldPos:-1,lastComponent:void 0}],newPos=this.extractCommon(bestPath[0],newTokens,oldTokens,0,options);if(bestPath[0].oldPos+1>=oldLen&&newPos+1>=newLen)return done(this.buildValues(bestPath[0].lastComponent,newTokens,oldTokens));let minDiagonalToConsider=-1/0,maxDiagonalToConsider=1/0,execEditLength=()=>{for(let diagonalPath=Math.max(minDiagonalToConsider,-editLength);diagonalPath<=Math.min(maxDiagonalToConsider,editLength);diagonalPath+=2){let basePath;var removePath=bestPath[diagonalPath-1],addPath=bestPath[diagonalPath+1];removePath&&(bestPath[diagonalPath-1]=void 0);let canAdd=!1;addPath&&(addPathNewPos=addPath.oldPos-diagonalPath,canAdd=addPath&&0<=addPathNewPos&&addPathNewPos<newLen);var addPathNewPos=removePath&&removePath.oldPos+1<oldLen;if(canAdd||addPathNewPos){if(basePath=!addPathNewPos||canAdd&&removePath.oldPos<addPath.oldPos?this.addToPath(addPath,!0,!1,0,options):this.addToPath(removePath,!1,!0,1,options),newPos=this.extractCommon(basePath,newTokens,oldTokens,diagonalPath,options),basePath.oldPos+1>=oldLen&&newPos+1>=newLen)return done(this.buildValues(basePath.lastComponent,newTokens,oldTokens))||!0;(bestPath[diagonalPath]=basePath).oldPos+1>=oldLen&&(maxDiagonalToConsider=Math.min(maxDiagonalToConsider,diagonalPath-1)),newPos+1>=newLen&&(minDiagonalToConsider=Math.max(minDiagonalToConsider,diagonalPath+1))}else bestPath[diagonalPath]=void 0}editLength++};if(callback)!function exec(){setTimeout(function(){if(editLength>maxEditLength||Date.now()>abortAfterTimestamp)return callback(void 0);execEditLength()||exec()},0)}();else for(;editLength<=maxEditLength&&Date.now()<=abortAfterTimestamp;){var ret=execEditLength();if(ret)return ret}}addToPath(path,added,removed,oldPosInc,options){var last=path.lastComponent;return last&&!options.oneChangePerToken&&last.added===added&&last.removed===removed?{oldPos:path.oldPos+oldPosInc,lastComponent:{count:last.count+1,added:added,removed:removed,previousComponent:last.previousComponent}}:{oldPos:path.oldPos+oldPosInc,lastComponent:{count:1,added:added,removed:removed,previousComponent:last}}}extractCommon(basePath,newTokens,oldTokens,diagonalPath,options){var newLen=newTokens.length,oldLen=oldTokens.length;let oldPos=basePath.oldPos,newPos=oldPos-diagonalPath,commonCount=0;for(;newPos+1<newLen&&oldPos+1<oldLen&&this.equals(oldTokens[oldPos+1],newTokens[newPos+1],options);)newPos++,oldPos++,commonCount++,options.oneChangePerToken&&(basePath.lastComponent={count:1,previousComponent:basePath.lastComponent,added:!1,removed:!1});return commonCount&&!options.oneChangePerToken&&(basePath.lastComponent={count:commonCount,previousComponent:basePath.lastComponent,added:!1,removed:!1}),basePath.oldPos=oldPos,newPos}equals(left,right,options){return options.comparator?options.comparator(left,right):left===right||!!options.ignoreCase&&left.toLowerCase()===right.toLowerCase()}removeEmpty(array){var ret=[];for(let i=0;i<array.length;i++)array[i]&&ret.push(array[i]);return ret}castInput(value,options){return value}tokenize(value,options){return Array.from(value)}join(chars){return chars.join("")}postProcess(changeObjects,options){return changeObjects}get useLongestToken(){return!1}buildValues(lastComponent,newTokens,oldTokens){for(var nextComponent,components=[];lastComponent;)components.push(lastComponent),nextComponent=lastComponent.previousComponent,delete lastComponent.previousComponent,lastComponent=nextComponent;components.reverse();var componentLen=components.length;let componentPos=0,newPos=0,oldPos=0;for(;componentPos<componentLen;componentPos++){var component=components[componentPos];if(component.removed)component.value=this.join(oldTokens.slice(oldPos,oldPos+component.count)),oldPos+=component.count;else{if(!component.added&&this.useLongestToken){let value=newTokens.slice(newPos,newPos+component.count);value=value.map(function(value,i){i=oldTokens[oldPos+i];return i.length>value.length?i:value}),component.value=this.join(value)}else component.value=this.join(newTokens.slice(newPos,newPos+component.count));newPos+=component.count,component.added||(oldPos+=component.count)}}return components}}class CharacterDiff extends Diff{}let characterDiff=new CharacterDiff;function longestCommonPrefix(str1,str2){let i;for(i=0;i<str1.length&&i<str2.length;i++)if(str1[i]!=str2[i])return str1.slice(0,i);return str1.slice(0,i)}function longestCommonSuffix(str1,str2){let i;if(!str1||!str2||str1[str1.length-1]!=str2[str2.length-1])return"";for(i=0;i<str1.length&&i<str2.length;i++)if(str1[str1.length-(i+1)]!=str2[str2.length-(i+1)])return str1.slice(-i);return str1.slice(-i)}function replacePrefix(string,oldPrefix,newPrefix){if(string.slice(0,oldPrefix.length)!=oldPrefix)throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);return newPrefix+string.slice(oldPrefix.length)}function replaceSuffix(string,oldSuffix,newSuffix){if(!oldSuffix)return string+newSuffix;if(string.slice(-oldSuffix.length)!=oldSuffix)throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);return string.slice(0,-oldSuffix.length)+newSuffix}function removePrefix(string,oldPrefix){return replacePrefix(string,oldPrefix,"")}function removeSuffix(string,oldSuffix){return replaceSuffix(string,oldSuffix,"")}function maximumOverlap(string1,string2){return string2.slice(0,((a,b)=>{let startA=0,endB=(a.length>b.length&&(startA=a.length-b.length),b.length),map=(a.length<b.length&&(endB=a.length),Array(endB)),k=0;map[0]=0;for(let j=1;j<endB;j++){for(b[j]==b[k]?map[j]=map[k]:map[j]=k;0<k&&b[j]!=b[k];)k=map[k];b[j]==b[k]&&k++}k=0;for(let i=startA;i<a.length;i++){for(;0<k&&a[i]!=b[k];)k=map[k];a[i]==b[k]&&k++}return k})(string1,string2))}function trailingWs(string){let i;for(i=string.length-1;0<=i&&string[i].match(/\s/);i--);return string.substring(i+1)}function leadingWs(string){string=string.match(/^\s*/);return string?string[0]:""}let extendedWordChars="a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}",tokenizeIncludingWhitespace=new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`,"ug");class WordDiff extends Diff{equals(left,right,options){return options.ignoreCase&&(left=left.toLowerCase(),right=right.toLowerCase()),left.trim()===right.trim()}tokenize(value,options={}){let parts;if(options.intlSegmenter){var segmentObj,options=options.intlSegmenter;if("word"!=options.resolvedOptions().granularity)throw new Error('The segmenter passed must have a granularity of "word"');parts=[];for(segmentObj of Array.from(options.segment(value))){var segment=segmentObj.segment;parts.length&&/\s/.test(parts[parts.length-1])&&/\s/.test(segment)?parts[parts.length-1]+=segment:parts.push(segment)}}else parts=value.match(tokenizeIncludingWhitespace)||[];let tokens=[],prevPart=null;return parts.forEach(part=>{/\s/.test(part)?null==prevPart?tokens.push(part):tokens.push(tokens.pop()+part):null!=prevPart&&/\s/.test(prevPart)?tokens[tokens.length-1]==prevPart?tokens.push(tokens.pop()+part):tokens.push(prevPart+part):tokens.push(part),prevPart=part}),tokens}join(tokens){return tokens.map((token,i)=>0==i?token:token.replace(/^\s+/,"")).join("")}postProcess(changes,options){if(changes&&!options.oneChangePerToken){let lastKeep=null,insertion=null,deletion=null;changes.forEach(change=>{change.added?insertion=change:deletion=change.removed?change:((insertion||deletion)&&dedupeWhitespaceInChangeObjects(lastKeep,deletion,insertion,change),lastKeep=change,insertion=null)}),(insertion||deletion)&&dedupeWhitespaceInChangeObjects(lastKeep,deletion,insertion,null)}return changes}}let wordDiff=new WordDiff;function dedupeWhitespaceInChangeObjects(startKeep,deletion,insertion,endKeep){if(deletion&&insertion){var oldWsPrefix=leadingWs(deletion.value),oldWsSuffix=trailingWs(deletion.value),newWsPrefix=leadingWs(insertion.value),newWsSuffix=trailingWs(insertion.value);startKeep&&(oldWsPrefix=longestCommonPrefix(oldWsPrefix,newWsPrefix),startKeep.value=replaceSuffix(startKeep.value,newWsPrefix,oldWsPrefix),deletion.value=removePrefix(deletion.value,oldWsPrefix),insertion.value=removePrefix(insertion.value,oldWsPrefix)),endKeep&&(newWsPrefix=longestCommonSuffix(oldWsSuffix,newWsSuffix),endKeep.value=replacePrefix(endKeep.value,newWsSuffix,newWsPrefix),deletion.value=removeSuffix(deletion.value,newWsPrefix),insertion.value=removeSuffix(insertion.value,newWsPrefix))}else if(insertion){if(startKeep&&(oldWsPrefix=leadingWs(insertion.value),insertion.value=insertion.value.substring(oldWsPrefix.length)),endKeep){let ws=leadingWs(endKeep.value);endKeep.value=endKeep.value.substring(ws.length)}}else if(startKeep&&endKeep){oldWsSuffix=leadingWs(endKeep.value),newWsSuffix=leadingWs(deletion.value),newWsPrefix=trailingWs(deletion.value),insertion=longestCommonPrefix(oldWsSuffix,newWsSuffix),oldWsPrefix=(deletion.value=removePrefix(deletion.value,insertion),longestCommonSuffix(removePrefix(oldWsSuffix,insertion),newWsPrefix));deletion.value=removeSuffix(deletion.value,oldWsPrefix),endKeep.value=replacePrefix(endKeep.value,oldWsSuffix,oldWsPrefix),startKeep.value=replaceSuffix(startKeep.value,oldWsSuffix,oldWsSuffix.slice(0,oldWsSuffix.length-oldWsPrefix.length))}else if(endKeep){newWsSuffix=leadingWs(endKeep.value),insertion=maximumOverlap(trailingWs(deletion.value),newWsSuffix);deletion.value=removeSuffix(deletion.value,insertion)}else if(startKeep){let overlap=maximumOverlap(trailingWs(startKeep.value),leadingWs(deletion.value));deletion.value=removePrefix(deletion.value,overlap)}}class WordsWithSpaceDiff extends Diff{tokenize(value){var regex=new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`,"ug");return value.match(regex)||[]}}let wordsWithSpaceDiff=new WordsWithSpaceDiff;function diffWordsWithSpace(oldStr,newStr,options){return wordsWithSpaceDiff.diff(oldStr,newStr,options)}class LineDiff extends Diff{constructor(){super(...arguments),this.tokenize=tokenize}equals(left,right,options){return options.ignoreWhitespace?(options.newlineIsToken&&left.includes("\n")||(left=left.trim()),options.newlineIsToken&&right.includes("\n")||(right=right.trim())):options.ignoreNewlineAtEof&&!options.newlineIsToken&&(left.endsWith("\n")&&(left=left.slice(0,-1)),right.endsWith("\n"))&&(right=right.slice(0,-1)),super.equals(left,right,options)}}let lineDiff=new LineDiff;function diffLines(oldStr,newStr,options){return lineDiff.diff(oldStr,newStr,options)}function tokenize(value,options){var retLines=[],linesAndNewlines=(value=options.stripTrailingCr?value.replace(/\r\n/g,"\n"):value).split(/(\n|\r\n)/);linesAndNewlines[linesAndNewlines.length-1]||linesAndNewlines.pop();for(let i=0;i<linesAndNewlines.length;i++){var line=linesAndNewlines[i];i%2&&!options.newlineIsToken?retLines[retLines.length-1]+=line:retLines.push(line)}return retLines}class SentenceDiff extends Diff{tokenize(value){var _a,char,result=[];let tokenStartI=0;for(let i=0;i<value.length;i++){if(i==value.length-1){result.push(value.slice(tokenStartI));break}if(("."==(char=value[i])||"!"==char||"?"==char)&&value[i+1].match(/\s/)){for(result.push(value.slice(tokenStartI,i+1)),i=tokenStartI=i+1;null!=(_a=value[i+1])&&_a.match(/\s/);)i++;result.push(value.slice(tokenStartI,i+1)),tokenStartI=i+1}}return result}}let sentenceDiff=new SentenceDiff;class CssDiff extends Diff{tokenize(value){return value.split(/([{}:;,]|\s+)/)}}let cssDiff=new CssDiff;class JsonDiff extends Diff{constructor(){super(...arguments),this.tokenize=tokenize}get useLongestToken(){return!0}castInput(value,options){let{undefinedReplacement,stringifyReplacer=(k,v)=>void 0===v?undefinedReplacement:v}=options;return"string"==typeof value?value:JSON.stringify(canonicalize(value,null,null,stringifyReplacer),null," ")}equals(left,right,options){return super.equals(left.replace(/,([\r\n])/g,"$1"),right.replace(/,([\r\n])/g,"$1"),options)}}let jsonDiff=new JsonDiff;function canonicalize(obj,stack,replacementStack,replacer,key){stack=stack||[],replacementStack=replacementStack||[],replacer&&(obj=replacer(void 0===key?"":key,obj));let i;for(i=0;i<stack.length;i+=1)if(stack[i]===obj)return replacementStack[i];let canonicalizedObj;if("[object Array]"===Object.prototype.toString.call(obj)){for(stack.push(obj),canonicalizedObj=new Array(obj.length),replacementStack.push(canonicalizedObj),i=0;i<obj.length;i+=1)canonicalizedObj[i]=canonicalize(obj[i],stack,replacementStack,replacer,String(i));stack.pop(),replacementStack.pop()}else if("object"==typeof(obj=obj&&obj.toJSON?obj.toJSON():obj)&&null!==obj){stack.push(obj),canonicalizedObj={},replacementStack.push(canonicalizedObj);var sortedKeys=[];let key;for(key in obj)Object.prototype.hasOwnProperty.call(obj,key)&&sortedKeys.push(key);for(sortedKeys.sort(),i=0;i<sortedKeys.length;i+=1)key=sortedKeys[i],canonicalizedObj[key]=canonicalize(obj[key],stack,replacementStack,replacer,key);stack.pop(),replacementStack.pop()}else canonicalizedObj=obj;return canonicalizedObj}class ArrayDiff extends Diff{tokenize(value){return value.slice()}join(value){return value}removeEmpty(value){return value}}let arrayDiff=new ArrayDiff;function parsePatch(uniDiff){let diffstr=uniDiff.split(/\n/),list=[],i=0;function parseIndex(){var index={};for(list.push(index);i<diffstr.length;){var line=diffstr[i];if(/^(---|\+\+\+|@@)\s/.test(line))break;var headerMatch=/^(?:Index:|diff(?: -r \w+)+)\s+/.exec(line);headerMatch&&(index.index=line.substring(headerMatch[0].length).trim()),i++}for(parseFileHeader(index),parseFileHeader(index),index.hunks=[];i<diffstr.length;){let line=diffstr[i];if(/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line))break;if(/^@@/.test(line))index.hunks.push((()=>{var chunkHeaderIndex=i,chunkHeaderLine=diffstr[i++],hunk={oldStart:+(chunkHeaderLine=chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/))[1],oldLines:void 0===chunkHeaderLine[2]?1:+chunkHeaderLine[2],newStart:+chunkHeaderLine[3],newLines:void 0===chunkHeaderLine[4]?1:+chunkHeaderLine[4],lines:[]};0===hunk.oldLines&&(hunk.oldStart+=1),0===hunk.newLines&&(hunk.newStart+=1);let addCount=0,removeCount=0;for(;i<diffstr.length&&(removeCount<hunk.oldLines||addCount<hunk.newLines||null!=(_a=diffstr[i])&&_a.startsWith("\\"));i++){var _a=0==diffstr[i].length&&i!=diffstr.length-1?" ":diffstr[i][0];if("+"!==_a&&"-"!==_a&&" "!==_a&&"\\"!==_a)throw new Error(`Hunk at line ${chunkHeaderIndex+1} contained invalid line `+diffstr[i]);hunk.lines.push(diffstr[i]),"+"===_a?addCount++:"-"===_a?removeCount++:" "===_a&&(addCount++,removeCount++)}if(addCount||1!==hunk.newLines||(hunk.newLines=0),removeCount||1!==hunk.oldLines||(hunk.oldLines=0),addCount!==hunk.newLines)throw new Error("Added line count did not match for hunk at line "+(chunkHeaderIndex+1));if(removeCount===hunk.oldLines)return hunk;throw new Error("Removed line count did not match for hunk at line "+(chunkHeaderIndex+1))})());else{if(line)throw new Error("Unknown line "+(i+1)+" "+JSON.stringify(line));i++}}}function parseFileHeader(index){var fileHeaderMatch=/^(---|\+\+\+)\s+/.exec(diffstr[i]);if(fileHeaderMatch){var fileHeaderMatch=fileHeaderMatch[1],data=diffstr[i].substring(3).trim().split("\t",2),header=(data[1]||"").trim();let fileName=data[0].replace(/\\\\/g,"\\");fileName.startsWith('"')&&fileName.endsWith('"')&&(fileName=fileName.substr(1,fileName.length-2)),"---"===fileHeaderMatch?(index.oldFileName=fileName,index.oldHeader=header):(index.newFileName=fileName,index.newHeader=header),i++}}for(;i<diffstr.length;)parseIndex();return list}function applyPatch(source,patch,options={}){let patches;if(1<(patches="string"==typeof patch?parsePatch(patch):Array.isArray(patch)?patch:[patch]).length)throw new Error("applyPatch only works with a single input.");return((source,patch,options={})=>{!options.autoConvertLineEndings&&null!=options.autoConvertLineEndings||((string=>string.includes("\r\n")&&!string.startsWith("\n")&&!string.match(/[^\r]\n/))(source)&&(patch=>!(patch=Array.isArray(patch)?patch:[patch]).some(index=>index.hunks.some(hunk=>hunk.lines.some(line=>!line.startsWith("\\")&&line.endsWith("\r")))))(patch)?patch=function unixToWin(patch){return Array.isArray(patch)?patch.map(p=>unixToWin(p)):Object.assign(Object.assign({},patch),{hunks:patch.hunks.map(hunk=>Object.assign(Object.assign({},hunk),{lines:hunk.lines.map((line,i)=>line.startsWith("\\")||line.endsWith("\r")||null!=(i=hunk.lines[i+1])&&i.startsWith("\\")?line:line+"\r")}))})}(patch):(string=>!string.includes("\r\n")&&string.includes("\n"))(source)&&(patch=>(patch=Array.isArray(patch)?patch:[patch]).some(index=>index.hunks.some(hunk=>hunk.lines.some(line=>line.endsWith("\r"))))&&patch.every(index=>index.hunks.every(hunk=>hunk.lines.every((line,i)=>line.startsWith("\\")||line.endsWith("\r")||(null==(line=hunk.lines[i+1])?void 0:line.startsWith("\\"))))))(patch)&&(patch=function winToUnix(patch){return Array.isArray(patch)?patch.map(p=>winToUnix(p)):Object.assign(Object.assign({},patch),{hunks:patch.hunks.map(hunk=>Object.assign(Object.assign({},hunk),{lines:hunk.lines.map(line=>line.endsWith("\r")?line.substring(0,line.length-1):line)}))})}(patch)));let lines=source.split("\n"),hunks=patch.hunks,compareLine=options.compareLine||((lineNumber,line,operation,patchContent)=>line===patchContent),fuzzFactor=options.fuzzFactor||0,minLine=0;if(fuzzFactor<0||!Number.isInteger(fuzzFactor))throw new Error("fuzzFactor must be a non-negative integer");if(!hunks.length)return source;let prevLine="",removeEOFNL=!1,addEOFNL=!1;for(let i=0;i<hunks[hunks.length-1].lines.length;i++){var line=hunks[hunks.length-1].lines[i];"\\"==line[0]&&("+"==prevLine[0]?removeEOFNL=!0:"-"==prevLine[0]&&(addEOFNL=!0)),prevLine=line}if(removeEOFNL){if(addEOFNL){if(!fuzzFactor&&""==lines[lines.length-1])return!1}else if(""==lines[lines.length-1])lines.pop();else if(!fuzzFactor)return!1}else if(addEOFNL)if(""!=lines[lines.length-1])lines.push("");else if(!fuzzFactor)return!1;let resultLines=[],prevHunkOffset=0;for(let i=0;i<hunks.length;i++){var hunk=hunks[i];let hunkResult;var maxLine=lines.length-hunk.oldLines+fuzzFactor;let toPos;for(let maxErrors=0;maxErrors<=fuzzFactor;maxErrors++){for(var iterator=((start,minLine,maxLine)=>{let wantForward=!0,backwardExhausted=!1,forwardExhausted=!1,localOffset=1;return function iterator(){if(wantForward&&!forwardExhausted){if(backwardExhausted?localOffset++:wantForward=!1,start+localOffset<=maxLine)return start+localOffset;forwardExhausted=!0}if(!backwardExhausted)return forwardExhausted||(wantForward=!0),minLine<=start-localOffset?start-localOffset++:(backwardExhausted=!0,iterator())}})(toPos=hunk.oldStart+prevHunkOffset-1,minLine,maxLine);void 0!==toPos&&!(hunkResult=function applyHunk(hunkLines,toPos,maxErrors,hunkLinesI=0,lastContextLineMatched=!0,patchedLines=[],patchedLinesLength=0){let nConsecutiveOldContextLines=0,nextContextLineMustMatch=!1;for(;hunkLinesI<hunkLines.length;hunkLinesI++){var operation=0<(hunkLine=hunkLines[hunkLinesI]).length?hunkLine[0]:" ",hunkLine=0<hunkLine.length?hunkLine.substr(1):hunkLine;if("-"===operation){if(!compareLine(toPos+1,lines[toPos],operation,hunkLine))return maxErrors&&null!=lines[toPos]?(patchedLines[patchedLinesLength]=lines[toPos],applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI,!1,patchedLines,patchedLinesLength+1)):null;toPos++,nConsecutiveOldContextLines=0}if("+"===operation){if(!lastContextLineMatched)return null;patchedLines[patchedLinesLength]=hunkLine,patchedLinesLength++,nConsecutiveOldContextLines=0,nextContextLineMustMatch=!0}if(" "===operation){if(nConsecutiveOldContextLines++,patchedLines[patchedLinesLength]=lines[toPos],!compareLine(toPos+1,lines[toPos],operation,hunkLine))return nextContextLineMustMatch||!maxErrors?null:lines[toPos]&&(applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI+1,!1,patchedLines,patchedLinesLength+1)||applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI,!1,patchedLines,patchedLinesLength+1))||applyHunk(hunkLines,toPos,maxErrors-1,hunkLinesI+1,!1,patchedLines,patchedLinesLength);patchedLinesLength++,lastContextLineMatched=!0,nextContextLineMustMatch=!1,toPos++}}return patchedLinesLength-=nConsecutiveOldContextLines,toPos-=nConsecutiveOldContextLines,patchedLines.length=patchedLinesLength,{patchedLines:patchedLines,oldLineLastI:toPos-1}}(hunk.lines,toPos,maxErrors));toPos=iterator());if(hunkResult)break}if(!hunkResult)return!1;for(let i=minLine;i<toPos;i++)resultLines.push(lines[i]);for(let i=0;i<hunkResult.patchedLines.length;i++){var line=hunkResult.patchedLines[i];resultLines.push(line)}minLine=hunkResult.oldLineLastI+1,prevHunkOffset=toPos+1-hunk.oldStart}for(let i=minLine;i<lines.length;i++)resultLines.push(lines[i]);return resultLines.join("\n")})(source,patches[0],options)}let INCLUDE_HEADERS={includeIndex:!0,includeUnderline:!0,includeFileHeaders:!0};function structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options){let optionsObj,context=(void 0===(optionsObj=options?"function"==typeof options?{callback:options}:options:{}).context&&(optionsObj.context=4),optionsObj.context);if(optionsObj.newlineIsToken)throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");if(!optionsObj.callback)return diffLinesResultToPatch(diffLines(oldStr,newStr,optionsObj));{let callback=optionsObj.callback;diffLines(oldStr,newStr,Object.assign(Object.assign({},optionsObj),{callback:diff=>{diff=diffLinesResultToPatch(diff);callback(diff)}}))}function diffLinesResultToPatch(diff){if(diff){diff.push({value:"",lines:[]});var hunks=[];let oldRangeStart=0,newRangeStart=0,curRange=[],oldLine=1,newLine=1;for(let i=0;i<diff.length;i++){var line,current=diff[i],lines=current.lines||(text=>{var hasTrailingNl=text.endsWith("\n"),text=text.split("\n").map(line=>line+"\n");return hasTrailingNl?text.pop():text.push(text.pop().slice(0,-1)),text})(current.value);if(current.lines=lines,current.added||current.removed){oldRangeStart||(prev=diff[i-1],oldRangeStart=oldLine,newRangeStart=newLine,prev&&(curRange=0<context?contextLines(prev.lines.slice(-context)):[],oldRangeStart-=curRange.length,newRangeStart-=curRange.length));for(line of lines)curRange.push((current.added?"+":"-")+line);current.added?newLine+=lines.length:oldLine+=lines.length}else{if(oldRangeStart)if(lines.length<=2*context&&i<diff.length-2)for(let line of contextLines(lines))curRange.push(line);else{var prev=Math.min(lines.length,context);for(let line of contextLines(lines.slice(0,prev)))curRange.push(line);var hunk={oldStart:oldRangeStart,oldLines:oldLine-oldRangeStart+prev,newStart:newRangeStart,newLines:newLine-newRangeStart+prev,lines:curRange};hunks.push(hunk),oldRangeStart=0,newRangeStart=0,curRange=[]}oldLine+=lines.length,newLine+=lines.length}}for(let hunk of hunks)for(let i=0;i<hunk.lines.length;i++)hunk.lines[i].endsWith("\n")?hunk.lines[i]=hunk.lines[i].slice(0,-1):(hunk.lines.splice(i+1,0,"\"),i++);return{oldFileName:oldFileName,newFileName:newFileName,oldHeader:oldHeader,newHeader:newHeader,hunks:hunks};function contextLines(lines){return lines.map(function(entry){return" "+entry})}}}}function formatPatch(patch,headerOptions){if(headerOptions=headerOptions||INCLUDE_HEADERS,Array.isArray(patch)){if(1<patch.length&&!headerOptions.includeFileHeaders)throw new Error("Cannot omit file headers on a multi-file patch. (The result would be unparseable; how would a tool trying to apply the patch know which changes are to which file?)");return patch.map(p=>formatPatch(p,headerOptions)).join("\n")}var ret=[];headerOptions.includeIndex&&patch.oldFileName==patch.newFileName&&ret.push("Index: "+patch.oldFileName),headerOptions.includeUnderline&&ret.push("==================================================================="),headerOptions.includeFileHeaders&&(ret.push("--- "+patch.oldFileName+(void 0===patch.oldHeader?"":"\t"+patch.oldHeader)),ret.push("+++ "+patch.newFileName+(void 0===patch.newHeader?"":"\t"+patch.newHeader)));for(let i=0;i<patch.hunks.length;i++){var line,hunk=patch.hunks[i];0===hunk.oldLines&&--hunk.oldStart,0===hunk.newLines&&--hunk.newStart,ret.push("@@ -"+hunk.oldStart+","+hunk.oldLines+" +"+hunk.newStart+","+hunk.newLines+" @@");for(line of hunk.lines)ret.push(line)}return ret.join("\n")+"\n"}function createTwoFilesPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options){if(null!=(options="function"==typeof options?{callback:options}:options)&&options.callback){let callback=options.callback;structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,Object.assign(Object.assign({},options),{callback:patchObj=>{patchObj?callback(formatPatch(patchObj,options.headerOptions)):callback(void 0)}}))}else{oldFileName=structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options);if(oldFileName)return formatPatch(oldFileName,null==options?void 0:options.headerOptions)}}exports.Diff=Diff,exports.FILE_HEADERS_ONLY={includeIndex:!1,includeUnderline:!1,includeFileHeaders:!0},exports.INCLUDE_HEADERS=INCLUDE_HEADERS,exports.OMIT_HEADERS={includeIndex:!1,includeUnderline:!1,includeFileHeaders:!1},exports.applyPatch=applyPatch,exports.applyPatches=function(uniDiff,options){let spDiff="string"==typeof uniDiff?parsePatch(uniDiff):uniDiff,currentIndex=0;!function processIndex(){let index=spDiff[currentIndex++];if(!index)return options.complete();options.loadFile(index,function(err,data){if(err)return options.complete(err);err=applyPatch(data,index,options),options.patched(index,err,function(err){if(err)return options.complete(err);processIndex()})})}()},exports.arrayDiff=arrayDiff,exports.canonicalize=canonicalize,exports.characterDiff=characterDiff,exports.convertChangesToDMP=function(changes){var ret=[];let change,operation;for(let i=0;i<changes.length;i++)change=changes[i],operation=change.added?1:change.removed?-1:0,ret.push([operation,change.value]);return ret},exports.convertChangesToXML=function(changes){var ret=[];for(let i=0;i<changes.length;i++){var change=changes[i];change.added?ret.push("<ins>"):change.removed&&ret.push("<del>"),ret.push((s=>{let n=s;return n=(n=(n=(n=n.replace(/&/g,"&amp;")).replace(/</g,"&lt;")).replace(/>/g,"&gt;")).replace(/"/g,"&quot;")})(change.value)),change.added?ret.push("</ins>"):change.removed&&ret.push("</del>")}return ret.join("")},exports.createPatch=function(fileName,oldStr,newStr,oldHeader,newHeader,options){return createTwoFilesPatch(fileName,fileName,oldStr,newStr,oldHeader,newHeader,options)},exports.createTwoFilesPatch=createTwoFilesPatch,exports.cssDiff=cssDiff,exports.diffArrays=function(oldArr,newArr,options){return arrayDiff.diff(oldArr,newArr,options)},exports.diffChars=function(oldStr,newStr,options){return characterDiff.diff(oldStr,newStr,options)},exports.diffCss=function(oldStr,newStr,options){return cssDiff.diff(oldStr,newStr,options)},exports.diffJson=function(oldStr,newStr,options){return jsonDiff.diff(oldStr,newStr,options)},exports.diffLines=diffLines,exports.diffSentences=function(oldStr,newStr,options){return sentenceDiff.diff(oldStr,newStr,options)},exports.diffTrimmedLines=function(oldStr,newStr,options){return options=((options,defaults)=>{if("function"==typeof options)defaults.callback=options;else if(options)for(var name in options)Object.prototype.hasOwnProperty.call(options,name)&&(defaults[name]=options[name]);return defaults})(options,{ignoreWhitespace:!0}),lineDiff.diff(oldStr,newStr,options)},exports.diffWords=function(oldStr,newStr,options){return null==(null==options?void 0:options.ignoreWhitespace)||options.ignoreWhitespace?wordDiff.diff(oldStr,newStr,options):diffWordsWithSpace(oldStr,newStr,options)},exports.diffWordsWithSpace=diffWordsWithSpace,exports.formatPatch=formatPatch,exports.jsonDiff=jsonDiff,exports.lineDiff=lineDiff,exports.parsePatch=parsePatch,exports.reversePatch=function reversePatch(structuredPatch){return Array.isArray(structuredPatch)?structuredPatch.map(patch=>reversePatch(patch)).reverse():Object.assign(Object.assign({},structuredPatch),{oldFileName:structuredPatch.newFileName,oldHeader:structuredPatch.newHeader,newFileName:structuredPatch.oldFileName,newHeader:structuredPatch.oldHeader,hunks:structuredPatch.hunks.map(hunk=>({oldLines:hunk.newLines,oldStart:hunk.newStart,newLines:hunk.oldLines,newStart:hunk.oldStart,lines:hunk.lines.map(l=>l.startsWith("-")?"+"+l.slice(1):l.startsWith("+")?"-"+l.slice(1):l)}))})},exports.sentenceDiff=sentenceDiff,exports.structuredPatch=structuredPatch,exports.wordDiff=wordDiff,exports.wordsWithSpaceDiff=wordsWithSpaceDiff});
1
+ ((global,factory)=>{"object"==typeof exports&&"undefined"!=typeof module?factory(exports):"function"==typeof define&&define.amd?define(["exports"],factory):factory((global="undefined"!=typeof globalThis?globalThis:global||self).Diff={})})(this,function(exports){class Diff{diff(oldStr,newStr,options={}){let callback;"function"==typeof options?(callback=options,options={}):"callback"in options&&(callback=options.callback);oldStr=this.castInput(oldStr,options),newStr=this.castInput(newStr,options),oldStr=this.removeEmpty(this.tokenize(oldStr,options)),newStr=this.removeEmpty(this.tokenize(newStr,options));return this.diffWithOptionsObj(oldStr,newStr,options,callback)}diffWithOptionsObj(oldTokens,newTokens,options,callback){let _a,done=value=>{if(value=this.postProcess(value,options),!callback)return value;setTimeout(function(){callback(value)},0)},newLen=newTokens.length,oldLen=oldTokens.length,editLength=1,maxEditLength=newLen+oldLen;null!=options.maxEditLength&&(maxEditLength=Math.min(maxEditLength,options.maxEditLength));var maxExecutionTime=null!=(_a=options.timeout)?_a:1/0;let abortAfterTimestamp=Date.now()+maxExecutionTime,bestPath=[{oldPos:-1,lastComponent:void 0}],newPos=this.extractCommon(bestPath[0],newTokens,oldTokens,0,options);if(bestPath[0].oldPos+1>=oldLen&&newPos+1>=newLen)return done(this.buildValues(bestPath[0].lastComponent,newTokens,oldTokens));let minDiagonalToConsider=-1/0,maxDiagonalToConsider=1/0,execEditLength=()=>{for(let diagonalPath=Math.max(minDiagonalToConsider,-editLength);diagonalPath<=Math.min(maxDiagonalToConsider,editLength);diagonalPath+=2){let basePath;var removePath=bestPath[diagonalPath-1],addPath=bestPath[diagonalPath+1];removePath&&(bestPath[diagonalPath-1]=void 0);let canAdd=!1;addPath&&(addPathNewPos=addPath.oldPos-diagonalPath,canAdd=addPath&&0<=addPathNewPos&&addPathNewPos<newLen);var addPathNewPos=removePath&&removePath.oldPos+1<oldLen;if(canAdd||addPathNewPos){if(basePath=!addPathNewPos||canAdd&&removePath.oldPos<addPath.oldPos?this.addToPath(addPath,!0,!1,0,options):this.addToPath(removePath,!1,!0,1,options),newPos=this.extractCommon(basePath,newTokens,oldTokens,diagonalPath,options),basePath.oldPos+1>=oldLen&&newPos+1>=newLen)return done(this.buildValues(basePath.lastComponent,newTokens,oldTokens))||!0;(bestPath[diagonalPath]=basePath).oldPos+1>=oldLen&&(maxDiagonalToConsider=Math.min(maxDiagonalToConsider,diagonalPath-1)),newPos+1>=newLen&&(minDiagonalToConsider=Math.max(minDiagonalToConsider,diagonalPath+1))}else bestPath[diagonalPath]=void 0}editLength++};if(callback)!function exec(){setTimeout(function(){if(editLength>maxEditLength||Date.now()>abortAfterTimestamp)return callback(void 0);execEditLength()||exec()},0)}();else for(;editLength<=maxEditLength&&Date.now()<=abortAfterTimestamp;){var ret=execEditLength();if(ret)return ret}}addToPath(path,added,removed,oldPosInc,options){var last=path.lastComponent;return last&&!options.oneChangePerToken&&last.added===added&&last.removed===removed?{oldPos:path.oldPos+oldPosInc,lastComponent:{count:last.count+1,added:added,removed:removed,previousComponent:last.previousComponent}}:{oldPos:path.oldPos+oldPosInc,lastComponent:{count:1,added:added,removed:removed,previousComponent:last}}}extractCommon(basePath,newTokens,oldTokens,diagonalPath,options){var newLen=newTokens.length,oldLen=oldTokens.length;let oldPos=basePath.oldPos,newPos=oldPos-diagonalPath,commonCount=0;for(;newPos+1<newLen&&oldPos+1<oldLen&&this.equals(oldTokens[oldPos+1],newTokens[newPos+1],options);)newPos++,oldPos++,commonCount++,options.oneChangePerToken&&(basePath.lastComponent={count:1,previousComponent:basePath.lastComponent,added:!1,removed:!1});return commonCount&&!options.oneChangePerToken&&(basePath.lastComponent={count:commonCount,previousComponent:basePath.lastComponent,added:!1,removed:!1}),basePath.oldPos=oldPos,newPos}equals(left,right,options){return options.comparator?options.comparator(left,right):left===right||!!options.ignoreCase&&left.toLowerCase()===right.toLowerCase()}removeEmpty(array){var ret=[];for(let i=0;i<array.length;i++)array[i]&&ret.push(array[i]);return ret}castInput(value,options){return value}tokenize(value,options){return Array.from(value)}join(chars){return chars.join("")}postProcess(changeObjects,options){return changeObjects}get useLongestToken(){return!1}buildValues(lastComponent,newTokens,oldTokens){for(var nextComponent,components=[];lastComponent;)components.push(lastComponent),nextComponent=lastComponent.previousComponent,delete lastComponent.previousComponent,lastComponent=nextComponent;components.reverse();var componentLen=components.length;let componentPos=0,newPos=0,oldPos=0;for(;componentPos<componentLen;componentPos++){var component=components[componentPos];if(component.removed)component.value=this.join(oldTokens.slice(oldPos,oldPos+component.count)),oldPos+=component.count;else{if(!component.added&&this.useLongestToken){let value=newTokens.slice(newPos,newPos+component.count);value=value.map(function(value,i){i=oldTokens[oldPos+i];return i.length>value.length?i:value}),component.value=this.join(value)}else component.value=this.join(newTokens.slice(newPos,newPos+component.count));newPos+=component.count,component.added||(oldPos+=component.count)}}return components}}class CharacterDiff extends Diff{}let characterDiff=new CharacterDiff;function longestCommonPrefix(str1,str2){let i;for(i=0;i<str1.length&&i<str2.length;i++)if(str1[i]!=str2[i])return str1.slice(0,i);return str1.slice(0,i)}function longestCommonSuffix(str1,str2){let i;if(!str1||!str2||str1[str1.length-1]!=str2[str2.length-1])return"";for(i=0;i<str1.length&&i<str2.length;i++)if(str1[str1.length-(i+1)]!=str2[str2.length-(i+1)])return str1.slice(-i);return str1.slice(-i)}function replacePrefix(string,oldPrefix,newPrefix){if(string.slice(0,oldPrefix.length)!=oldPrefix)throw Error(`string ${JSON.stringify(string)} doesn't start with prefix ${JSON.stringify(oldPrefix)}; this is a bug`);return newPrefix+string.slice(oldPrefix.length)}function replaceSuffix(string,oldSuffix,newSuffix){if(!oldSuffix)return string+newSuffix;if(string.slice(-oldSuffix.length)!=oldSuffix)throw Error(`string ${JSON.stringify(string)} doesn't end with suffix ${JSON.stringify(oldSuffix)}; this is a bug`);return string.slice(0,-oldSuffix.length)+newSuffix}function removePrefix(string,oldPrefix){return replacePrefix(string,oldPrefix,"")}function removeSuffix(string,oldSuffix){return replaceSuffix(string,oldSuffix,"")}function maximumOverlap(string1,string2){return string2.slice(0,((a,b)=>{let startA=0,endB=(a.length>b.length&&(startA=a.length-b.length),b.length),map=(a.length<b.length&&(endB=a.length),Array(endB)),k=0;map[0]=0;for(let j=1;j<endB;j++){for(b[j]==b[k]?map[j]=map[k]:map[j]=k;0<k&&b[j]!=b[k];)k=map[k];b[j]==b[k]&&k++}k=0;for(let i=startA;i<a.length;i++){for(;0<k&&a[i]!=b[k];)k=map[k];a[i]==b[k]&&k++}return k})(string1,string2))}function segment(string,segmenter){var segmentObj,parts=[];for(segmentObj of Array.from(segmenter.segment(string))){var segment=segmentObj.segment;parts.length&&/\s/.test(parts[parts.length-1])&&/\s/.test(segment)?parts[parts.length-1]+=segment:parts.push(segment)}return parts}function trailingWs(string,segmenter){if(segmenter)return leadingAndTrailingWs(string,segmenter)[1];let i;for(i=string.length-1;0<=i&&string[i].match(/\s/);i--);return string.substring(i+1)}function leadingWs(string,segmenter){return segmenter?leadingAndTrailingWs(string,segmenter)[0]:(segmenter=string.match(/^\s*/))?segmenter[0]:""}function leadingAndTrailingWs(string,segmenter){if(!segmenter)return[leadingWs(string),trailingWs(string)];if("word"!=segmenter.resolvedOptions().granularity)throw new Error('The segmenter passed must have a granularity of "word"');string=segment(string,segmenter),segmenter=string[0],string=string[string.length-1];return[/\s/.test(segmenter)?segmenter:"",/\s/.test(string)?string:""]}let extendedWordChars="a-zA-Z0-9_\\u{AD}\\u{C0}-\\u{D6}\\u{D8}-\\u{F6}\\u{F8}-\\u{2C6}\\u{2C8}-\\u{2D7}\\u{2DE}-\\u{2FF}\\u{1E00}-\\u{1EFF}",tokenizeIncludingWhitespace=new RegExp(`[${extendedWordChars}]+|\\s+|[^${extendedWordChars}]`,"ug");class WordDiff extends Diff{equals(left,right,options){return options.ignoreCase&&(left=left.toLowerCase(),right=right.toLowerCase()),left.trim()===right.trim()}tokenize(value,options={}){let parts;if(options.intlSegmenter){options=options.intlSegmenter;if("word"!=options.resolvedOptions().granularity)throw new Error('The segmenter passed must have a granularity of "word"');parts=segment(value,options)}else parts=value.match(tokenizeIncludingWhitespace)||[];let tokens=[],prevPart=null;return parts.forEach(part=>{/\s/.test(part)?null==prevPart?tokens.push(part):tokens.push(tokens.pop()+part):null!=prevPart&&/\s/.test(prevPart)?tokens[tokens.length-1]==prevPart?tokens.push(tokens.pop()+part):tokens.push(prevPart+part):tokens.push(part),prevPart=part}),tokens}join(tokens){return tokens.map((token,i)=>0==i?token:token.replace(/^\s+/,"")).join("")}postProcess(changes,options){if(changes&&!options.oneChangePerToken){let lastKeep=null,insertion=null,deletion=null;changes.forEach(change=>{change.added?insertion=change:deletion=change.removed?change:((insertion||deletion)&&dedupeWhitespaceInChangeObjects(lastKeep,deletion,insertion,change,options.intlSegmenter),lastKeep=change,insertion=null)}),(insertion||deletion)&&dedupeWhitespaceInChangeObjects(lastKeep,deletion,insertion,null,options.intlSegmenter)}return changes}}let wordDiff=new WordDiff;function dedupeWhitespaceInChangeObjects(startKeep,deletion,insertion,endKeep,segmenter){if(deletion&&insertion){var[oldWsPrefix,oldWsSuffix]=leadingAndTrailingWs(deletion.value,segmenter),[newWsPrefix,newWsSuffix]=leadingAndTrailingWs(insertion.value,segmenter);startKeep&&(oldWsPrefix=longestCommonPrefix(oldWsPrefix,newWsPrefix),startKeep.value=replaceSuffix(startKeep.value,newWsPrefix,oldWsPrefix),deletion.value=removePrefix(deletion.value,oldWsPrefix),insertion.value=removePrefix(insertion.value,oldWsPrefix)),endKeep&&(newWsPrefix=longestCommonSuffix(oldWsSuffix,newWsSuffix),endKeep.value=replacePrefix(endKeep.value,newWsSuffix,newWsPrefix),deletion.value=removeSuffix(deletion.value,newWsPrefix),insertion.value=removeSuffix(insertion.value,newWsPrefix))}else if(insertion){if(startKeep&&(oldWsPrefix=leadingWs(insertion.value,segmenter),insertion.value=insertion.value.substring(oldWsPrefix.length)),endKeep){let ws=leadingWs(endKeep.value,segmenter);endKeep.value=endKeep.value.substring(ws.length)}}else if(startKeep&&endKeep){var oldWsSuffix=leadingWs(endKeep.value,segmenter),[newWsSuffix,newWsPrefix]=leadingAndTrailingWs(deletion.value,segmenter),insertion=longestCommonPrefix(oldWsSuffix,newWsSuffix),oldWsPrefix=(deletion.value=removePrefix(deletion.value,insertion),longestCommonSuffix(removePrefix(oldWsSuffix,insertion),newWsPrefix));deletion.value=removeSuffix(deletion.value,oldWsPrefix),endKeep.value=replacePrefix(endKeep.value,oldWsSuffix,oldWsPrefix),startKeep.value=replaceSuffix(startKeep.value,oldWsSuffix,oldWsSuffix.slice(0,oldWsSuffix.length-oldWsPrefix.length))}else if(endKeep){newWsSuffix=leadingWs(endKeep.value,segmenter),insertion=maximumOverlap(trailingWs(deletion.value,segmenter),newWsSuffix);deletion.value=removeSuffix(deletion.value,insertion)}else if(startKeep){let overlap=maximumOverlap(trailingWs(startKeep.value,segmenter),leadingWs(deletion.value,segmenter));deletion.value=removePrefix(deletion.value,overlap)}}class WordsWithSpaceDiff extends Diff{tokenize(value){var regex=new RegExp(`(\\r?\\n)|[${extendedWordChars}]+|[^\\S\\n\\r]+|[^${extendedWordChars}]`,"ug");return value.match(regex)||[]}}let wordsWithSpaceDiff=new WordsWithSpaceDiff;function diffWordsWithSpace(oldStr,newStr,options){return wordsWithSpaceDiff.diff(oldStr,newStr,options)}class LineDiff extends Diff{constructor(){super(...arguments),this.tokenize=tokenize}equals(left,right,options){return options.ignoreWhitespace?(options.newlineIsToken&&left.includes("\n")||(left=left.trim()),options.newlineIsToken&&right.includes("\n")||(right=right.trim())):options.ignoreNewlineAtEof&&!options.newlineIsToken&&(left.endsWith("\n")&&(left=left.slice(0,-1)),right.endsWith("\n"))&&(right=right.slice(0,-1)),super.equals(left,right,options)}}let lineDiff=new LineDiff;function diffLines(oldStr,newStr,options){return lineDiff.diff(oldStr,newStr,options)}function tokenize(value,options){var retLines=[],linesAndNewlines=(value=options.stripTrailingCr?value.replace(/\r\n/g,"\n"):value).split(/(\n|\r\n)/);linesAndNewlines[linesAndNewlines.length-1]||linesAndNewlines.pop();for(let i=0;i<linesAndNewlines.length;i++){var line=linesAndNewlines[i];i%2&&!options.newlineIsToken?retLines[retLines.length-1]+=line:retLines.push(line)}return retLines}class SentenceDiff extends Diff{tokenize(value){var _a,char,result=[];let tokenStartI=0;for(let i=0;i<value.length;i++){if(i==value.length-1){result.push(value.slice(tokenStartI));break}if(("."==(char=value[i])||"!"==char||"?"==char)&&value[i+1].match(/\s/)){for(result.push(value.slice(tokenStartI,i+1)),i=tokenStartI=i+1;null!=(_a=value[i+1])&&_a.match(/\s/);)i++;result.push(value.slice(tokenStartI,i+1)),tokenStartI=i+1}}return result}}let sentenceDiff=new SentenceDiff;class CssDiff extends Diff{tokenize(value){return value.split(/([{}:;,]|\s+)/)}}let cssDiff=new CssDiff;class JsonDiff extends Diff{constructor(){super(...arguments),this.tokenize=tokenize}get useLongestToken(){return!0}castInput(value,options){let{undefinedReplacement,stringifyReplacer=(k,v)=>void 0===v?undefinedReplacement:v}=options;return"string"==typeof value?value:JSON.stringify(canonicalize(value,null,null,stringifyReplacer),null," ")}equals(left,right,options){return super.equals(left.replace(/,([\r\n])/g,"$1"),right.replace(/,([\r\n])/g,"$1"),options)}}let jsonDiff=new JsonDiff;function canonicalize(obj,stack,replacementStack,replacer,key){stack=stack||[],replacementStack=replacementStack||[],replacer&&(obj=replacer(void 0===key?"":key,obj));let i;for(i=0;i<stack.length;i+=1)if(stack[i]===obj)return replacementStack[i];let canonicalizedObj;if("[object Array]"===Object.prototype.toString.call(obj)){for(stack.push(obj),canonicalizedObj=new Array(obj.length),replacementStack.push(canonicalizedObj),i=0;i<obj.length;i+=1)canonicalizedObj[i]=canonicalize(obj[i],stack,replacementStack,replacer,String(i));stack.pop(),replacementStack.pop()}else if("object"==typeof(obj=obj&&obj.toJSON?obj.toJSON():obj)&&null!==obj){stack.push(obj),canonicalizedObj={},replacementStack.push(canonicalizedObj);var sortedKeys=[];let key;for(key in obj)Object.prototype.hasOwnProperty.call(obj,key)&&sortedKeys.push(key);for(sortedKeys.sort(),i=0;i<sortedKeys.length;i+=1)key=sortedKeys[i],canonicalizedObj[key]=canonicalize(obj[key],stack,replacementStack,replacer,key);stack.pop(),replacementStack.pop()}else canonicalizedObj=obj;return canonicalizedObj}class ArrayDiff extends Diff{tokenize(value){return value.slice()}join(value){return value}removeEmpty(value){return value}}let arrayDiff=new ArrayDiff;function parsePatch(uniDiff){let diffstr=uniDiff.split(/\n/),list=[],i=0;function parseIndex(){var index={};for(list.push(index);i<diffstr.length;){var line=diffstr[i];if(/^(---|\+\+\+|@@)\s/.test(line))break;var headerMatch=/^(?:Index:|diff(?: -r \w+)+)\s+/.exec(line);headerMatch&&(index.index=line.substring(headerMatch[0].length).trim()),i++}for(parseFileHeader(index),parseFileHeader(index),index.hunks=[];i<diffstr.length;){let line=diffstr[i];if(/^(Index:\s|diff\s|---\s|\+\+\+\s|===================================================================)/.test(line))break;if(/^@@/.test(line))index.hunks.push((()=>{var chunkHeaderIndex=i,chunkHeaderLine=diffstr[i++],hunk={oldStart:+(chunkHeaderLine=chunkHeaderLine.split(/@@ -(\d+)(?:,(\d+))? \+(\d+)(?:,(\d+))? @@/))[1],oldLines:void 0===chunkHeaderLine[2]?1:+chunkHeaderLine[2],newStart:+chunkHeaderLine[3],newLines:void 0===chunkHeaderLine[4]?1:+chunkHeaderLine[4],lines:[]};0===hunk.oldLines&&(hunk.oldStart+=1),0===hunk.newLines&&(hunk.newStart+=1);let addCount=0,removeCount=0;for(;i<diffstr.length&&(removeCount<hunk.oldLines||addCount<hunk.newLines||null!=(_a=diffstr[i])&&_a.startsWith("\\"));i++){var _a=0==diffstr[i].length&&i!=diffstr.length-1?" ":diffstr[i][0];if("+"!==_a&&"-"!==_a&&" "!==_a&&"\\"!==_a)throw new Error(`Hunk at line ${chunkHeaderIndex+1} contained invalid line `+diffstr[i]);hunk.lines.push(diffstr[i]),"+"===_a?addCount++:"-"===_a?removeCount++:" "===_a&&(addCount++,removeCount++)}if(addCount||1!==hunk.newLines||(hunk.newLines=0),removeCount||1!==hunk.oldLines||(hunk.oldLines=0),addCount!==hunk.newLines)throw new Error("Added line count did not match for hunk at line "+(chunkHeaderIndex+1));if(removeCount===hunk.oldLines)return hunk;throw new Error("Removed line count did not match for hunk at line "+(chunkHeaderIndex+1))})());else{if(line)throw new Error("Unknown line "+(i+1)+" "+JSON.stringify(line));i++}}}function parseFileHeader(index){var fileHeaderMatch=/^(---|\+\+\+)\s+/.exec(diffstr[i]);if(fileHeaderMatch){var fileHeaderMatch=fileHeaderMatch[1],data=diffstr[i].substring(3).trim().split("\t",2),header=(data[1]||"").trim();let fileName=data[0].replace(/\\\\/g,"\\");fileName.startsWith('"')&&fileName.endsWith('"')&&(fileName=fileName.substr(1,fileName.length-2)),"---"===fileHeaderMatch?(index.oldFileName=fileName,index.oldHeader=header):(index.newFileName=fileName,index.newHeader=header),i++}}for(;i<diffstr.length;)parseIndex();return list}function applyPatch(source,patch,options={}){let patches;if(1<(patches="string"==typeof patch?parsePatch(patch):Array.isArray(patch)?patch:[patch]).length)throw new Error("applyPatch only works with a single input.");return((source,patch,options={})=>{!options.autoConvertLineEndings&&null!=options.autoConvertLineEndings||((string=>string.includes("\r\n")&&!string.startsWith("\n")&&!string.match(/[^\r]\n/))(source)&&(patch=>!(patch=Array.isArray(patch)?patch:[patch]).some(index=>index.hunks.some(hunk=>hunk.lines.some(line=>!line.startsWith("\\")&&line.endsWith("\r")))))(patch)?patch=function unixToWin(patch){return Array.isArray(patch)?patch.map(p=>unixToWin(p)):Object.assign(Object.assign({},patch),{hunks:patch.hunks.map(hunk=>Object.assign(Object.assign({},hunk),{lines:hunk.lines.map((line,i)=>line.startsWith("\\")||line.endsWith("\r")||null!=(i=hunk.lines[i+1])&&i.startsWith("\\")?line:line+"\r")}))})}(patch):(string=>!string.includes("\r\n")&&string.includes("\n"))(source)&&(patch=>(patch=Array.isArray(patch)?patch:[patch]).some(index=>index.hunks.some(hunk=>hunk.lines.some(line=>line.endsWith("\r"))))&&patch.every(index=>index.hunks.every(hunk=>hunk.lines.every((line,i)=>line.startsWith("\\")||line.endsWith("\r")||(null==(line=hunk.lines[i+1])?void 0:line.startsWith("\\"))))))(patch)&&(patch=function winToUnix(patch){return Array.isArray(patch)?patch.map(p=>winToUnix(p)):Object.assign(Object.assign({},patch),{hunks:patch.hunks.map(hunk=>Object.assign(Object.assign({},hunk),{lines:hunk.lines.map(line=>line.endsWith("\r")?line.substring(0,line.length-1):line)}))})}(patch)));let lines=source.split("\n"),hunks=patch.hunks,compareLine=options.compareLine||((lineNumber,line,operation,patchContent)=>line===patchContent),fuzzFactor=options.fuzzFactor||0,minLine=0;if(fuzzFactor<0||!Number.isInteger(fuzzFactor))throw new Error("fuzzFactor must be a non-negative integer");if(!hunks.length)return source;let prevLine="",removeEOFNL=!1,addEOFNL=!1;for(let i=0;i<hunks[hunks.length-1].lines.length;i++){var line=hunks[hunks.length-1].lines[i];"\\"==line[0]&&("+"==prevLine[0]?removeEOFNL=!0:"-"==prevLine[0]&&(addEOFNL=!0)),prevLine=line}if(removeEOFNL){if(addEOFNL){if(!fuzzFactor&&""==lines[lines.length-1])return!1}else if(""==lines[lines.length-1])lines.pop();else if(!fuzzFactor)return!1}else if(addEOFNL)if(""!=lines[lines.length-1])lines.push("");else if(!fuzzFactor)return!1;let resultLines=[],prevHunkOffset=0;for(let i=0;i<hunks.length;i++){var hunk=hunks[i];let hunkResult;var maxLine=lines.length-hunk.oldLines+fuzzFactor;let toPos;for(let maxErrors=0;maxErrors<=fuzzFactor;maxErrors++){for(var iterator=((start,minLine,maxLine)=>{let wantForward=!0,backwardExhausted=!1,forwardExhausted=!1,localOffset=1;return function iterator(){if(wantForward&&!forwardExhausted){if(backwardExhausted?localOffset++:wantForward=!1,start+localOffset<=maxLine)return start+localOffset;forwardExhausted=!0}if(!backwardExhausted)return forwardExhausted||(wantForward=!0),minLine<=start-localOffset?start-localOffset++:(backwardExhausted=!0,iterator())}})(toPos=hunk.oldStart+prevHunkOffset-1,minLine,maxLine);void 0!==toPos&&!(hunkResult=function applyHunk(hunkLines,toPos,maxErrors,hunkLinesI=0,lastContextLineMatched=!0,patchedLines=[],patchedLinesLength=0){let nConsecutiveOldContextLines=0,nextContextLineMustMatch=!1;for(;hunkLinesI<hunkLines.length;hunkLinesI++){var operation=0<(hunkLine=hunkLines[hunkLinesI]).length?hunkLine[0]:" ",hunkLine=0<hunkLine.length?hunkLine.substr(1):hunkLine;if("-"===operation){if(!compareLine(toPos+1,lines[toPos],operation,hunkLine))return maxErrors&&null!=lines[toPos]?(patchedLines[patchedLinesLength]=lines[toPos],applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI,!1,patchedLines,patchedLinesLength+1)):null;toPos++,nConsecutiveOldContextLines=0}if("+"===operation){if(!lastContextLineMatched)return null;patchedLines[patchedLinesLength]=hunkLine,patchedLinesLength++,nConsecutiveOldContextLines=0,nextContextLineMustMatch=!0}if(" "===operation){if(nConsecutiveOldContextLines++,patchedLines[patchedLinesLength]=lines[toPos],!compareLine(toPos+1,lines[toPos],operation,hunkLine))return nextContextLineMustMatch||!maxErrors?null:lines[toPos]&&(applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI+1,!1,patchedLines,patchedLinesLength+1)||applyHunk(hunkLines,toPos+1,maxErrors-1,hunkLinesI,!1,patchedLines,patchedLinesLength+1))||applyHunk(hunkLines,toPos,maxErrors-1,hunkLinesI+1,!1,patchedLines,patchedLinesLength);patchedLinesLength++,lastContextLineMatched=!0,nextContextLineMustMatch=!1,toPos++}}return patchedLinesLength-=nConsecutiveOldContextLines,toPos-=nConsecutiveOldContextLines,patchedLines.length=patchedLinesLength,{patchedLines:patchedLines,oldLineLastI:toPos-1}}(hunk.lines,toPos,maxErrors));toPos=iterator());if(hunkResult)break}if(!hunkResult)return!1;for(let i=minLine;i<toPos;i++)resultLines.push(lines[i]);for(let i=0;i<hunkResult.patchedLines.length;i++){var line=hunkResult.patchedLines[i];resultLines.push(line)}minLine=hunkResult.oldLineLastI+1,prevHunkOffset=toPos+1-hunk.oldStart}for(let i=minLine;i<lines.length;i++)resultLines.push(lines[i]);return resultLines.join("\n")})(source,patches[0],options)}let INCLUDE_HEADERS={includeIndex:!0,includeUnderline:!0,includeFileHeaders:!0};function structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options){let optionsObj,context=(void 0===(optionsObj=options?"function"==typeof options?{callback:options}:options:{}).context&&(optionsObj.context=4),optionsObj.context);if(optionsObj.newlineIsToken)throw new Error("newlineIsToken may not be used with patch-generation functions, only with diffing functions");if(!optionsObj.callback)return diffLinesResultToPatch(diffLines(oldStr,newStr,optionsObj));{let callback=optionsObj.callback;diffLines(oldStr,newStr,Object.assign(Object.assign({},optionsObj),{callback:diff=>{diff=diffLinesResultToPatch(diff);callback(diff)}}))}function diffLinesResultToPatch(diff){if(diff){diff.push({value:"",lines:[]});var hunks=[];let oldRangeStart=0,newRangeStart=0,curRange=[],oldLine=1,newLine=1;for(let i=0;i<diff.length;i++){var line,current=diff[i],lines=current.lines||(text=>{var hasTrailingNl=text.endsWith("\n"),text=text.split("\n").map(line=>line+"\n");return hasTrailingNl?text.pop():text.push(text.pop().slice(0,-1)),text})(current.value);if(current.lines=lines,current.added||current.removed){oldRangeStart||(prev=diff[i-1],oldRangeStart=oldLine,newRangeStart=newLine,prev&&(curRange=0<context?contextLines(prev.lines.slice(-context)):[],oldRangeStart-=curRange.length,newRangeStart-=curRange.length));for(line of lines)curRange.push((current.added?"+":"-")+line);current.added?newLine+=lines.length:oldLine+=lines.length}else{if(oldRangeStart)if(lines.length<=2*context&&i<diff.length-2)for(let line of contextLines(lines))curRange.push(line);else{var prev=Math.min(lines.length,context);for(let line of contextLines(lines.slice(0,prev)))curRange.push(line);var hunk={oldStart:oldRangeStart,oldLines:oldLine-oldRangeStart+prev,newStart:newRangeStart,newLines:newLine-newRangeStart+prev,lines:curRange};hunks.push(hunk),oldRangeStart=0,newRangeStart=0,curRange=[]}oldLine+=lines.length,newLine+=lines.length}}for(let hunk of hunks)for(let i=0;i<hunk.lines.length;i++)hunk.lines[i].endsWith("\n")?hunk.lines[i]=hunk.lines[i].slice(0,-1):(hunk.lines.splice(i+1,0,"\"),i++);return{oldFileName:oldFileName,newFileName:newFileName,oldHeader:oldHeader,newHeader:newHeader,hunks:hunks};function contextLines(lines){return lines.map(function(entry){return" "+entry})}}}}function formatPatch(patch,headerOptions){if(headerOptions=headerOptions||INCLUDE_HEADERS,Array.isArray(patch)){if(1<patch.length&&!headerOptions.includeFileHeaders)throw new Error("Cannot omit file headers on a multi-file patch. (The result would be unparseable; how would a tool trying to apply the patch know which changes are to which file?)");return patch.map(p=>formatPatch(p,headerOptions)).join("\n")}var ret=[];headerOptions.includeIndex&&patch.oldFileName==patch.newFileName&&ret.push("Index: "+patch.oldFileName),headerOptions.includeUnderline&&ret.push("==================================================================="),headerOptions.includeFileHeaders&&(ret.push("--- "+patch.oldFileName+(void 0===patch.oldHeader?"":"\t"+patch.oldHeader)),ret.push("+++ "+patch.newFileName+(void 0===patch.newHeader?"":"\t"+patch.newHeader)));for(let i=0;i<patch.hunks.length;i++){var line,hunk=patch.hunks[i];0===hunk.oldLines&&--hunk.oldStart,0===hunk.newLines&&--hunk.newStart,ret.push("@@ -"+hunk.oldStart+","+hunk.oldLines+" +"+hunk.newStart+","+hunk.newLines+" @@");for(line of hunk.lines)ret.push(line)}return ret.join("\n")+"\n"}function createTwoFilesPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options){if(null!=(options="function"==typeof options?{callback:options}:options)&&options.callback){let callback=options.callback;structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,Object.assign(Object.assign({},options),{callback:patchObj=>{patchObj?callback(formatPatch(patchObj,options.headerOptions)):callback(void 0)}}))}else{oldFileName=structuredPatch(oldFileName,newFileName,oldStr,newStr,oldHeader,newHeader,options);if(oldFileName)return formatPatch(oldFileName,null==options?void 0:options.headerOptions)}}exports.Diff=Diff,exports.FILE_HEADERS_ONLY={includeIndex:!1,includeUnderline:!1,includeFileHeaders:!0},exports.INCLUDE_HEADERS=INCLUDE_HEADERS,exports.OMIT_HEADERS={includeIndex:!1,includeUnderline:!1,includeFileHeaders:!1},exports.applyPatch=applyPatch,exports.applyPatches=function(uniDiff,options){let spDiff="string"==typeof uniDiff?parsePatch(uniDiff):uniDiff,currentIndex=0;!function processIndex(){let index=spDiff[currentIndex++];if(!index)return options.complete();options.loadFile(index,function(err,data){if(err)return options.complete(err);err=applyPatch(data,index,options),options.patched(index,err,function(err){if(err)return options.complete(err);processIndex()})})}()},exports.arrayDiff=arrayDiff,exports.canonicalize=canonicalize,exports.characterDiff=characterDiff,exports.convertChangesToDMP=function(changes){var ret=[];let change,operation;for(let i=0;i<changes.length;i++)change=changes[i],operation=change.added?1:change.removed?-1:0,ret.push([operation,change.value]);return ret},exports.convertChangesToXML=function(changes){var ret=[];for(let i=0;i<changes.length;i++){var change=changes[i];change.added?ret.push("<ins>"):change.removed&&ret.push("<del>"),ret.push((s=>{let n=s;return n=(n=(n=(n=n.replace(/&/g,"&amp;")).replace(/</g,"&lt;")).replace(/>/g,"&gt;")).replace(/"/g,"&quot;")})(change.value)),change.added?ret.push("</ins>"):change.removed&&ret.push("</del>")}return ret.join("")},exports.createPatch=function(fileName,oldStr,newStr,oldHeader,newHeader,options){return createTwoFilesPatch(fileName,fileName,oldStr,newStr,oldHeader,newHeader,options)},exports.createTwoFilesPatch=createTwoFilesPatch,exports.cssDiff=cssDiff,exports.diffArrays=function(oldArr,newArr,options){return arrayDiff.diff(oldArr,newArr,options)},exports.diffChars=function(oldStr,newStr,options){return characterDiff.diff(oldStr,newStr,options)},exports.diffCss=function(oldStr,newStr,options){return cssDiff.diff(oldStr,newStr,options)},exports.diffJson=function(oldStr,newStr,options){return jsonDiff.diff(oldStr,newStr,options)},exports.diffLines=diffLines,exports.diffSentences=function(oldStr,newStr,options){return sentenceDiff.diff(oldStr,newStr,options)},exports.diffTrimmedLines=function(oldStr,newStr,options){return options=((options,defaults)=>{if("function"==typeof options)defaults.callback=options;else if(options)for(var name in options)Object.prototype.hasOwnProperty.call(options,name)&&(defaults[name]=options[name]);return defaults})(options,{ignoreWhitespace:!0}),lineDiff.diff(oldStr,newStr,options)},exports.diffWords=function(oldStr,newStr,options){return null==(null==options?void 0:options.ignoreWhitespace)||options.ignoreWhitespace?wordDiff.diff(oldStr,newStr,options):diffWordsWithSpace(oldStr,newStr,options)},exports.diffWordsWithSpace=diffWordsWithSpace,exports.formatPatch=formatPatch,exports.jsonDiff=jsonDiff,exports.lineDiff=lineDiff,exports.parsePatch=parsePatch,exports.reversePatch=function reversePatch(structuredPatch){return Array.isArray(structuredPatch)?structuredPatch.map(patch=>reversePatch(patch)).reverse():Object.assign(Object.assign({},structuredPatch),{oldFileName:structuredPatch.newFileName,oldHeader:structuredPatch.newHeader,newFileName:structuredPatch.oldFileName,newHeader:structuredPatch.oldHeader,hunks:structuredPatch.hunks.map(hunk=>({oldLines:hunk.newLines,oldStart:hunk.newStart,newLines:hunk.oldLines,newStart:hunk.oldStart,lines:hunk.lines.map(l=>l.startsWith("-")?"+"+l.slice(1):l.startsWith("+")?"-"+l.slice(1):l)}))})},exports.sentenceDiff=sentenceDiff,exports.structuredPatch=structuredPatch,exports.wordDiff=wordDiff,exports.wordsWithSpaceDiff=wordsWithSpaceDiff});
@@ -1 +1 @@
1
- {"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/diff/word.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,4BAA4B,EAAC,MAAM,aAAa,CAAC;AAqDvL,cAAM,QAAS,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,4BAA4B;IASrG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,yBAAyB,GAAG,4BAAiC;IAoD9F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;IAerB,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG;CA6B1D;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;AA8IzB,cAAM,kBAAmB,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM;CASvB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA"}
1
+ {"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/diff/word.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,4BAA4B,EAAC,MAAM,aAAa,CAAC;AAqDvL,cAAM,QAAS,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,4BAA4B;IASrG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,yBAAyB,GAAG,4BAAiC;IAwC9F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;IAerB,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG;CA6B1D;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;AA4IzB,cAAM,kBAAmB,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM;CASvB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA"}
@@ -89,23 +89,9 @@ var WordDiff = /** @class */ (function (_super) {
89
89
  // We want `parts` to be an array whose elements alternate between being
90
90
  // pure whitespace and being pure non-whitespace. This is ALMOST what the
91
91
  // segments returned by a word-based Intl.Segmenter already look like,
92
- // and therefore we can ALMOST get what we want by simply doing...
93
- // parts = Array.from(segmenter.segment(value), segment => segment.segment);
94
- // ... but not QUITE, because there's of one annoying special case: every
95
- // newline character gets its own segment, instead of sharing a segment
96
- // with other surrounding whitespace. We therefore need to manually merge
97
- // consecutive segments of whitespace into a single part:
98
- parts = [];
99
- for (var _i = 0, _a = Array.from(segmenter.segment(value)); _i < _a.length; _i++) {
100
- var segmentObj = _a[_i];
101
- var segment = segmentObj.segment;
102
- if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment)) {
103
- parts[parts.length - 1] += segment;
104
- }
105
- else {
106
- parts.push(segment);
107
- }
108
- }
92
+ // but not quite - see explanation in the docs of our custom segment()
93
+ // function.
94
+ parts = (0, string_js_1.segment)(value, segmenter);
109
95
  }
110
96
  else {
111
97
  parts = value.match(tokenizeIncludingWhitespace) || [];
@@ -169,7 +155,7 @@ var WordDiff = /** @class */ (function (_super) {
169
155
  }
170
156
  else {
171
157
  if (insertion || deletion) { // May be false at start of text
172
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
158
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter);
173
159
  }
174
160
  lastKeep = change;
175
161
  insertion = null;
@@ -177,7 +163,7 @@ var WordDiff = /** @class */ (function (_super) {
177
163
  }
178
164
  });
179
165
  if (insertion || deletion) {
180
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
166
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
181
167
  }
182
168
  return changes;
183
169
  };
@@ -194,7 +180,7 @@ function diffWords(oldStr, newStr, options) {
194
180
  }
195
181
  return exports.wordDiff.diff(oldStr, newStr, options);
196
182
  }
197
- function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
183
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
198
184
  // Before returning, we tidy up the leading and trailing whitespace of the
199
185
  // change objects to eliminate cases where trailing whitespace in one object
200
186
  // is repeated as leading whitespace in the next.
@@ -237,10 +223,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
237
223
  // * Just a "delete"
238
224
  // We handle the three cases separately.
239
225
  if (deletion && insertion) {
240
- var oldWsPrefix = (0, string_js_1.leadingWs)(deletion.value);
241
- var oldWsSuffix = (0, string_js_1.trailingWs)(deletion.value);
242
- var newWsPrefix = (0, string_js_1.leadingWs)(insertion.value);
243
- var newWsSuffix = (0, string_js_1.trailingWs)(insertion.value);
226
+ var _a = (0, string_js_1.leadingAndTrailingWs)(deletion.value, segmenter), oldWsPrefix = _a[0], oldWsSuffix = _a[1];
227
+ var _b = (0, string_js_1.leadingAndTrailingWs)(insertion.value, segmenter), newWsPrefix = _b[0], newWsSuffix = _b[1];
244
228
  if (startKeep) {
245
229
  var commonWsPrefix = (0, string_js_1.longestCommonPrefix)(oldWsPrefix, newWsPrefix);
246
230
  startKeep.value = (0, string_js_1.replaceSuffix)(startKeep.value, newWsPrefix, commonWsPrefix);
@@ -262,17 +246,17 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
262
246
  // whitespace and deleting duplicate leading whitespace where
263
247
  // present.
264
248
  if (startKeep) {
265
- var ws = (0, string_js_1.leadingWs)(insertion.value);
249
+ var ws = (0, string_js_1.leadingWs)(insertion.value, segmenter);
266
250
  insertion.value = insertion.value.substring(ws.length);
267
251
  }
268
252
  if (endKeep) {
269
- var ws = (0, string_js_1.leadingWs)(endKeep.value);
253
+ var ws = (0, string_js_1.leadingWs)(endKeep.value, segmenter);
270
254
  endKeep.value = endKeep.value.substring(ws.length);
271
255
  }
272
256
  // otherwise we've got a deletion and no insertion
273
257
  }
274
258
  else if (startKeep && endKeep) {
275
- var newWsFull = (0, string_js_1.leadingWs)(endKeep.value), delWsStart = (0, string_js_1.leadingWs)(deletion.value), delWsEnd = (0, string_js_1.trailingWs)(deletion.value);
259
+ var newWsFull = (0, string_js_1.leadingWs)(endKeep.value, segmenter), _c = (0, string_js_1.leadingAndTrailingWs)(deletion.value, segmenter), delWsStart = _c[0], delWsEnd = _c[1];
276
260
  // Any whitespace that comes straight after startKeep in both the old and
277
261
  // new texts, assign to startKeep and remove from the deletion.
278
262
  var newWsStart = (0, string_js_1.longestCommonPrefix)(newWsFull, delWsStart);
@@ -291,8 +275,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
291
275
  // We are at the start of the text. Preserve all the whitespace on
292
276
  // endKeep, and just remove whitespace from the end of deletion to the
293
277
  // extent that it overlaps with the start of endKeep.
294
- var endKeepWsPrefix = (0, string_js_1.leadingWs)(endKeep.value);
295
- var deletionWsSuffix = (0, string_js_1.trailingWs)(deletion.value);
278
+ var endKeepWsPrefix = (0, string_js_1.leadingWs)(endKeep.value, segmenter);
279
+ var deletionWsSuffix = (0, string_js_1.trailingWs)(deletion.value, segmenter);
296
280
  var overlap = (0, string_js_1.maximumOverlap)(deletionWsSuffix, endKeepWsPrefix);
297
281
  deletion.value = (0, string_js_1.removeSuffix)(deletion.value, overlap);
298
282
  }
@@ -300,8 +284,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
300
284
  // We are at the END of the text. Preserve all the whitespace on
301
285
  // startKeep, and just remove whitespace from the start of deletion to
302
286
  // the extent that it overlaps with the end of startKeep.
303
- var startKeepWsSuffix = (0, string_js_1.trailingWs)(startKeep.value);
304
- var deletionWsPrefix = (0, string_js_1.leadingWs)(deletion.value);
287
+ var startKeepWsSuffix = (0, string_js_1.trailingWs)(startKeep.value, segmenter);
288
+ var deletionWsPrefix = (0, string_js_1.leadingWs)(deletion.value, segmenter);
305
289
  var overlap = (0, string_js_1.maximumOverlap)(startKeepWsSuffix, deletionWsPrefix);
306
290
  deletion.value = (0, string_js_1.removePrefix)(deletion.value, overlap);
307
291
  }
@@ -13,6 +13,18 @@ export declare function hasOnlyWinLineEndings(string: string): boolean;
13
13
  * Returns true if the string consistently uses Unix line endings.
14
14
  */
15
15
  export declare function hasOnlyUnixLineEndings(string: string): boolean;
16
- export declare function trailingWs(string: string): string;
17
- export declare function leadingWs(string: string): string;
16
+ /**
17
+ * Split a string into segments using a word segmenter, merging consecutive
18
+ * segments if they are both whitespace segments. Whitespace segments can
19
+ * appear adjacent to one another for two reasons:
20
+ * - newlines always get their own segment
21
+ * - where a diacritic is attached to a whitespace character in the text, the
22
+ * segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
23
+ * This function therefore runs the segmenter's .segment() method and then
24
+ * merges consecutive segments of whitespace into a single part.
25
+ */
26
+ export declare function segment(string: string, segmenter: Intl.Segmenter): string[];
27
+ export declare function trailingWs(string: string, segmenter?: Intl.Segmenter): string;
28
+ export declare function leadingWs(string: string, segmenter?: Intl.Segmenter): string;
29
+ export declare function leadingAndTrailingWs(string: string, segmenter?: Intl.Segmenter): [string, string];
18
30
  //# sourceMappingURL=string.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/util/string.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAkCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBjD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIhD"}
1
+ {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/util/string.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAkCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,EAAE,CAW3E;AAgBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAuB7E;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAQ5E;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GACzB,CAAC,MAAM,EAAE,MAAM,CAAC,CAelB"}
@@ -9,8 +9,10 @@ exports.removeSuffix = removeSuffix;
9
9
  exports.maximumOverlap = maximumOverlap;
10
10
  exports.hasOnlyWinLineEndings = hasOnlyWinLineEndings;
11
11
  exports.hasOnlyUnixLineEndings = hasOnlyUnixLineEndings;
12
+ exports.segment = segment;
12
13
  exports.trailingWs = trailingWs;
13
14
  exports.leadingWs = leadingWs;
15
+ exports.leadingAndTrailingWs = leadingAndTrailingWs;
14
16
  function longestCommonPrefix(str1, str2) {
15
17
  var i;
16
18
  for (i = 0; i < str1.length && i < str2.length; i++) {
@@ -114,7 +116,47 @@ function hasOnlyWinLineEndings(string) {
114
116
  function hasOnlyUnixLineEndings(string) {
115
117
  return !string.includes('\r\n') && string.includes('\n');
116
118
  }
117
- function trailingWs(string) {
119
+ /**
120
+ * Split a string into segments using a word segmenter, merging consecutive
121
+ * segments if they are both whitespace segments. Whitespace segments can
122
+ * appear adjacent to one another for two reasons:
123
+ * - newlines always get their own segment
124
+ * - where a diacritic is attached to a whitespace character in the text, the
125
+ * segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
126
+ * This function therefore runs the segmenter's .segment() method and then
127
+ * merges consecutive segments of whitespace into a single part.
128
+ */
129
+ function segment(string, segmenter) {
130
+ var parts = [];
131
+ for (var _i = 0, _a = Array.from(segmenter.segment(string)); _i < _a.length; _i++) {
132
+ var segmentObj = _a[_i];
133
+ var segment_1 = segmentObj.segment;
134
+ if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment_1)) {
135
+ parts[parts.length - 1] += segment_1;
136
+ }
137
+ else {
138
+ parts.push(segment_1);
139
+ }
140
+ }
141
+ return parts;
142
+ }
143
+ // The functions below take a `segmenter` argument so that, when called from
144
+ // diffWords when it is using a segmenter, they can use a notion of what
145
+ // constitutes "whitespace" that is consistent with the segmenter.
146
+ //
147
+ // USUALLY this will be identical to the result of the non-segmenter-based
148
+ // logic, but it differs in at least one case: when whitespace characters are
149
+ // modified by diacritics. A word segmenter considers these diacritics to be
150
+ // part of the whitespace, whereas our non-segmenter-based logic does not.
151
+ //
152
+ // Because the segmenter-based approach necessarily requires segmenting the
153
+ // entire string, we offer a leadingAndTrailingWs function to allow getting the
154
+ // whitespace prefix AND whitespace suffix with a single call to the segmenter,
155
+ // for efficiency's sake.
156
+ function trailingWs(string, segmenter) {
157
+ if (segmenter) {
158
+ return leadingAndTrailingWs(string, segmenter)[1];
159
+ }
118
160
  // Yes, this looks overcomplicated and dumb - why not replace the whole function with
119
161
  // return string.match(/\s*$/)[0]
120
162
  // you ask? Because:
@@ -134,8 +176,25 @@ function trailingWs(string) {
134
176
  }
135
177
  return string.substring(i + 1);
136
178
  }
137
- function leadingWs(string) {
179
+ function leadingWs(string, segmenter) {
180
+ if (segmenter) {
181
+ return leadingAndTrailingWs(string, segmenter)[0];
182
+ }
138
183
  // Thankfully the annoying considerations described in trailingWs don't apply here:
139
184
  var match = string.match(/^\s*/);
140
185
  return match ? match[0] : '';
141
186
  }
187
+ function leadingAndTrailingWs(string, segmenter) {
188
+ if (!segmenter) {
189
+ return [leadingWs(string), trailingWs(string)];
190
+ }
191
+ if (segmenter.resolvedOptions().granularity != 'word') {
192
+ throw new Error('The segmenter passed must have a granularity of "word"');
193
+ }
194
+ var segments = segment(string, segmenter);
195
+ var firstSeg = segments[0];
196
+ var lastSeg = segments[segments.length - 1];
197
+ var head = (/\s/).test(firstSeg) ? firstSeg : '';
198
+ var tail = (/\s/).test(lastSeg) ? lastSeg : '';
199
+ return [head, tail];
200
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/diff/word.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,4BAA4B,EAAC,MAAM,aAAa,CAAC;AAqDvL,cAAM,QAAS,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,4BAA4B;IASrG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,yBAAyB,GAAG,4BAAiC;IAoD9F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;IAerB,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG;CA6B1D;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;AA8IzB,cAAM,kBAAmB,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM;CASvB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA"}
1
+ {"version":3,"file":"word.d.ts","sourceRoot":"","sources":["../../src/diff/word.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,KAAK,EAAE,YAAY,EAAE,uBAAuB,EAAE,0BAA0B,EAAE,wBAAwB,EAAE,yBAAyB,EAAE,4BAA4B,EAAC,MAAM,aAAa,CAAC;AAqDvL,cAAM,QAAS,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACzC,MAAM,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,yBAAyB,GAAG,4BAA4B;IASrG,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,yBAAyB,GAAG,4BAAiC;IAwC9F,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE;IAerB,WAAW,CAAC,OAAO,EAAE,YAAY,CAAC,MAAM,CAAC,EAAE,EAAE,OAAO,EAAE,GAAG;CA6B1D;AAED,eAAO,MAAM,QAAQ,UAAiB,CAAC;AAEvC;;;;;GAKG;AACH,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,SAAS,CACvB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA;AA4IzB,cAAM,kBAAmB,SAAQ,IAAI,CAAC,MAAM,EAAE,MAAM,CAAC;IACnD,QAAQ,CAAC,KAAK,EAAE,MAAM;CASvB;AAED,eAAO,MAAM,kBAAkB,oBAA2B,CAAC;AAE3D;;;GAGG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,wBAAwB,CAAC,MAAM,CAAC,GACxC,SAAS,CAAC;AACb,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GAAG,uBAAuB,CAAC,MAAM,CAAC,GACnE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,4BAA4B,GAAG,0BAA0B,CAAC,MAAM,CAAC,GACzE,SAAS,CAAA;AACZ,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,yBAAyB,GACjC,YAAY,CAAC,MAAM,CAAC,EAAE,GAAG,SAAS,CAAA;AACrC,wBAAgB,kBAAkB,CAChC,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,4BAA4B,GACrC,YAAY,CAAC,MAAM,CAAC,EAAE,CAAA"}
@@ -1,5 +1,5 @@
1
1
  import Diff from './base.js';
2
- import { longestCommonPrefix, longestCommonSuffix, replacePrefix, replaceSuffix, removePrefix, removeSuffix, maximumOverlap, leadingWs, trailingWs } from '../util/string.js';
2
+ import { longestCommonPrefix, longestCommonSuffix, replacePrefix, replaceSuffix, removePrefix, removeSuffix, maximumOverlap, leadingWs, trailingWs, leadingAndTrailingWs, segment } from '../util/string.js';
3
3
  // Based on https://en.wikipedia.org/wiki/Latin_script_in_Unicode
4
4
  //
5
5
  // Chars/ranges counted as "word" characters by this regex are as follows:
@@ -64,22 +64,9 @@ class WordDiff extends Diff {
64
64
  // We want `parts` to be an array whose elements alternate between being
65
65
  // pure whitespace and being pure non-whitespace. This is ALMOST what the
66
66
  // segments returned by a word-based Intl.Segmenter already look like,
67
- // and therefore we can ALMOST get what we want by simply doing...
68
- // parts = Array.from(segmenter.segment(value), segment => segment.segment);
69
- // ... but not QUITE, because there's of one annoying special case: every
70
- // newline character gets its own segment, instead of sharing a segment
71
- // with other surrounding whitespace. We therefore need to manually merge
72
- // consecutive segments of whitespace into a single part:
73
- parts = [];
74
- for (const segmentObj of Array.from(segmenter.segment(value))) {
75
- const segment = segmentObj.segment;
76
- if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment)) {
77
- parts[parts.length - 1] += segment;
78
- }
79
- else {
80
- parts.push(segment);
81
- }
82
- }
67
+ // but not quite - see explanation in the docs of our custom segment()
68
+ // function.
69
+ parts = segment(value, segmenter);
83
70
  }
84
71
  else {
85
72
  parts = value.match(tokenizeIncludingWhitespace) || [];
@@ -143,7 +130,7 @@ class WordDiff extends Diff {
143
130
  }
144
131
  else {
145
132
  if (insertion || deletion) { // May be false at start of text
146
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change);
133
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, change, options.intlSegmenter);
147
134
  }
148
135
  lastKeep = change;
149
136
  insertion = null;
@@ -151,7 +138,7 @@ class WordDiff extends Diff {
151
138
  }
152
139
  });
153
140
  if (insertion || deletion) {
154
- dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null);
141
+ dedupeWhitespaceInChangeObjects(lastKeep, deletion, insertion, null, options.intlSegmenter);
155
142
  }
156
143
  return changes;
157
144
  }
@@ -167,7 +154,7 @@ export function diffWords(oldStr, newStr, options) {
167
154
  }
168
155
  return wordDiff.diff(oldStr, newStr, options);
169
156
  }
170
- function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep) {
157
+ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep, segmenter) {
171
158
  // Before returning, we tidy up the leading and trailing whitespace of the
172
159
  // change objects to eliminate cases where trailing whitespace in one object
173
160
  // is repeated as leading whitespace in the next.
@@ -210,10 +197,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
210
197
  // * Just a "delete"
211
198
  // We handle the three cases separately.
212
199
  if (deletion && insertion) {
213
- const oldWsPrefix = leadingWs(deletion.value);
214
- const oldWsSuffix = trailingWs(deletion.value);
215
- const newWsPrefix = leadingWs(insertion.value);
216
- const newWsSuffix = trailingWs(insertion.value);
200
+ const [oldWsPrefix, oldWsSuffix] = leadingAndTrailingWs(deletion.value, segmenter);
201
+ const [newWsPrefix, newWsSuffix] = leadingAndTrailingWs(insertion.value, segmenter);
217
202
  if (startKeep) {
218
203
  const commonWsPrefix = longestCommonPrefix(oldWsPrefix, newWsPrefix);
219
204
  startKeep.value = replaceSuffix(startKeep.value, newWsPrefix, commonWsPrefix);
@@ -235,17 +220,17 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
235
220
  // whitespace and deleting duplicate leading whitespace where
236
221
  // present.
237
222
  if (startKeep) {
238
- const ws = leadingWs(insertion.value);
223
+ const ws = leadingWs(insertion.value, segmenter);
239
224
  insertion.value = insertion.value.substring(ws.length);
240
225
  }
241
226
  if (endKeep) {
242
- const ws = leadingWs(endKeep.value);
227
+ const ws = leadingWs(endKeep.value, segmenter);
243
228
  endKeep.value = endKeep.value.substring(ws.length);
244
229
  }
245
230
  // otherwise we've got a deletion and no insertion
246
231
  }
247
232
  else if (startKeep && endKeep) {
248
- const newWsFull = leadingWs(endKeep.value), delWsStart = leadingWs(deletion.value), delWsEnd = trailingWs(deletion.value);
233
+ const newWsFull = leadingWs(endKeep.value, segmenter), [delWsStart, delWsEnd] = leadingAndTrailingWs(deletion.value, segmenter);
249
234
  // Any whitespace that comes straight after startKeep in both the old and
250
235
  // new texts, assign to startKeep and remove from the deletion.
251
236
  const newWsStart = longestCommonPrefix(newWsFull, delWsStart);
@@ -264,8 +249,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
264
249
  // We are at the start of the text. Preserve all the whitespace on
265
250
  // endKeep, and just remove whitespace from the end of deletion to the
266
251
  // extent that it overlaps with the start of endKeep.
267
- const endKeepWsPrefix = leadingWs(endKeep.value);
268
- const deletionWsSuffix = trailingWs(deletion.value);
252
+ const endKeepWsPrefix = leadingWs(endKeep.value, segmenter);
253
+ const deletionWsSuffix = trailingWs(deletion.value, segmenter);
269
254
  const overlap = maximumOverlap(deletionWsSuffix, endKeepWsPrefix);
270
255
  deletion.value = removeSuffix(deletion.value, overlap);
271
256
  }
@@ -273,8 +258,8 @@ function dedupeWhitespaceInChangeObjects(startKeep, deletion, insertion, endKeep
273
258
  // We are at the END of the text. Preserve all the whitespace on
274
259
  // startKeep, and just remove whitespace from the start of deletion to
275
260
  // the extent that it overlaps with the end of startKeep.
276
- const startKeepWsSuffix = trailingWs(startKeep.value);
277
- const deletionWsPrefix = leadingWs(deletion.value);
261
+ const startKeepWsSuffix = trailingWs(startKeep.value, segmenter);
262
+ const deletionWsPrefix = leadingWs(deletion.value, segmenter);
278
263
  const overlap = maximumOverlap(startKeepWsSuffix, deletionWsPrefix);
279
264
  deletion.value = removePrefix(deletion.value, overlap);
280
265
  }
@@ -13,6 +13,18 @@ export declare function hasOnlyWinLineEndings(string: string): boolean;
13
13
  * Returns true if the string consistently uses Unix line endings.
14
14
  */
15
15
  export declare function hasOnlyUnixLineEndings(string: string): boolean;
16
- export declare function trailingWs(string: string): string;
17
- export declare function leadingWs(string: string): string;
16
+ /**
17
+ * Split a string into segments using a word segmenter, merging consecutive
18
+ * segments if they are both whitespace segments. Whitespace segments can
19
+ * appear adjacent to one another for two reasons:
20
+ * - newlines always get their own segment
21
+ * - where a diacritic is attached to a whitespace character in the text, the
22
+ * segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
23
+ * This function therefore runs the segmenter's .segment() method and then
24
+ * merges consecutive segments of whitespace into a single part.
25
+ */
26
+ export declare function segment(string: string, segmenter: Intl.Segmenter): string[];
27
+ export declare function trailingWs(string: string, segmenter?: Intl.Segmenter): string;
28
+ export declare function leadingWs(string: string, segmenter?: Intl.Segmenter): string;
29
+ export declare function leadingAndTrailingWs(string: string, segmenter?: Intl.Segmenter): [string, string];
18
30
  //# sourceMappingURL=string.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/util/string.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAkCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAmBjD;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAIhD"}
1
+ {"version":3,"file":"string.d.ts","sourceRoot":"","sources":["../../src/util/string.ts"],"names":[],"mappings":"AAAA,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAQtE;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,MAAM,CAgBtE;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAK1F;AAED,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAS1F;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,MAAM,CAEtE;AAED,wBAAgB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,MAAM,CAEvE;AAkCD;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE7D;AAED;;GAEG;AACH,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM,GAAG,OAAO,CAE9D;AAED;;;;;;;;;GASG;AACH,wBAAgB,OAAO,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,EAAE,CAW3E;AAgBD,wBAAgB,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAuB7E;AAED,wBAAgB,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GAAG,MAAM,CAQ5E;AAED,wBAAgB,oBAAoB,CAClC,MAAM,EAAE,MAAM,EACd,SAAS,CAAC,EAAE,IAAI,CAAC,SAAS,GACzB,CAAC,MAAM,EAAE,MAAM,CAAC,CAelB"}
@@ -101,7 +101,46 @@ export function hasOnlyWinLineEndings(string) {
101
101
  export function hasOnlyUnixLineEndings(string) {
102
102
  return !string.includes('\r\n') && string.includes('\n');
103
103
  }
104
- export function trailingWs(string) {
104
+ /**
105
+ * Split a string into segments using a word segmenter, merging consecutive
106
+ * segments if they are both whitespace segments. Whitespace segments can
107
+ * appear adjacent to one another for two reasons:
108
+ * - newlines always get their own segment
109
+ * - where a diacritic is attached to a whitespace character in the text, the
110
+ * segment ends after the diacritic, so e.g. " \u0300 " becomes two segments.
111
+ * This function therefore runs the segmenter's .segment() method and then
112
+ * merges consecutive segments of whitespace into a single part.
113
+ */
114
+ export function segment(string, segmenter) {
115
+ const parts = [];
116
+ for (const segmentObj of Array.from(segmenter.segment(string))) {
117
+ const segment = segmentObj.segment;
118
+ if (parts.length && (/\s/).test(parts[parts.length - 1]) && (/\s/).test(segment)) {
119
+ parts[parts.length - 1] += segment;
120
+ }
121
+ else {
122
+ parts.push(segment);
123
+ }
124
+ }
125
+ return parts;
126
+ }
127
+ // The functions below take a `segmenter` argument so that, when called from
128
+ // diffWords when it is using a segmenter, they can use a notion of what
129
+ // constitutes "whitespace" that is consistent with the segmenter.
130
+ //
131
+ // USUALLY this will be identical to the result of the non-segmenter-based
132
+ // logic, but it differs in at least one case: when whitespace characters are
133
+ // modified by diacritics. A word segmenter considers these diacritics to be
134
+ // part of the whitespace, whereas our non-segmenter-based logic does not.
135
+ //
136
+ // Because the segmenter-based approach necessarily requires segmenting the
137
+ // entire string, we offer a leadingAndTrailingWs function to allow getting the
138
+ // whitespace prefix AND whitespace suffix with a single call to the segmenter,
139
+ // for efficiency's sake.
140
+ export function trailingWs(string, segmenter) {
141
+ if (segmenter) {
142
+ return leadingAndTrailingWs(string, segmenter)[1];
143
+ }
105
144
  // Yes, this looks overcomplicated and dumb - why not replace the whole function with
106
145
  // return string.match(/\s*$/)[0]
107
146
  // you ask? Because:
@@ -121,8 +160,25 @@ export function trailingWs(string) {
121
160
  }
122
161
  return string.substring(i + 1);
123
162
  }
124
- export function leadingWs(string) {
163
+ export function leadingWs(string, segmenter) {
164
+ if (segmenter) {
165
+ return leadingAndTrailingWs(string, segmenter)[0];
166
+ }
125
167
  // Thankfully the annoying considerations described in trailingWs don't apply here:
126
168
  const match = string.match(/^\s*/);
127
169
  return match ? match[0] : '';
128
170
  }
171
+ export function leadingAndTrailingWs(string, segmenter) {
172
+ if (!segmenter) {
173
+ return [leadingWs(string), trailingWs(string)];
174
+ }
175
+ if (segmenter.resolvedOptions().granularity != 'word') {
176
+ throw new Error('The segmenter passed must have a granularity of "word"');
177
+ }
178
+ const segments = segment(string, segmenter);
179
+ const firstSeg = segments[0];
180
+ const lastSeg = segments[segments.length - 1];
181
+ const head = (/\s/).test(firstSeg) ? firstSeg : '';
182
+ const tail = (/\s/).test(lastSeg) ? lastSeg : '';
183
+ return [head, tail];
184
+ }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "diff",
3
- "version": "8.0.3",
3
+ "version": "8.0.4",
4
4
  "description": "A JavaScript text diff implementation.",
5
5
  "keywords": [
6
6
  "diff",
@@ -83,35 +83,33 @@
83
83
  "run-mocha": "mocha --require ./runtime 'test/**/*.js'"
84
84
  },
85
85
  "devDependencies": {
86
- "@arethetypeswrong/cli": "^0.17.4",
87
- "@babel/core": "^7.26.9",
88
- "@babel/preset-env": "^7.26.9",
89
- "@babel/register": "^7.25.9",
86
+ "@arethetypeswrong/cli": "^0.18.2",
87
+ "@babel/core": "^7.29.0",
88
+ "@babel/preset-env": "^7.29.2",
89
+ "@babel/register": "^7.28.6",
90
90
  "@colors/colors": "^1.6.0",
91
- "@eslint/js": "^9.25.1",
92
- "babel-loader": "^10.0.0",
93
- "babel-plugin-istanbul": "^7.0.0",
94
- "chai": "^5.2.0",
95
- "cross-env": "^7.0.3",
96
- "eslint": "^9.25.1",
97
- "globals": "^16.0.0",
91
+ "@eslint/js": "^10.0.1",
92
+ "babel-loader": "^10.1.1",
93
+ "babel-plugin-istanbul": "^7.0.1",
94
+ "chai": "^6.2.2",
95
+ "cross-env": "^10.1.0",
96
+ "eslint": "^10.1.0",
97
+ "globals": "^17.4.0",
98
98
  "karma": "^6.4.4",
99
99
  "karma-mocha": "^2.0.1",
100
100
  "karma-mocha-reporter": "^2.2.5",
101
101
  "karma-sourcemap-loader": "^0.4.0",
102
102
  "karma-webpack": "^5.0.1",
103
- "mocha": "^11.1.0",
104
- "nyc": "^17.1.0",
105
- "rollup": "^4.40.1",
106
- "tsd": "^0.32.0",
107
- "typescript": "^5.8.3",
108
- "typescript-eslint": "^8.31.0",
103
+ "mocha": "^11.7.5",
104
+ "nyc": "^18.0.0",
105
+ "rollup": "^4.60.0",
106
+ "tsd": "^0.33.0",
107
+ "typescript": "^5.9.3",
108
+ "typescript-eslint": "^8.57.1",
109
109
  "uglify-js": "^3.19.3",
110
- "webpack": "^5.99.7",
111
- "webpack-dev-server": "^5.2.1"
110
+ "webpack": "^5.105.4",
111
+ "webpack-dev-server": "^5.2.3"
112
112
  },
113
- "optionalDependencies": {},
114
- "dependencies": {},
115
113
  "nyc": {
116
114
  "require": [
117
115
  "@babel/register"
@@ -128,5 +126,5 @@
128
126
  "functions": 100,
129
127
  "statements": 100
130
128
  },
131
- "packageManager": "yarn@1.22.22+sha1.ac34549e6aa8e7ead463a7407e1c7390f61a6610"
132
- }
129
+ "packageManager": "yarn@4.12.0"
130
+ }
@@ -1,5 +1,9 @@
1
1
  # Release Notes
2
2
 
3
+ ## 8.0.4
4
+
5
+ - [#667](https://github.com/kpdecker/jsdiff/pull/667) - **fix another bug in `diffWords` when used with an `Intl.Segmenter`**. If the text to be diffed included a combining mark after a whitespace character (i.e. roughly speaking, an accented space), `diffWords` would previously crash. Now this case is handled correctly.
6
+
3
7
  ## 8.0.3
4
8
 
5
9
  - [#631](https://github.com/kpdecker/jsdiff/pull/631) - **fix support for using an `Intl.Segmenter` with `diffWords`**. This has been almost completely broken since the feature was added in v6.0.0, since it would outright crash on any text that featured two consecutive newlines between a pair of words (a very common case).
@@ -87,6 +91,14 @@ This is a release containing many, *many* breaking changes. The objective of thi
87
91
  - [#535](https://github.com/kpdecker/jsdiff/pull/535) **Passing `newlineIsToken: true` to *patch*-generation functions is no longer allowed.** (Passing it to `diffLines` is still supported - it's only functions like `createPatch` where passing `newlineIsToken` is now an error.) Allowing it to be passed never really made sense, since in cases where the option had any effect on the output at all, the effect tended to be causing a garbled patch to be created that couldn't actually be applied to the source file.
88
92
  - [#539](https://github.com/kpdecker/jsdiff/pull/539) **`diffWords` now takes an optional `intlSegmenter` option** which should be an `Intl.Segmenter` with word-level granularity. This provides better tokenization of text into words than the default behaviour, even for English but especially for some other languages for which the default behaviour is poor.
89
93
 
94
+ ## v5.2.2 - January 2026
95
+
96
+ Only change from 5.2.0 is a backport of the fix to https://github.com/kpdecker/jsdiff/security/advisories/GHSA-73rr-hh4g-fpgx.
97
+
98
+ ## v5.2.1 (deprecated)
99
+
100
+ Accidental release - do not use.
101
+
90
102
  ## v5.2.0
91
103
 
92
104
  [Commits](https://github.com/kpdecker/jsdiff/compare/v5.1.0...v5.2.0)
@@ -113,6 +125,18 @@ This is a release containing many, *many* breaking changes. The objective of thi
113
125
 
114
126
  [Commits](https://github.com/kpdecker/jsdiff/compare/v4.0.1...v5.0.0)
115
127
 
128
+ ## v4.0.4 - January 2026
129
+
130
+ Only change from 4.0.2 is a backport of the fix to https://github.com/kpdecker/jsdiff/security/advisories/GHSA-73rr-hh4g-fpgx.
131
+
132
+ ## v4.0.3 (deprecated)
133
+
134
+ Accidental release - do not use.
135
+
136
+ ## v4.0.2
137
+
138
+ No meaningful changes from v4.0.1 - just removed some cruft that shouldn't've been published.
139
+
116
140
  ## v4.0.1 - January 6th, 2019
117
141
 
118
142
  - Fix main reference path - b826104
@@ -138,6 +162,10 @@ Compatibility notes:
138
162
 
139
163
  [Commits](https://github.com/kpdecker/jsdiff/compare/v3.5.0...v4.0.0)
140
164
 
165
+ ## v3.5.1 - January 2026
166
+
167
+ Only change from 3.5.0 is a backport of the fix to https://github.com/kpdecker/jsdiff/security/advisories/GHSA-73rr-hh4g-fpgx.
168
+
141
169
  ## v3.5.0 - March 4th, 2018
142
170
 
143
171
  - Omit redundant slice in join method of diffArrays - 1023590
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@openclaw/diffs",
3
- "version": "2026.5.25-beta.1",
3
+ "version": "2026.5.26-beta.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@openclaw/diffs",
9
- "version": "2026.5.25-beta.1",
9
+ "version": "2026.5.26-beta.1",
10
10
  "dependencies": {
11
11
  "@pierre/diffs": "1.2.2",
12
12
  "@pierre/theme": "1.0.3",
@@ -212,9 +212,9 @@
212
212
  }
213
213
  },
214
214
  "node_modules/diff": {
215
- "version": "8.0.3",
216
- "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.3.tgz",
217
- "integrity": "sha512-qejHi7bcSD4hQAZE0tNAawRK1ZtafHDmMTMkrrIGgSLl7hTnQHmKCeB45xAcbfTqK2zowkM3j3bHt/4b/ARbYQ==",
215
+ "version": "8.0.4",
216
+ "resolved": "https://registry.npmjs.org/diff/-/diff-8.0.4.tgz",
217
+ "integrity": "sha512-DPi0FmjiSU5EvQV0++GFDOJ9ASQUVFh5kD+OzOnYdi7n3Wpm9hWWGfB/O2blfHcMVTL5WkQXSnRiK9makhrcnw==",
218
218
  "license": "BSD-3-Clause",
219
219
  "engines": {
220
220
  "node": ">=0.3.1"
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openclaw/diffs",
3
- "version": "2026.5.25-beta.1",
3
+ "version": "2026.5.26-beta.1",
4
4
  "description": "OpenClaw diff viewer plugin",
5
5
  "repository": {
6
6
  "type": "git",
@@ -28,10 +28,10 @@
28
28
  "minHostVersion": ">=2026.4.30"
29
29
  },
30
30
  "compat": {
31
- "pluginApi": ">=2026.5.25-beta.1"
31
+ "pluginApi": ">=2026.5.26-beta.1"
32
32
  },
33
33
  "build": {
34
- "openclawVersion": "2026.5.25-beta.1",
34
+ "openclawVersion": "2026.5.26-beta.1",
35
35
  "staticAssets": [
36
36
  {
37
37
  "source": "./assets/viewer-runtime.js",
@@ -55,7 +55,7 @@
55
55
  "skills/**"
56
56
  ],
57
57
  "peerDependencies": {
58
- "openclaw": ">=2026.5.25-beta.1"
58
+ "openclaw": ">=2026.5.26-beta.1"
59
59
  },
60
60
  "peerDependenciesMeta": {
61
61
  "openclaw": {