@x-oasis/diff-match-patch 0.1.3 → 0.2.0

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.
@@ -1,11 +1,11 @@
1
1
 
2
- > @x-oasis/diff-match-patch@0.1.3 build /home/runner/work/x-oasis/x-oasis/packages/diff/diff-match-patch
2
+ > @x-oasis/diff-match-patch@0.2.0 build /home/runner/work/x-oasis/x-oasis/packages/diff/diff-match-patch
3
3
  > tsdx build --tsconfig tsconfig.build.json
4
4
 
5
5
  @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
6
6
  @rollup/plugin-replace: 'preventAssignment' currently defaults to false. It is recommended to set this option to `true`, as the next major version will default this option to `true`.
7
7
  ⠙ Creating entry file
8
- ✓ Creating entry file 3.6 secs
8
+ ✓ Creating entry file 3.4 secs
9
9
  ⠙ Building modules
10
10
  ⠹ Building modules
11
11
  ⠸ Building modules
@@ -13,7 +13,9 @@
13
13
  ⠴ Building modules
14
14
  ⠦ Building modules
15
15
  ⠧ Building modules
16
+ ⠇ Building modules
17
+ ⠏ Building modules
16
18
  [tsdx]: Your rootDir is currently set to "./". Please change your rootDir to "./src".
17
19
  TSDX has deprecated setting tsconfig.compilerOptions.rootDir to "./" as it caused buggy output for declarationMaps and more.
18
20
  You may also need to change your include to remove "test", which also caused declarations to be unnecessarily created for test files.
19
- ✓ Building modules 7.3 secs
21
+ ✓ Building modules 6.8 secs
package/CHANGELOG.md CHANGED
@@ -1,5 +1,34 @@
1
1
  # @x-oasis/diff-match-patch
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c16e063: bump version
8
+
9
+ ### Patch Changes
10
+
11
+ - f7a393b: bump diff range
12
+ - b666c87: bump next
13
+ - a33ef8e: bump version
14
+ - 8256c76: bump version
15
+ - 33888cc: permission
16
+ - Updated dependencies [f7a393b]
17
+ - Updated dependencies [b666c87]
18
+ - Updated dependencies [a33ef8e]
19
+ - Updated dependencies [8256c76]
20
+ - Updated dependencies [33888cc]
21
+ - Updated dependencies [c16e063]
22
+ - @x-oasis/log@0.2.0
23
+
24
+ ## 0.1.4
25
+
26
+ ### Patch Changes
27
+
28
+ - 0ddda70: fix: diff example
29
+ - Updated dependencies [0ddda70]
30
+ - @x-oasis/log@0.1.4
31
+
3
32
  ## 0.1.3
4
33
 
5
34
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"diff-match-patch.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","DIFF_DELETE","DIFF_INSERT","DIFF_EQUAL","FileRestoreManager","originalContent","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","op","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","text","textLength","nextDiff","rangeStart","rangeEnd","offsetInRange","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange","manager"],"mappings":"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"}
1
+ {"version":3,"file":"diff-match-patch.cjs.development.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n * @param options.originalContent 原始文件内容\n * @param options.currentContent 最新文件内容\n * @param options.startOffset 开始偏移(基于最新文件)\n * @param options.endOffset 结束偏移(基于最新文件)\n * @returns 恢复后的文件内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","DIFF_DELETE","DIFF_INSERT","DIFF_EQUAL","FileRestoreManager","originalContent","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","op","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","text","textLength","nextDiff","rangeStart","rangeEnd","offsetInRange","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange","manager"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"diff-match-patch.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","FileRestoreManager","originalContent","this","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","textLength","nextDiff","rangeEnd","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange"],"mappings":"gIAGMA,EAAc,IAAIC,SAAO,CAAEC,cAAe,uBAenCC,aAIX,SAAAA,EAAYC,GACVC,KAAKD,gBAAkBA,EACvBC,KAAKC,IAAM,IAAIC,mBACfP,EAAYQ,MAAM,6BAA8B,CAC9CC,eAAgBL,EAAgBM,SAEnC,IAAAC,EAAAR,EAAAS,UA2SA,OA3SAD,EAQDE,aAAA,SAAaC,EAAwBC,GACnC,IAAQC,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAQrB,GANAjB,EAAYQ,MAAM,sBAAuB,CACvCQ,YAAAA,EACAC,UAAAA,EACAC,cAAeJ,EAAeJ,SAG5BM,EAAc,GAAKC,EAAY,GAAKD,EAAcC,EACpD,MAAM,IAAIE,MAAM,wBAGlB,GACEH,EAAcF,EAAeJ,QAC7BO,EAAYH,EAAeJ,OAE3B,MAAM,IAAIS,MAAM,+CAIlB,IAAMC,EAAQf,KAAKC,IAAIe,UAAUhB,KAAKD,gBAAiBU,GACvDT,KAAKC,IAAIgB,qBAAqBF,GAE9BpB,EAAYQ,MAAM,iBAAkB,CAClCe,UAAWH,EAAMV,OACjBc,WAAYJ,EAAMK,MAAK,SAAAC,GAAI,OAvDd,IAuDcA,UAI7B,IAAMC,EAAgBtB,KAAKuB,0BACzBR,EACAJ,EACAC,GAIIY,EAAuBxB,KAAKD,gBAAgB0B,UAChDH,EAAcI,MACdJ,EAAcK,KAIVC,EAAsBnB,EAAegB,UACzCd,EACAC,GAGIiB,EAAoBD,IAAwBJ,EAClD7B,EAAYQ,MAAM,yBAA0B,CAC1CQ,YAAAA,EACAC,UAAAA,EACAU,cAAe,CAAEI,MAAOJ,EAAcI,MAAOC,IAAKL,EAAcK,KAChEG,oBACEF,EAAoBvB,OAAS,GACtBuB,EAAoBG,MAAM,EAAG,UAASH,EAAoBG,OAC1D,IAEHH,EACNI,qBACER,EAAqBnB,OAAS,GACvBmB,EAAqBO,MACtB,EACA,UACKP,EAAqBO,OAAO,IACnCP,EACNK,kBAAAA,IAIF,IAAMI,EACJxB,EAAegB,UAAU,EAAGd,GAC5Ba,EACAf,EAAegB,UAAUb,GAO3B,OALAjB,EAAYQ,MAAM,oBAAqB,CACrC+B,eAAgBD,EAAgB5B,OAChC8B,eAAgBN,IAGXI,GACR3B,EAKOiB,0BAAA,SACNR,EACAqB,EACAC,GAEA1C,EAAYQ,MAAM,mCAAoC,CACpDiC,aAAAA,EACAC,WAAAA,EACAnB,UAAWH,EAAMV,SAQnB,IALA,IAAIiC,EAAgB,EAChBC,EAAiB,EACjBC,EAA+B,KAC/BC,EAA6B,KAExBC,EAAI,EAAGA,EAAI3B,EAAMV,OAAQqC,IAAK,CACrC,IAAAC,EAA0B5B,EAAM2B,GAAzBE,EAASD,KACVE,EADgBF,KACEtC,OAClByC,EAAWJ,EAAI3B,EAAMV,OAAS,EAAIU,EAAM2B,EAAI,GAAK,KAEvD,GAxIa,IAwITE,EAA0B,CAE5B,IACMG,EAAWT,EAAgBO,EAIb,OAAlBL,GACAJ,GANiBE,GAOjBF,EAAeW,IAGfP,EAAgBD,GADMH,EATLE,IAcD,OAAhBG,GACAJ,EAfiBC,GAgBjBD,GAAcU,IAGdN,EAAcF,GADQF,EAlBLC,GAkCfD,IAAeU,GACfD,IA/KQ,IAgLRA,EAAS,KAETL,EAAcF,EAAiBM,EAAaC,EAAS,GAAGzC,SAI5DiC,GAAiBO,EACjBN,GAAkBM,OACb,GAvLO,IAuLHD,EAA2B,CAEpC,IACMG,EAAWT,EAAgBO,EAIb,OAAlBL,GACAJ,GANiBE,GAOjBF,EAAeW,IAEfP,EAAgBD,GAIA,OAAhBE,GACAJ,EAdiBC,GAejBD,GAAcU,IAEdN,EAAcF,GAGhBD,GAAiBO,OA9ML,IAgNHD,KAGa,OAAlBJ,GAA0BJ,IAAiBE,GAGlB,OAAlBE,GAA0BJ,EAAeE,KADlDE,EAAgBD,GAOE,OAAhBE,GAAwBJ,IAAeC,EAEzCG,EAAcF,EAAiBM,EACN,OAAhBJ,GAAwBJ,EAAaC,IAE9CG,EAAcF,GAGhBA,GAAkBM,GAKpB,GAAsB,OAAlBL,GAA0C,OAAhBC,EAC5B,MAKkB,OAAlBD,IACFA,EAAgBD,GAEE,OAAhBE,IACFA,EAAcF,GAGhB,IAAMS,EAAS,CAAEtB,MAAOc,EAAeb,IAAKc,GAE5C,OADA9C,EAAYQ,MAAM,mCAAoC6C,GAC/CA,GACR1C,EAKD2C,mBAAA,WACE,OAAOjD,KAAKD,iBACbO,EAKD4C,sBAAA,SAAsBC,GACpBnD,KAAKD,gBAAkBoD,GACxB7C,EAKD8C,kBAAA,SACE3C,EACAC,GASA,IAAQC,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAErBjB,EAAYQ,MAAM,2BAA4B,CAC5CQ,YAAAA,EACAC,UAAAA,EACAC,cAAeJ,EAAeJ,SAIhC,IAAMU,EAAQf,KAAKC,IAAIe,UAAUhB,KAAKD,gBAAiBU,GACvDT,KAAKC,IAAIgB,qBAAqBF,GAG9B,IAAMO,EAAgBtB,KAAKuB,0BACzBR,EACAJ,EACAC,GAGIY,EAAuBxB,KAAKD,gBAAgB0B,UAChDH,EAAcI,MACdJ,EAAcK,KAEVC,EAAsBnB,EAAegB,UACzCd,EACAC,GAGIoC,EAAS,CACb7B,WAAYnB,KAAKD,kBAAoBU,EACrCa,cAAAA,EACA+B,aAAc,CAAE3B,MAAOf,EAAagB,IAAKf,GACzCb,gBAAiByB,EACjBf,eAAgBmB,EAChB0B,WAAY9B,IAAyBI,GAQvC,OANAjC,EAAYQ,MAAM,2BAA4B,CAC5CgB,WAAY6B,EAAO7B,WACnBmC,WAAYN,EAAOM,WACnBhC,cAAe0B,EAAO1B,cACtB+B,aAAcL,EAAOK,eAEhBL,GACRlD,kFAM0BY,GAM3B,IAAQX,EAA4DW,EAA5DX,gBAAiBU,EAA2CC,EAA3CD,eAAgBE,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAQtD,OAPAjB,EAAYQ,MAAM,mCAAoC,CACpDQ,YAAAA,EACAC,UAAAA,EACAR,eAAgBL,EAAgBM,OAChCQ,cAAeJ,EAAeJ,SAEhB,IAAIP,EAAmBC,GACxBS,aAAaC,EAAgB,CAAEE,YAAAA,EAAaC,UAAAA"}
1
+ {"version":3,"file":"diff-match-patch.cjs.production.min.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n * @param options.originalContent 原始文件内容\n * @param options.currentContent 最新文件内容\n * @param options.startOffset 开始偏移(基于最新文件)\n * @param options.endOffset 结束偏移(基于最新文件)\n * @returns 恢复后的文件内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","FileRestoreManager","originalContent","this","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","textLength","nextDiff","rangeEnd","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange"],"mappings":"gIAGMA,EAAc,IAAIC,SAAO,CAAEC,cAAe,uBAenCC,aAIX,SAAAA,EAAYC,GACVC,KAAKD,gBAAkBA,EACvBC,KAAKC,IAAM,IAAIC,mBACfP,EAAYQ,MAAM,6BAA8B,CAC9CC,eAAgBL,EAAgBM,SAEnC,IAAAC,EAAAR,EAAAS,UA2SA,OA3SAD,EAQDE,aAAA,SAAaC,EAAwBC,GACnC,IAAQC,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAQrB,GANAjB,EAAYQ,MAAM,sBAAuB,CACvCQ,YAAAA,EACAC,UAAAA,EACAC,cAAeJ,EAAeJ,SAG5BM,EAAc,GAAKC,EAAY,GAAKD,EAAcC,EACpD,MAAM,IAAIE,MAAM,wBAGlB,GACEH,EAAcF,EAAeJ,QAC7BO,EAAYH,EAAeJ,OAE3B,MAAM,IAAIS,MAAM,+CAIlB,IAAMC,EAAQf,KAAKC,IAAIe,UAAUhB,KAAKD,gBAAiBU,GACvDT,KAAKC,IAAIgB,qBAAqBF,GAE9BpB,EAAYQ,MAAM,iBAAkB,CAClCe,UAAWH,EAAMV,OACjBc,WAAYJ,EAAMK,MAAK,SAAAC,GAAI,OAvDd,IAuDcA,UAI7B,IAAMC,EAAgBtB,KAAKuB,0BACzBR,EACAJ,EACAC,GAIIY,EAAuBxB,KAAKD,gBAAgB0B,UAChDH,EAAcI,MACdJ,EAAcK,KAIVC,EAAsBnB,EAAegB,UACzCd,EACAC,GAGIiB,EAAoBD,IAAwBJ,EAClD7B,EAAYQ,MAAM,yBAA0B,CAC1CQ,YAAAA,EACAC,UAAAA,EACAU,cAAe,CAAEI,MAAOJ,EAAcI,MAAOC,IAAKL,EAAcK,KAChEG,oBACEF,EAAoBvB,OAAS,GACtBuB,EAAoBG,MAAM,EAAG,UAASH,EAAoBG,OAC1D,IAEHH,EACNI,qBACER,EAAqBnB,OAAS,GACvBmB,EAAqBO,MACtB,EACA,UACKP,EAAqBO,OAAO,IACnCP,EACNK,kBAAAA,IAIF,IAAMI,EACJxB,EAAegB,UAAU,EAAGd,GAC5Ba,EACAf,EAAegB,UAAUb,GAO3B,OALAjB,EAAYQ,MAAM,oBAAqB,CACrC+B,eAAgBD,EAAgB5B,OAChC8B,eAAgBN,IAGXI,GACR3B,EAKOiB,0BAAA,SACNR,EACAqB,EACAC,GAEA1C,EAAYQ,MAAM,mCAAoC,CACpDiC,aAAAA,EACAC,WAAAA,EACAnB,UAAWH,EAAMV,SAQnB,IALA,IAAIiC,EAAgB,EAChBC,EAAiB,EACjBC,EAA+B,KAC/BC,EAA6B,KAExBC,EAAI,EAAGA,EAAI3B,EAAMV,OAAQqC,IAAK,CACrC,IAAAC,EAA0B5B,EAAM2B,GAAzBE,EAASD,KACVE,EADgBF,KACEtC,OAClByC,EAAWJ,EAAI3B,EAAMV,OAAS,EAAIU,EAAM2B,EAAI,GAAK,KAEvD,GAxIa,IAwITE,EAA0B,CAE5B,IACMG,EAAWT,EAAgBO,EAIb,OAAlBL,GACAJ,GANiBE,GAOjBF,EAAeW,IAGfP,EAAgBD,GADMH,EATLE,IAcD,OAAhBG,GACAJ,EAfiBC,GAgBjBD,GAAcU,IAGdN,EAAcF,GADQF,EAlBLC,GAkCfD,IAAeU,GACfD,IA/KQ,IAgLRA,EAAS,KAETL,EAAcF,EAAiBM,EAAaC,EAAS,GAAGzC,SAI5DiC,GAAiBO,EACjBN,GAAkBM,OACb,GAvLO,IAuLHD,EAA2B,CAEpC,IACMG,EAAWT,EAAgBO,EAIb,OAAlBL,GACAJ,GANiBE,GAOjBF,EAAeW,IAEfP,EAAgBD,GAIA,OAAhBE,GACAJ,EAdiBC,GAejBD,GAAcU,IAEdN,EAAcF,GAGhBD,GAAiBO,OA9ML,IAgNHD,KAGa,OAAlBJ,GAA0BJ,IAAiBE,GAGlB,OAAlBE,GAA0BJ,EAAeE,KADlDE,EAAgBD,GAOE,OAAhBE,GAAwBJ,IAAeC,EAEzCG,EAAcF,EAAiBM,EACN,OAAhBJ,GAAwBJ,EAAaC,IAE9CG,EAAcF,GAGhBA,GAAkBM,GAKpB,GAAsB,OAAlBL,GAA0C,OAAhBC,EAC5B,MAKkB,OAAlBD,IACFA,EAAgBD,GAEE,OAAhBE,IACFA,EAAcF,GAGhB,IAAMS,EAAS,CAAEtB,MAAOc,EAAeb,IAAKc,GAE5C,OADA9C,EAAYQ,MAAM,mCAAoC6C,GAC/CA,GACR1C,EAKD2C,mBAAA,WACE,OAAOjD,KAAKD,iBACbO,EAKD4C,sBAAA,SAAsBC,GACpBnD,KAAKD,gBAAkBoD,GACxB7C,EAKD8C,kBAAA,SACE3C,EACAC,GASA,IAAQC,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAErBjB,EAAYQ,MAAM,2BAA4B,CAC5CQ,YAAAA,EACAC,UAAAA,EACAC,cAAeJ,EAAeJ,SAIhC,IAAMU,EAAQf,KAAKC,IAAIe,UAAUhB,KAAKD,gBAAiBU,GACvDT,KAAKC,IAAIgB,qBAAqBF,GAG9B,IAAMO,EAAgBtB,KAAKuB,0BACzBR,EACAJ,EACAC,GAGIY,EAAuBxB,KAAKD,gBAAgB0B,UAChDH,EAAcI,MACdJ,EAAcK,KAEVC,EAAsBnB,EAAegB,UACzCd,EACAC,GAGIoC,EAAS,CACb7B,WAAYnB,KAAKD,kBAAoBU,EACrCa,cAAAA,EACA+B,aAAc,CAAE3B,MAAOf,EAAagB,IAAKf,GACzCb,gBAAiByB,EACjBf,eAAgBmB,EAChB0B,WAAY9B,IAAyBI,GAQvC,OANAjC,EAAYQ,MAAM,2BAA4B,CAC5CgB,WAAY6B,EAAO7B,WACnBmC,WAAYN,EAAOM,WACnBhC,cAAe0B,EAAO1B,cACtB+B,aAAcL,EAAOK,eAEhBL,GACRlD,kFAW0BY,GAM3B,IAAQX,EAA4DW,EAA5DX,gBAAiBU,EAA2CC,EAA3CD,eAAgBE,EAA2BD,EAA3BC,YAAaC,EAAcF,EAAdE,UAQtD,OAPAjB,EAAYQ,MAAM,mCAAoC,CACpDQ,YAAAA,EACAC,UAAAA,EACAR,eAAgBL,EAAgBM,OAChCQ,cAAeJ,EAAeJ,SAEhB,IAAIP,EAAmBC,GACxBS,aAAaC,EAAgB,CAAEE,YAAAA,EAAaC,UAAAA"}
@@ -1 +1 @@
1
- {"version":3,"file":"diff-match-patch.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","DIFF_DELETE","DIFF_INSERT","DIFF_EQUAL","FileRestoreManager","originalContent","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","op","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","text","textLength","nextDiff","rangeStart","rangeEnd","offsetInRange","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange","manager"],"mappings":"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"}
1
+ {"version":3,"file":"diff-match-patch.esm.js","sources":["../src/index.ts"],"sourcesContent":["import { Logger } from '@x-oasis/log';\nimport { diff_match_patch } from 'diff-match-patch';\n\nconst debugLogger = new Logger({ defaultPrefix: '[diff-match-patch]' });\n\nconst DIFF_DELETE = -1;\nconst DIFF_INSERT = 1;\nconst DIFF_EQUAL = 0;\n\nexport interface RestoreRangeOptions {\n startOffset: number;\n endOffset: number;\n}\n\n/**\n * 文件恢复管理器\n * 用于将最新文件中的指定 range 恢复到原始版本\n */\nexport class FileRestoreManager {\n private originalContent: string;\n private dmp: diff_match_patch;\n\n constructor(originalContent: string) {\n this.originalContent = originalContent;\n this.dmp = new diff_match_patch();\n debugLogger.debug('FileRestoreManager created', {\n originalLength: originalContent.length,\n });\n }\n\n /**\n * 将最新文件中指定 offset range 的内容恢复到原始版本\n * @param currentContent 最新文件内容\n * @param options 包含 startOffset 和 endOffset 的选项\n * @returns 恢复后的文件内容\n */\n restoreRange(currentContent: string, options: RestoreRangeOptions): string {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('restoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n if (startOffset < 0 || endOffset < 0 || startOffset > endOffset) {\n throw new Error('Invalid offset range');\n }\n\n if (\n startOffset > currentContent.length ||\n endOffset > currentContent.length\n ) {\n throw new Error('Offset range exceeds current content length');\n }\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n debugLogger.debug('diffs computed', {\n diffCount: diffs.length,\n hasChanges: diffs.some(([op]) => op !== DIFF_EQUAL),\n });\n\n // 找到最新文件中 startOffset 和 endOffset 对应的原始文件中的位置\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n // 从原始文件中提取对应范围的内容\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n\n // 获取当前 range 的内容(用于调试)\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const contentWillChange = currentRangeContent !== originalRangeContent;\n debugLogger.debug('range mapping resolved', {\n startOffset,\n endOffset,\n originalRange: { start: originalRange.start, end: originalRange.end },\n currentRangePreview:\n currentRangeContent.length > 80\n ? `${currentRangeContent.slice(0, 40)}...${currentRangeContent.slice(\n -40\n )}`\n : currentRangeContent,\n originalRangePreview:\n originalRangeContent.length > 80\n ? `${originalRangeContent.slice(\n 0,\n 40\n )}...${originalRangeContent.slice(-40)}`\n : originalRangeContent,\n contentWillChange,\n });\n\n // 替换最新文件中指定 range 的内容\n const restoredContent =\n currentContent.substring(0, startOffset) +\n originalRangeContent +\n currentContent.substring(endOffset);\n\n debugLogger.debug('restoreRange done', {\n restoredLength: restoredContent.length,\n contentChanged: contentWillChange,\n });\n\n return restoredContent;\n }\n\n /**\n * 将最新文件中的 offset range 映射到原始文件中的 offset range\n */\n private mapCurrentRangeToOriginal(\n diffs: Array<[number, string]>,\n currentStart: number,\n currentEnd: number\n ): { start: number; end: number } {\n debugLogger.debug('mapCurrentRangeToOriginal called', {\n currentStart,\n currentEnd,\n diffCount: diffs.length,\n });\n\n let currentOffset = 0; // 当前在最新文件中的 offset\n let originalOffset = 0; // 当前在原始文件中的 offset\n let originalStart: number | null = null;\n let originalEnd: number | null = null;\n\n for (let i = 0; i < diffs.length; i++) {\n const [operation, text] = diffs[i];\n const textLength = text.length;\n const nextDiff = i < diffs.length - 1 ? diffs[i + 1] : null;\n\n if (operation === DIFF_EQUAL) {\n // 相等部分:两个文件的 offset 同步增加\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 检查 currentStart 是否在这个 EQUAL 区间内\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n const offsetInRange = currentStart - rangeStart;\n originalStart = originalOffset + offsetInRange;\n }\n // 检查 currentEnd 是否在这个 EQUAL 区间内\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n const offsetInRange = currentEnd - rangeStart;\n originalEnd = originalOffset + offsetInRange;\n\n // 特殊处理:如果 currentEnd 正好在 EQUAL 的结束位置,且下一个 diff 是 DELETE\n // 需要包含被删除的内容,以便正确恢复\n //\n // 示例:\n // 原始文件: \"...禁用按钮</button>...\"\n // 最新文件: \"...禁用</button>...\"\n // diff: [EQUAL: \"...禁用\"], [DELETE: \"按钮\"], [EQUAL: \"</button>...\"]\n //\n // 如果用户选择最新文件的 offset 1512-1514(\"禁用\"),\n // 应该恢复为原始文件的 offset 1512-1516(\"禁用按钮\")\n //\n // 如果不包含 DELETE 的内容,只会恢复到 \"禁用\",而不是 \"禁用按钮\"\n if (\n currentEnd === rangeEnd &&\n nextDiff &&\n nextDiff[0] === DIFF_DELETE\n ) {\n originalEnd = originalOffset + textLength + nextDiff[1].length;\n }\n }\n\n currentOffset += textLength;\n originalOffset += textLength;\n } else if (operation === DIFF_INSERT) {\n // 插入部分:只在新文件中存在\n const rangeStart = currentOffset;\n const rangeEnd = currentOffset + textLength;\n\n // 如果 currentStart 在插入内容中,映射到插入前的原始位置\n if (\n originalStart === null &&\n currentStart >= rangeStart &&\n currentStart < rangeEnd\n ) {\n originalStart = originalOffset;\n }\n // 如果 currentEnd 在插入内容中,映射到插入前的原始位置\n if (\n originalEnd === null &&\n currentEnd > rangeStart &&\n currentEnd <= rangeEnd\n ) {\n originalEnd = originalOffset;\n }\n\n currentOffset += textLength;\n // INSERT 不增加 originalOffset\n } else if (operation === DIFF_DELETE) {\n // 删除部分:只在原始文件中存在\n // 如果 currentStart 正好在删除位置之前,需要包含删除的内容\n if (originalStart === null && currentStart === currentOffset) {\n // currentStart 正好在删除位置,映射到删除开始的位置\n originalStart = originalOffset;\n } else if (originalStart === null && currentStart < currentOffset) {\n // currentStart 在删除位置之前,映射到删除开始的位置\n originalStart = originalOffset;\n }\n\n // 如果 currentEnd 正好在删除位置之前,需要包含删除的内容\n if (originalEnd === null && currentEnd === currentOffset) {\n // currentEnd 正好在删除位置,需要包含整个删除的内容\n originalEnd = originalOffset + textLength;\n } else if (originalEnd === null && currentEnd < currentOffset) {\n // currentEnd 在删除位置之前,映射到删除开始的位置\n originalEnd = originalOffset;\n }\n\n originalOffset += textLength;\n // DELETE 不增加 currentOffset\n }\n\n // 如果两个位置都找到了,可以提前退出\n if (originalStart !== null && originalEnd !== null) {\n break;\n }\n }\n\n // 处理边界情况:如果 range 在所有 diff 之后\n if (originalStart === null) {\n originalStart = originalOffset;\n }\n if (originalEnd === null) {\n originalEnd = originalOffset;\n }\n\n const result = { start: originalStart, end: originalEnd };\n debugLogger.debug('mapCurrentRangeToOriginal result', result);\n return result;\n }\n\n /**\n * 获取原始文件内容\n */\n getOriginalContent(): string {\n return this.originalContent;\n }\n\n /**\n * 更新原始文件内容\n */\n updateOriginalContent(newOriginalContent: string): void {\n this.originalContent = newOriginalContent;\n }\n\n /**\n * 调试方法:分析指定 range 的恢复情况\n */\n debugRestoreRange(\n currentContent: string,\n options: RestoreRangeOptions\n ): {\n hasChanges: boolean;\n originalRange: { start: number; end: number };\n currentRange: { start: number; end: number };\n originalContent: string;\n currentContent: string;\n willChange: boolean;\n } {\n const { startOffset, endOffset } = options;\n\n debugLogger.debug('debugRestoreRange called', {\n startOffset,\n endOffset,\n currentLength: currentContent.length,\n });\n\n // 计算差异\n const diffs = this.dmp.diff_main(this.originalContent, currentContent);\n this.dmp.diff_cleanupSemantic(diffs);\n\n // 找到映射\n const originalRange = this.mapCurrentRangeToOriginal(\n diffs,\n startOffset,\n endOffset\n );\n\n const originalRangeContent = this.originalContent.substring(\n originalRange.start,\n originalRange.end\n );\n const currentRangeContent = currentContent.substring(\n startOffset,\n endOffset\n );\n\n const result = {\n hasChanges: this.originalContent !== currentContent,\n originalRange,\n currentRange: { start: startOffset, end: endOffset },\n originalContent: originalRangeContent,\n currentContent: currentRangeContent,\n willChange: originalRangeContent !== currentRangeContent,\n };\n debugLogger.debug('debugRestoreRange result', {\n hasChanges: result.hasChanges,\n willChange: result.willChange,\n originalRange: result.originalRange,\n currentRange: result.currentRange,\n });\n return result;\n }\n}\n\n/**\n * 便捷函数:直接恢复指定 range 的内容\n * @param options.originalContent 原始文件内容\n * @param options.currentContent 最新文件内容\n * @param options.startOffset 开始偏移(基于最新文件)\n * @param options.endOffset 结束偏移(基于最新文件)\n * @returns 恢复后的文件内容\n */\nexport function restoreRange(options: {\n originalContent: string;\n currentContent: string;\n startOffset: number;\n endOffset: number;\n}): string {\n const { originalContent, currentContent, startOffset, endOffset } = options;\n debugLogger.debug('restoreRange (standalone) called', {\n startOffset,\n endOffset,\n originalLength: originalContent.length,\n currentLength: currentContent.length,\n });\n const manager = new FileRestoreManager(originalContent);\n return manager.restoreRange(currentContent, { startOffset, endOffset });\n}\n\nexport default FileRestoreManager;\n"],"names":["debugLogger","Logger","defaultPrefix","DIFF_DELETE","DIFF_INSERT","DIFF_EQUAL","FileRestoreManager","originalContent","dmp","diff_match_patch","debug","originalLength","length","_proto","prototype","restoreRange","currentContent","options","startOffset","endOffset","currentLength","Error","diffs","diff_main","diff_cleanupSemantic","diffCount","hasChanges","some","_ref","op","originalRange","mapCurrentRangeToOriginal","originalRangeContent","substring","start","end","currentRangeContent","contentWillChange","currentRangePreview","slice","originalRangePreview","restoredContent","restoredLength","contentChanged","currentStart","currentEnd","currentOffset","originalOffset","originalStart","originalEnd","i","_diffs$i","operation","text","textLength","nextDiff","rangeStart","rangeEnd","offsetInRange","result","getOriginalContent","updateOriginalContent","newOriginalContent","debugRestoreRange","currentRange","willChange","manager"],"mappings":"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"}
@@ -1,5 +1,17 @@
1
1
 
2
- > diff-match-patch-example@0.1.3 build /home/runner/work/x-oasis/x-oasis/packages/diff/diff-match-patch/examples
3
- > echo 'build'
2
+ > diff-match-patch-example@0.2.0 build /home/runner/work/x-oasis/x-oasis/packages/diff/diff-match-patch/examples
3
+ > vite build
4
4
 
5
- build
5
+ vite v4.1.4 building for production...
6
+ transforming...
7
+ ✓ 270 modules transformed.
8
+ rendering chunks...
9
+ computing gzip size...
10
+ dist/index.html  0.52 kB
11
+ dist/assets/index-2c456c5a.css  21.67 kB │ gzip: 3.94 kB
12
+ dist/assets/index-022e0260.js 1,245.48 kB │ gzip: 393.15 kB
13
+ 
14
+ (!) Some chunks are larger than 500 kBs after minification. Consider:
15
+ - Using dynamic import() to code-split the application
16
+ - Use build.rollupOptions.output.manualChunks to improve chunking: https://rollupjs.org/configuration-options/#output-manualchunks
17
+ - Adjust chunk size limit for this warning via build.chunkSizeWarningLimit.
@@ -1,5 +1,25 @@
1
1
  # diff-match-patch-example
2
2
 
3
+ ## 0.2.0
4
+
5
+ ### Minor Changes
6
+
7
+ - c16e063: bump version
8
+
9
+ ### Patch Changes
10
+
11
+ - f7a393b: bump diff range
12
+ - b666c87: bump next
13
+ - a33ef8e: bump version
14
+ - 8256c76: bump version
15
+ - 33888cc: permission
16
+
17
+ ## 0.1.4
18
+
19
+ ### Patch Changes
20
+
21
+ - 0ddda70: fix: diff example
22
+
3
23
  ## 0.1.3
4
24
 
5
25
  ### Patch Changes
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "diff-match-patch-example",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "private": true,
5
5
  "type": "module",
6
6
  "scripts": {
7
7
  "dev": "vite",
8
- "build": "echo 'build'",
8
+ "build": "vite build",
9
9
  "preview": "vite preview"
10
10
  },
11
11
  "dependencies": {
@@ -21,6 +21,10 @@ export default defineConfig({
21
21
  resolve: {
22
22
  alias: {
23
23
  '@x-oasis/diff-match-patch': path.resolve(__dirname, '../src/index.ts'),
24
+ '@x-oasis/log': path.resolve(
25
+ __dirname,
26
+ '../../../error/log/src/index.ts'
27
+ ),
24
28
  },
25
29
  },
26
30
  server: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@x-oasis/diff-match-patch",
3
- "version": "0.1.3",
3
+ "version": "0.2.0",
4
4
  "description": "Restore file content to original version based on offset range",
5
5
  "main": "dist/index.js",
6
6
  "typings": "dist/index.d.ts",
@@ -15,7 +15,7 @@
15
15
  },
16
16
  "dependencies": {
17
17
  "diff-match-patch": "^1.0.5",
18
- "@x-oasis/log": "0.1.3"
18
+ "@x-oasis/log": "0.2.0"
19
19
  },
20
20
  "scripts": {
21
21
  "build": "tsdx build --tsconfig tsconfig.build.json",
package/src/index.ts CHANGED
@@ -330,6 +330,11 @@ export class FileRestoreManager {
330
330
 
331
331
  /**
332
332
  * 便捷函数:直接恢复指定 range 的内容
333
+ * @param options.originalContent 原始文件内容
334
+ * @param options.currentContent 最新文件内容
335
+ * @param options.startOffset 开始偏移(基于最新文件)
336
+ * @param options.endOffset 结束偏移(基于最新文件)
337
+ * @returns 恢复后的文件内容
333
338
  */
334
339
  export function restoreRange(options: {
335
340
  originalContent: string;