@openclaw/diffs 2026.5.24-beta.2 → 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.
- package/node_modules/@pierre/diffs/dist/components/File.d.ts.map +1 -1
- package/node_modules/@pierre/diffs/dist/components/UnresolvedFile.d.ts.map +1 -1
- package/node_modules/@pierre/diffs/dist/renderers/DiffHunksRenderer.js +7 -4
- package/node_modules/@pierre/diffs/dist/renderers/DiffHunksRenderer.js.map +1 -1
- package/node_modules/@pierre/diffs/dist/renderers/FileRenderer.js +8 -5
- package/node_modules/@pierre/diffs/dist/renderers/FileRenderer.js.map +1 -1
- package/node_modules/@pierre/diffs/package.json +1 -1
- package/node_modules/diff/CONTRIBUTING.md +1 -1
- package/node_modules/diff/dist/diff.js +73 -32
- package/node_modules/diff/dist/diff.min.js +1 -1
- package/node_modules/diff/libcjs/diff/word.d.ts.map +1 -1
- package/node_modules/diff/libcjs/diff/word.js +15 -31
- package/node_modules/diff/libcjs/util/string.d.ts +14 -2
- package/node_modules/diff/libcjs/util/string.d.ts.map +1 -1
- package/node_modules/diff/libcjs/util/string.js +61 -2
- package/node_modules/diff/libesm/diff/word.d.ts.map +1 -1
- package/node_modules/diff/libesm/diff/word.js +16 -31
- package/node_modules/diff/libesm/util/string.d.ts +14 -2
- package/node_modules/diff/libesm/util/string.d.ts.map +1 -1
- package/node_modules/diff/libesm/util/string.js +58 -2
- package/node_modules/diff/package.json +22 -24
- package/node_modules/diff/release-notes.md +28 -0
- package/npm-shrinkwrap.json +9 -9
- package/package.json +5 -5
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"FileRenderer.js","names":["options: FileRendererOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options: RenderFileOptions","options","contentArray: ElementContent[]"],"sources":["../../src/renderers/FileRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport {\n DEFAULT_RENDER_RANGE,\n DEFAULT_THEMES,\n DEFAULT_TOKENIZE_MAX_LENGTH,\n} from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport { hasResolvedThemes } from '../highlighter/themes/hasResolvedThemes';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n FileContents,\n FileHeaderRenderMode,\n LineAnnotation,\n RenderedFileASTCache,\n RenderFileOptions,\n RenderFileResult,\n RenderRange,\n SupportedLanguages,\n ThemedFileResult,\n} from '../types';\nimport { areFileRenderOptionsEqual } from '../utils/areFileRenderOptionsEqual';\nimport { areFilesEqual } from '../utils/areFilesEqual';\nimport { areRenderRangesEqual } from '../utils/areRenderRangesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createContentColumn } from '../utils/createContentColumn';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getThemes } from '../utils/getThemes';\nimport {\n createGutterGap,\n createGutterItem,\n createGutterWrapper,\n createHastElement,\n} from '../utils/hast_utils';\nimport { isFilePlainText } from '../utils/isFilePlainText';\nimport { iterateOverFile } from '../utils/iterateOverFile';\nimport { renderFileWithHighlighter } from '../utils/renderFileWithHighlighter';\nimport { shouldUseTokenTransformer } from '../utils/shouldUseTokenTransformer';\nimport { splitFileContents } from '../utils/splitFileContents';\nimport type { WorkerPoolManager } from '../worker';\n\ntype AnnotationLineMap<LAnnotation> = Record<\n number,\n LineAnnotation<LAnnotation>[] | undefined\n>;\n\ninterface GetRenderOptionsReturn {\n options: RenderFileOptions;\n forceHighlight: boolean;\n}\n\nexport interface FileRenderResult {\n gutterAST: ElementContent[];\n contentAST: ElementContent[];\n preAST: HASTElement;\n headerAST: HASTElement | undefined;\n css: string;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n rowCount: number;\n bufferBefore: number;\n bufferAfter: number;\n}\n\ninterface LineCache {\n cacheKey: string | undefined;\n lines: string[];\n}\n\nexport interface FileRendererOptions extends BaseCodeOptions {\n headerRenderMode?: FileHeaderRenderMode;\n}\n\nlet instanceId = -1;\n\nexport class FileRenderer<LAnnotation = undefined> {\n readonly __id: string = `file-renderer:${++instanceId}`;\n\n private highlighter: DiffsHighlighter | undefined;\n private renderCache: RenderedFileASTCache | undefined;\n private computedLang: SupportedLanguages = 'text';\n private lineAnnotations: AnnotationLineMap<LAnnotation> = {};\n private lineCache: LineCache | undefined;\n\n constructor(\n public options: FileRendererOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n public setOptions(options: FileRendererOptions): void {\n this.options = options;\n }\n\n public mergeOptions(options: Partial<FileRendererOptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n public setLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): void {\n this.lineAnnotations = {};\n for (const annotation of lineAnnotations) {\n const arr = this.lineAnnotations[annotation.lineNumber] ?? [];\n this.lineAnnotations[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n public cleanUp(): void {\n this.recycle();\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n public recycle(): void {\n this.renderCache = undefined;\n this.highlighter = undefined;\n this.workerManager?.cleanUpTasks(this);\n this.lineCache = undefined;\n }\n\n public hydrate(file: FileContents): void {\n const { options } = this.getRenderOptions(file);\n const lines = this.getOrCreateLineCache(file);\n const massiveFile = isFileMassive(\n lines.length,\n this.getTokenizeMaxLength()\n );\n let cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && !areFileRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n file,\n options,\n highlighted: !massiveFile && !isFilePlainText(file),\n result: massiveFile ? undefined : cache?.result,\n // FIXME(amadeus): Add support for renderRanges\n renderRange: undefined,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n if (this.renderCache.result == null && !massiveFile) {\n // We should only kick off a preload of the AST if we have a WorkerPool\n this.workerManager.highlightFileAST(this, file);\n }\n }\n // Lets attempt to get the highlighter/languages ready immediately\n else if (this.highlighter == null) {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n void this.initializeHighlighter();\n }\n }\n\n private getRenderOptions(file: FileContents): GetRenderOptionsReturn {\n const options: RenderFileOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getFileRenderOptions();\n }\n const { theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1000 } =\n this.options;\n return {\n theme,\n useTokenTransformer: shouldUseTokenTransformer(this.options),\n tokenizeMaxLineLength,\n };\n })();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceHighlight: true };\n }\n if (\n !areFilesEqual(file, renderCache.file) ||\n !areFileRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceHighlight: true };\n }\n return { options, forceHighlight: false };\n }\n\n public getOrCreateLineCache(file: FileContents): string[] {\n // Uncached files will get split every time, not the greatest experience\n // tbh... but something people should try to optimize away\n if (file.cacheKey == null) {\n this.lineCache = undefined;\n return splitFileContents(file.contents);\n }\n\n let { lineCache } = this;\n if (lineCache == null || lineCache.cacheKey !== file.cacheKey) {\n lineCache = {\n cacheKey: file.cacheKey,\n lines: splitFileContents(file.contents),\n };\n }\n this.lineCache = lineCache;\n return lineCache.lines;\n }\n\n public renderFile(\n file: FileContents | undefined = this.renderCache?.file,\n renderRange: RenderRange = DEFAULT_RENDER_RANGE\n ): FileRenderResult | undefined {\n if (file == null) {\n return undefined;\n }\n let { options, forceHighlight } = this.getRenderOptions(file);\n const cache = this.getMatchingWorkerResultCache(file, options);\n if (cache != null && !this.hasHighlightedRenderCache(file, options)) {\n this.renderCache = {\n file,\n highlighted: true,\n renderRange: undefined,\n ...cache,\n };\n forceHighlight = false;\n }\n const lines = this.getOrCreateLineCache(file);\n const forcePlainText = isFileMassive(\n lines.length,\n this.getTokenizeMaxLength()\n );\n this.renderCache ??= {\n file,\n highlighted: false,\n options,\n result: undefined,\n renderRange: undefined,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n // Cache invalidation based on renderRange comparison\n if (\n this.renderCache.result == null ||\n forcePlainText ||\n (!this.renderCache.highlighted &&\n (!areFilesEqual(file, this.renderCache.file) ||\n !areRenderRangesEqual(this.renderCache.renderRange, renderRange)))\n ) {\n this.renderCache.file = file;\n this.renderCache.options = options;\n this.renderCache.highlighted = false;\n this.renderCache.result = this.workerManager.getPlainFileAST(\n file,\n renderRange.startingLine,\n renderRange.totalLines,\n lines\n );\n this.renderCache.renderRange = renderRange;\n }\n\n if (\n // We should only attempt to kick off the worker highlighter if there\n // are lines to render\n renderRange.totalLines > 0 &&\n !forcePlainText &&\n (!this.renderCache.highlighted || forceHighlight)\n ) {\n this.workerManager.highlightFileAST(this, file);\n }\n } else {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n const canHighlight = !forcePlainText && hasLangs;\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceHighlight ||\n forcePlainText ||\n (!this.renderCache.highlighted && canHighlight) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderFileWithHighlighter(\n file,\n this.highlighter,\n forcePlainText || !hasLangs\n );\n this.renderCache = {\n file,\n options,\n highlighted: canHighlight,\n result,\n renderRange: undefined,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || (!forcePlainText && !hasLangs)) {\n void this.asyncHighlight(file).then(({ result, options }) => {\n // In this case we need to force a re-render, so we can do that by\n // reaching into renderCache\n if (this.renderCache != null) {\n this.renderCache.highlighted = false;\n }\n this.onHighlightSuccess(file, result, options, !forcePlainText);\n });\n }\n }\n\n return this.renderCache.result != null\n ? this.processFileResult(\n this.renderCache.file,\n renderRange,\n this.renderCache.result\n )\n : undefined;\n }\n\n async asyncRender(\n file: FileContents,\n renderRange: RenderRange = DEFAULT_RENDER_RANGE\n ): Promise<FileRenderResult> {\n const { result } = await this.asyncHighlight(file);\n return this.processFileResult(file, renderRange, result);\n }\n\n private async asyncHighlight(file: FileContents): Promise<RenderFileResult> {\n const lines = this.getOrCreateLineCache(file);\n const forcePlainText = isFileMassive(\n lines.length,\n this.getTokenizeMaxLength()\n );\n this.computedLang = forcePlainText\n ? 'text'\n : (file.lang ?? getFiletypeFromFileName(file.name));\n const hasThemes =\n this.highlighter != null &&\n hasResolvedThemes(getThemes(this.options.theme));\n const hasLangs =\n forcePlainText ||\n (this.highlighter != null && areLanguagesAttached(this.computedLang));\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderFileWithHighlighter(\n file,\n this.highlighter,\n forcePlainText\n );\n }\n\n private renderFileWithHighlighter(\n file: FileContents,\n highlighter: DiffsHighlighter,\n forcePlainText = false\n ): RenderFileResult {\n const { options } = this.getRenderOptions(file);\n const result = renderFileWithHighlighter(file, highlighter, options, {\n forcePlainText,\n });\n return { result, options };\n }\n\n private processFileResult(\n file: FileContents,\n renderRange: RenderRange,\n { code, themeStyles, baseThemeType }: ThemedFileResult\n ): FileRenderResult {\n const { disableFileHeader = false } = this.options;\n const contentArray: ElementContent[] = [];\n const gutter = createGutterWrapper();\n const lines = this.getOrCreateLineCache(file);\n let rowCount = 0;\n\n iterateOverFile({\n lines,\n startingLine: renderRange.startingLine,\n totalLines: renderRange.totalLines,\n callback: ({ lineIndex, lineNumber }) => {\n // Sparse array - directly indexed by lineIndex\n const line = code[lineIndex];\n if (line == null) {\n const message = 'FileRenderer.processFileResult: Line doesnt exist';\n console.error(message, {\n name: file.name,\n lineIndex,\n lineNumber,\n lines,\n });\n throw new Error(message);\n }\n\n if (line != null) {\n // Add gutter line number\n gutter.children.push(\n createGutterItem('context', lineNumber, `${lineIndex}`)\n );\n contentArray.push(line);\n rowCount++;\n\n // Check annotations using ACTUAL line number from file\n const annotations = this.lineAnnotations[lineNumber];\n if (annotations != null) {\n gutter.children.push(createGutterGap('context', 'annotation', 1));\n contentArray.push(\n createAnnotationElement({\n type: 'annotation',\n hunkIndex: 0,\n lineIndex: lineNumber,\n annotations: annotations.map((annotation) =>\n getLineAnnotationName(annotation)\n ),\n })\n );\n rowCount++;\n }\n }\n },\n });\n\n // Finalize: wrap gutter and content\n gutter.properties.style = `grid-row: span ${rowCount}`;\n return {\n gutterAST: gutter.children ?? [],\n contentAST: contentArray,\n preAST: this.createPreElement(lines.length),\n headerAST: !disableFileHeader ? this.renderHeader(file) : undefined,\n totalLines: lines.length,\n rowCount,\n themeStyles: themeStyles,\n baseThemeType,\n bufferBefore: renderRange.bufferBefore,\n bufferAfter: renderRange.bufferAfter,\n css: '',\n };\n }\n\n private renderHeader(file: FileContents) {\n const { headerRenderMode = 'default', stickyHeader = false } = this.options;\n return createFileHeaderElement({\n fileOrDiff: file,\n mode: headerRenderMode,\n stickyHeader,\n });\n }\n\n public renderFullHTML(result: FileRenderResult): string {\n return toHtml(this.renderFullAST(result));\n }\n\n public renderFullAST(\n result: FileRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n children.push(\n createHastElement({\n tagName: 'code',\n children: this.renderCodeAST(result),\n properties: { 'data-code': '' },\n })\n );\n return { ...result.preAST, children };\n }\n\n public renderCodeAST(result: FileRenderResult): ElementContent[] {\n const gutter = createGutterWrapper();\n gutter.children = result.gutterAST;\n gutter.properties.style = `grid-row: span ${result.rowCount}`;\n const contentColumn = createContentColumn(\n result.contentAST,\n result.rowCount\n );\n return [gutter, contentColumn];\n }\n\n public renderPartialHTML(\n children: ElementContent[],\n includeCodeNode: boolean = false\n ): string {\n if (!includeCodeNode) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: { 'data-code': '' },\n })\n );\n }\n\n public async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n public onHighlightSuccess(\n file: FileContents,\n result: ThemedFileResult,\n options: RenderFileOptions,\n highlighted = true\n ): void {\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n !areFilesEqual(file, this.renderCache.file) ||\n !this.renderCache.highlighted ||\n !areFileRenderOptionsEqual(options, this.renderCache.options);\n\n this.renderCache = {\n file,\n options,\n highlighted,\n result,\n renderRange: undefined,\n };\n\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n private getMatchingWorkerResultCache(\n file: FileContents,\n options: RenderFileOptions\n ): RenderFileResult | undefined {\n const cache = this.workerManager?.getFileResultCache(file);\n if (cache == null || !areFileRenderOptionsEqual(options, cache.options)) {\n return undefined;\n }\n return cache;\n }\n\n private hasHighlightedRenderCache(\n file: FileContents,\n options: RenderFileOptions\n ): boolean {\n const { renderCache } = this;\n return (\n renderCache?.result != null &&\n renderCache.highlighted &&\n areFilesEqual(file, renderCache.file) &&\n areFileRenderOptionsEqual(options, renderCache.options)\n );\n }\n\n public onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private getTokenizeMaxLength(): number {\n return this.options.tokenizeMaxLength ?? DEFAULT_TOKENIZE_MAX_LENGTH;\n }\n\n private createPreElement(totalLines: number): HASTElement {\n const { disableLineNumbers = false, overflow = 'scroll' } = this.options;\n return createPreElement({\n type: 'file',\n diffIndicators: 'none',\n disableBackground: true,\n disableLineNumbers,\n overflow,\n split: false,\n totalLines,\n });\n }\n}\n\nfunction isFileMassive(lineCount: number, tokenizeMaxLength: number): boolean {\n return lineCount > tokenizeMaxLength;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"FileRenderer.js","names":["options: FileRendererOptions","onRenderUpdate?: () => unknown","workerManager?: WorkerPoolManager | undefined","options: RenderFileOptions","options","contentArray: ElementContent[]"],"sources":["../../src/renderers/FileRenderer.ts"],"sourcesContent":["import type { ElementContent, Element as HASTElement } from 'hast';\nimport { toHtml } from 'hast-util-to-html';\n\nimport {\n DEFAULT_RENDER_RANGE,\n DEFAULT_THEMES,\n DEFAULT_TOKENIZE_MAX_LENGTH,\n} from '../constants';\nimport { areLanguagesAttached } from '../highlighter/languages/areLanguagesAttached';\nimport {\n getHighlighterIfLoaded,\n getSharedHighlighter,\n} from '../highlighter/shared_highlighter';\nimport { areThemesAttached } from '../highlighter/themes/areThemesAttached';\nimport { hasResolvedThemes } from '../highlighter/themes/hasResolvedThemes';\nimport type {\n BaseCodeOptions,\n DiffsHighlighter,\n FileContents,\n FileHeaderRenderMode,\n LineAnnotation,\n RenderedFileASTCache,\n RenderFileOptions,\n RenderFileResult,\n RenderRange,\n SupportedLanguages,\n ThemedFileResult,\n} from '../types';\nimport { areFileRenderOptionsEqual } from '../utils/areFileRenderOptionsEqual';\nimport { areFilesEqual } from '../utils/areFilesEqual';\nimport { areRenderRangesEqual } from '../utils/areRenderRangesEqual';\nimport { createAnnotationElement } from '../utils/createAnnotationElement';\nimport { createContentColumn } from '../utils/createContentColumn';\nimport { createFileHeaderElement } from '../utils/createFileHeaderElement';\nimport { createPreElement } from '../utils/createPreElement';\nimport { getFiletypeFromFileName } from '../utils/getFiletypeFromFileName';\nimport { getHighlighterOptions } from '../utils/getHighlighterOptions';\nimport { getLineAnnotationName } from '../utils/getLineAnnotationName';\nimport { getThemes } from '../utils/getThemes';\nimport {\n createGutterGap,\n createGutterItem,\n createGutterWrapper,\n createHastElement,\n} from '../utils/hast_utils';\nimport { isFilePlainText } from '../utils/isFilePlainText';\nimport { iterateOverFile } from '../utils/iterateOverFile';\nimport { renderFileWithHighlighter } from '../utils/renderFileWithHighlighter';\nimport { shouldUseTokenTransformer } from '../utils/shouldUseTokenTransformer';\nimport { splitFileContents } from '../utils/splitFileContents';\nimport type { WorkerPoolManager } from '../worker';\n\ntype AnnotationLineMap<LAnnotation> = Record<\n number,\n LineAnnotation<LAnnotation>[] | undefined\n>;\n\ninterface GetRenderOptionsReturn {\n options: RenderFileOptions;\n forceHighlight: boolean;\n}\n\nexport interface FileRenderResult {\n gutterAST: ElementContent[];\n contentAST: ElementContent[];\n preAST: HASTElement;\n headerAST: HASTElement | undefined;\n css: string;\n totalLines: number;\n themeStyles: string;\n baseThemeType: 'light' | 'dark' | undefined;\n rowCount: number;\n bufferBefore: number;\n bufferAfter: number;\n}\n\ninterface LineCache {\n cacheKey: string | undefined;\n lines: string[];\n}\n\nexport interface FileRendererOptions extends BaseCodeOptions {\n headerRenderMode?: FileHeaderRenderMode;\n}\n\nlet instanceId = -1;\n\nexport class FileRenderer<LAnnotation = undefined> {\n readonly __id: string = `file-renderer:${++instanceId}`;\n\n private highlighter: DiffsHighlighter | undefined;\n private renderCache: RenderedFileASTCache | undefined;\n private computedLang: SupportedLanguages = 'text';\n private lineAnnotations: AnnotationLineMap<LAnnotation> = {};\n private lineCache: LineCache | undefined;\n\n constructor(\n public options: FileRendererOptions = { theme: DEFAULT_THEMES },\n private onRenderUpdate?: () => unknown,\n private workerManager?: WorkerPoolManager | undefined\n ) {\n if (workerManager?.isWorkingPool() !== true) {\n this.highlighter = areThemesAttached(options.theme ?? DEFAULT_THEMES)\n ? getHighlighterIfLoaded()\n : undefined;\n }\n }\n\n public setOptions(options: FileRendererOptions): void {\n this.options = options;\n }\n\n public mergeOptions(options: Partial<FileRendererOptions>): void {\n this.options = { ...this.options, ...options };\n }\n\n public setLineAnnotations(\n lineAnnotations: LineAnnotation<LAnnotation>[]\n ): void {\n this.lineAnnotations = {};\n for (const annotation of lineAnnotations) {\n const arr = this.lineAnnotations[annotation.lineNumber] ?? [];\n this.lineAnnotations[annotation.lineNumber] = arr;\n arr.push(annotation);\n }\n }\n\n public cleanUp(): void {\n this.recycle();\n this.workerManager = undefined;\n this.onRenderUpdate = undefined;\n }\n\n public recycle(): void {\n this.renderCache = undefined;\n this.highlighter = undefined;\n this.workerManager?.cleanUpTasks(this);\n this.lineCache = undefined;\n }\n\n public hydrate(file: FileContents): void {\n const { options } = this.getRenderOptions(file);\n const lines = this.getOrCreateLineCache(file);\n const massiveFile = isFileMassive(\n lines.length,\n this.getTokenizeMaxLength()\n );\n let cache = this.workerManager?.getFileResultCache(file);\n if (cache != null && !areFileRenderOptionsEqual(options, cache.options)) {\n cache = undefined;\n }\n this.renderCache ??= {\n file,\n options,\n highlighted: !massiveFile && !isFilePlainText(file),\n result: massiveFile ? undefined : cache?.result,\n // FIXME(amadeus): Add support for renderRanges\n renderRange: undefined,\n };\n if (this.workerManager?.isWorkingPool() === true) {\n if (this.renderCache.result == null && !massiveFile) {\n // We should only kick off a preload of the AST if we have a WorkerPool\n this.workerManager.highlightFileAST(this, file);\n }\n }\n // Lets attempt to get the highlighter/languages ready immediately\n else if (this.highlighter == null) {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n void this.initializeHighlighter();\n }\n }\n\n private getRenderOptions(file: FileContents): GetRenderOptionsReturn {\n const options: RenderFileOptions = (() => {\n if (this.workerManager?.isWorkingPool() === true) {\n return this.workerManager.getFileRenderOptions();\n }\n const { theme = DEFAULT_THEMES, tokenizeMaxLineLength = 1000 } =\n this.options;\n return {\n theme,\n useTokenTransformer: shouldUseTokenTransformer(this.options),\n tokenizeMaxLineLength,\n };\n })();\n const { renderCache } = this;\n if (renderCache?.result == null) {\n return { options, forceHighlight: true };\n }\n if (\n !areFilesEqual(file, renderCache.file) ||\n !areFileRenderOptionsEqual(options, renderCache.options)\n ) {\n return { options, forceHighlight: true };\n }\n return { options, forceHighlight: false };\n }\n\n public getOrCreateLineCache(file: FileContents): string[] {\n // Uncached files will get split every time, not the greatest experience\n // tbh... but something people should try to optimize away\n if (file.cacheKey == null) {\n this.lineCache = undefined;\n return splitFileContents(file.contents);\n }\n\n let { lineCache } = this;\n if (lineCache == null || lineCache.cacheKey !== file.cacheKey) {\n lineCache = {\n cacheKey: file.cacheKey,\n lines: splitFileContents(file.contents),\n };\n }\n this.lineCache = lineCache;\n return lineCache.lines;\n }\n\n public renderFile(\n file: FileContents | undefined = this.renderCache?.file,\n renderRange: RenderRange = DEFAULT_RENDER_RANGE\n ): FileRenderResult | undefined {\n if (file == null) {\n return undefined;\n }\n let { options, forceHighlight } = this.getRenderOptions(file);\n const cache = this.getMatchingWorkerResultCache(file, options);\n if (cache != null && !this.hasHighlightedRenderCache(file, options)) {\n this.renderCache = {\n file,\n highlighted: true,\n renderRange: undefined,\n ...cache,\n };\n forceHighlight = false;\n }\n this.renderCache ??= {\n file,\n highlighted: false,\n options,\n result: undefined,\n renderRange: undefined,\n };\n const lines = this.getOrCreateLineCache(file);\n const hasContent = file.contents.length > 0;\n const forcePlainText =\n !hasContent ||\n isFilePlainText(file) ||\n isFileMassive(lines.length, this.getTokenizeMaxLength());\n const newContent = !areFilesEqual(file, this.renderCache.file);\n const newRenderRange = !areRenderRangesEqual(\n this.renderCache.renderRange,\n renderRange\n );\n if (this.workerManager?.isWorkingPool() === true) {\n // Cache invalidation based on renderRange comparison\n if (\n forcePlainText ||\n this.renderCache.result == null ||\n (!this.renderCache.highlighted && (newContent || newRenderRange))\n ) {\n this.renderCache.file = file;\n this.renderCache.options = options;\n this.renderCache.highlighted = false;\n if (\n this.renderCache.result == null ||\n newContent ||\n newRenderRange ||\n forceHighlight\n ) {\n this.renderCache.result = this.workerManager.getPlainFileAST(\n file,\n renderRange.startingLine,\n renderRange.totalLines,\n lines\n );\n }\n this.renderCache.renderRange = renderRange;\n }\n\n if (\n !forcePlainText &&\n hasContent &&\n (!this.renderCache.highlighted || forceHighlight)\n ) {\n this.workerManager.highlightFileAST(this, file);\n }\n } else {\n this.computedLang = file.lang ?? getFiletypeFromFileName(file.name);\n const hasThemes =\n this.highlighter != null && areThemesAttached(options.theme);\n const hasLangs =\n this.highlighter != null && areLanguagesAttached(this.computedLang);\n const canHighlight = !forcePlainText && hasLangs;\n\n // If we have any semblance of a highlighter with the correct theme(s)\n // attached, we can kick off some form of rendering. If we don't have\n // the correct language, then we can render plain text and after kick off\n // an async job to get the highlighted AST\n if (\n this.highlighter != null &&\n hasThemes &&\n (forceHighlight ||\n forcePlainText ||\n (!this.renderCache.highlighted && canHighlight) ||\n this.renderCache.result == null)\n ) {\n const { result, options } = this.renderFileWithHighlighter(\n file,\n this.highlighter,\n forcePlainText || !hasLangs\n );\n this.renderCache = {\n file,\n options,\n highlighted: canHighlight,\n result,\n renderRange: undefined,\n };\n }\n\n // If we get in here it means we'll have to kick off an async highlight\n // process which will involve initializing the highlighter with new themes\n // and languages\n if (!hasThemes || (!forcePlainText && !hasLangs)) {\n void this.asyncHighlight(file).then(({ result, options }) => {\n // In this case we need to force a re-render, so we can do that by\n // reaching into renderCache\n if (this.renderCache != null) {\n this.renderCache.highlighted = false;\n }\n this.onHighlightSuccess(file, result, options, !forcePlainText);\n });\n }\n }\n\n return this.renderCache.result != null\n ? this.processFileResult(\n this.renderCache.file,\n renderRange,\n this.renderCache.result\n )\n : undefined;\n }\n\n async asyncRender(\n file: FileContents,\n renderRange: RenderRange = DEFAULT_RENDER_RANGE\n ): Promise<FileRenderResult> {\n const { result } = await this.asyncHighlight(file);\n return this.processFileResult(file, renderRange, result);\n }\n\n private async asyncHighlight(file: FileContents): Promise<RenderFileResult> {\n const lines = this.getOrCreateLineCache(file);\n const forcePlainText = isFileMassive(\n lines.length,\n this.getTokenizeMaxLength()\n );\n this.computedLang = forcePlainText\n ? 'text'\n : (file.lang ?? getFiletypeFromFileName(file.name));\n const hasThemes =\n this.highlighter != null &&\n hasResolvedThemes(getThemes(this.options.theme));\n const hasLangs =\n forcePlainText ||\n (this.highlighter != null && areLanguagesAttached(this.computedLang));\n // If we don't have the required langs or themes, then we need to\n // initialize the highlighter to load the appropriate languages and themes\n if (this.highlighter == null || !hasThemes || !hasLangs) {\n this.highlighter = await this.initializeHighlighter();\n }\n return this.renderFileWithHighlighter(\n file,\n this.highlighter,\n forcePlainText\n );\n }\n\n private renderFileWithHighlighter(\n file: FileContents,\n highlighter: DiffsHighlighter,\n forcePlainText = false\n ): RenderFileResult {\n const { options } = this.getRenderOptions(file);\n const result = renderFileWithHighlighter(file, highlighter, options, {\n forcePlainText,\n });\n return { result, options };\n }\n\n private processFileResult(\n file: FileContents,\n renderRange: RenderRange,\n { code, themeStyles, baseThemeType }: ThemedFileResult\n ): FileRenderResult {\n const { disableFileHeader = false } = this.options;\n const contentArray: ElementContent[] = [];\n const gutter = createGutterWrapper();\n const lines = this.getOrCreateLineCache(file);\n let rowCount = 0;\n\n iterateOverFile({\n lines,\n startingLine: renderRange.startingLine,\n totalLines: renderRange.totalLines,\n callback: ({ lineIndex, lineNumber }) => {\n // Sparse array - directly indexed by lineIndex\n const line = code[lineIndex];\n if (line == null) {\n const message = 'FileRenderer.processFileResult: Line doesnt exist';\n console.error(message, {\n name: file.name,\n lineIndex,\n lineNumber,\n lines,\n });\n throw new Error(message);\n }\n\n if (line != null) {\n // Add gutter line number\n gutter.children.push(\n createGutterItem('context', lineNumber, `${lineIndex}`)\n );\n contentArray.push(line);\n rowCount++;\n\n // Check annotations using ACTUAL line number from file\n const annotations = this.lineAnnotations[lineNumber];\n if (annotations != null) {\n gutter.children.push(createGutterGap('context', 'annotation', 1));\n contentArray.push(\n createAnnotationElement({\n type: 'annotation',\n hunkIndex: 0,\n lineIndex: lineNumber,\n annotations: annotations.map((annotation) =>\n getLineAnnotationName(annotation)\n ),\n })\n );\n rowCount++;\n }\n }\n },\n });\n\n // Finalize: wrap gutter and content\n gutter.properties.style = `grid-row: span ${rowCount}`;\n return {\n gutterAST: gutter.children ?? [],\n contentAST: contentArray,\n preAST: this.createPreElement(lines.length),\n headerAST: !disableFileHeader ? this.renderHeader(file) : undefined,\n totalLines: lines.length,\n rowCount,\n themeStyles: themeStyles,\n baseThemeType,\n bufferBefore: renderRange.bufferBefore,\n bufferAfter: renderRange.bufferAfter,\n css: '',\n };\n }\n\n private renderHeader(file: FileContents) {\n const { headerRenderMode = 'default', stickyHeader = false } = this.options;\n return createFileHeaderElement({\n fileOrDiff: file,\n mode: headerRenderMode,\n stickyHeader,\n });\n }\n\n public renderFullHTML(result: FileRenderResult): string {\n return toHtml(this.renderFullAST(result));\n }\n\n public renderFullAST(\n result: FileRenderResult,\n children: ElementContent[] = []\n ): HASTElement {\n children.push(\n createHastElement({\n tagName: 'code',\n children: this.renderCodeAST(result),\n properties: { 'data-code': '' },\n })\n );\n return { ...result.preAST, children };\n }\n\n public renderCodeAST(result: FileRenderResult): ElementContent[] {\n const gutter = createGutterWrapper();\n gutter.children = result.gutterAST;\n gutter.properties.style = `grid-row: span ${result.rowCount}`;\n const contentColumn = createContentColumn(\n result.contentAST,\n result.rowCount\n );\n return [gutter, contentColumn];\n }\n\n public renderPartialHTML(\n children: ElementContent[],\n includeCodeNode: boolean = false\n ): string {\n if (!includeCodeNode) {\n return toHtml(children);\n }\n return toHtml(\n createHastElement({\n tagName: 'code',\n children,\n properties: { 'data-code': '' },\n })\n );\n }\n\n public async initializeHighlighter(): Promise<DiffsHighlighter> {\n this.highlighter = await getSharedHighlighter(\n getHighlighterOptions(this.computedLang, this.options)\n );\n return this.highlighter;\n }\n\n public onHighlightSuccess(\n file: FileContents,\n result: ThemedFileResult,\n options: RenderFileOptions,\n highlighted = true\n ): void {\n if (this.renderCache == null) {\n return;\n }\n const triggerRenderUpdate =\n !areFilesEqual(file, this.renderCache.file) ||\n !this.renderCache.highlighted ||\n !areFileRenderOptionsEqual(options, this.renderCache.options);\n\n this.renderCache = {\n file,\n options,\n highlighted,\n result,\n renderRange: undefined,\n };\n\n if (triggerRenderUpdate) {\n this.onRenderUpdate?.();\n }\n }\n\n private getMatchingWorkerResultCache(\n file: FileContents,\n options: RenderFileOptions\n ): RenderFileResult | undefined {\n const cache = this.workerManager?.getFileResultCache(file);\n if (cache == null || !areFileRenderOptionsEqual(options, cache.options)) {\n return undefined;\n }\n return cache;\n }\n\n private hasHighlightedRenderCache(\n file: FileContents,\n options: RenderFileOptions\n ): boolean {\n const { renderCache } = this;\n return (\n renderCache?.result != null &&\n renderCache.highlighted &&\n areFilesEqual(file, renderCache.file) &&\n areFileRenderOptionsEqual(options, renderCache.options)\n );\n }\n\n public onHighlightError(error: unknown): void {\n console.error(error);\n }\n\n private getTokenizeMaxLength(): number {\n return this.options.tokenizeMaxLength ?? DEFAULT_TOKENIZE_MAX_LENGTH;\n }\n\n private createPreElement(totalLines: number): HASTElement {\n const { disableLineNumbers = false, overflow = 'scroll' } = this.options;\n return createPreElement({\n type: 'file',\n diffIndicators: 'none',\n disableBackground: true,\n disableLineNumbers,\n overflow,\n split: false,\n totalLines,\n });\n }\n}\n\nfunction isFileMassive(lineCount: number, tokenizeMaxLength: number): boolean {\n return lineCount > tokenizeMaxLength;\n}\n"],"mappings":"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"}
|
|
@@ -368,7 +368,46 @@
|
|
|
368
368
|
function hasOnlyUnixLineEndings(string) {
|
|
369
369
|
return !string.includes('\r\n') && string.includes('\n');
|
|
370
370
|
}
|
|
371
|
-
|
|
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
|
-
//
|
|
462
|
-
//
|
|
463
|
-
|
|
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 =
|
|
608
|
-
const
|
|
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
|
|
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,"&")).replace(/</g,"<")).replace(/>/g,">")).replace(/"/g,""")})(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,"&")).replace(/</g,"<")).replace(/>/g,">")).replace(/"/g,""")})(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;
|
|
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
|
-
//
|
|
93
|
-
//
|
|
94
|
-
|
|
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
|
|
241
|
-
var
|
|
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),
|
|
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
|
}
|