/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A range of offsets (0-based). */ declare class OffsetRange { readonly start: number; readonly endExclusive: number; static ofLength(length: number): OffsetRange; static ofStartAndLength(start: number, length: number): OffsetRange; constructor(start: number, endExclusive: number); get isEmpty(): boolean; get length(): number; delta(offset: number): OffsetRange; deltaStart(offset: number): OffsetRange; deltaEnd(offset: number): OffsetRange; equals(other: OffsetRange): boolean; containsRange(other: OffsetRange): boolean; contains(offset: number): boolean; join(other: OffsetRange): OffsetRange; intersect(other: OffsetRange): OffsetRange | undefined; intersects(other: OffsetRange): boolean; intersectsOrTouches(other: OffsetRange): boolean; slice(arr: readonly T[]): T[]; toString(): string; } /** * A pair of ranges, one in `original`, one in `modified`. */ declare class OffsetRangeMapping { readonly original: OffsetRange; readonly modified: OffsetRange; constructor(original: OffsetRange, modified: OffsetRange); toString(): string; } /** * A single atomic replacement: replace `range` in the input with `newText`. */ declare class StringReplacement { readonly range: OffsetRange; readonly newText: string; constructor(range: OffsetRange, newText: string); get isEmpty(): boolean; toString(): string; } /** * A set of replacements applied in parallel to one input string. * * Invariants: * - replacements are sorted by `range.start` * - replacements do not overlap (touching is allowed) * - all ranges live in the same coordinate space (the input passed to `apply`) */ declare class StringEdit { readonly replacements: readonly StringReplacement[]; static readonly empty: StringEdit; static single(replacement: StringReplacement): StringEdit; /** * Validates that replacements are sorted and non-overlapping. */ static of(replacements: readonly StringReplacement[]): StringEdit; private constructor(); get isEmpty(): boolean; apply(text: string): string; /** * Returns an edit `E` such that `E.apply(this.apply(input)) === input`. */ inverse(input: string): StringEdit; /** * Joins touching replacements and drops no-ops. */ normalize(): StringEdit; toString(): string; } /** * Annotation attached to a replacement. `join` decides whether two * adjacent annotations can be merged during `normalize()`. */ interface IEditData { join(other: T): T | undefined; } /** * An atomic replacement carrying user-defined metadata. */ declare class AnnotatedStringReplacement> { readonly range: OffsetRange; readonly newText: string; readonly data: T; constructor(range: OffsetRange, newText: string, data: T); get isEmpty(): boolean; toString(): string; } /** * A set of annotated replacements applied in parallel. * * Invariants: same as `StringEdit` (sorted by `range.start`, non-overlapping, * shared coordinate space). */ declare class AnnotatedStringEdit> { readonly replacements: readonly AnnotatedStringReplacement[]; static empty>(): AnnotatedStringEdit; static single>(replacement: AnnotatedStringReplacement): AnnotatedStringEdit; static of>(replacements: readonly AnnotatedStringReplacement[]): AnnotatedStringEdit; private constructor(); get isEmpty(): boolean; apply(text: string): string; inverse(input: string, invertData: (data: T) => T): AnnotatedStringEdit; /** * Joins touching replacements when their annotations join. Drops no-ops. */ normalize(): AnnotatedStringEdit; mapData>(f: (data: T) => U): AnnotatedStringEdit; stripData(): StringEdit; toString(): string; } /** * Diff result annotation. * * Carries flags describing the nature of the replacement. For now only * `isFormattingChange` is exposed; more flags (e.g. move source/target, * semantic category) can be added later. */ declare class DiffAnnotation implements IEditData { /** Whether the replacement is purely a formatting change (whitespace, indentation, etc.). */ readonly isFormattingChange: boolean; static readonly change: DiffAnnotation; static readonly formatting: DiffAnnotation; private constructor(); join(other: DiffAnnotation): DiffAnnotation | undefined; toString(): string; } /** * A block of text that was moved between two locations. * * `range` locates the block in `original` and in `modified` (offsets in the * respective full texts). `innerEdit` describes the changes inside the moved * block, with offsets local to the slice (i.e. `0` is the start of the slice). */ declare class Move { readonly range: OffsetRangeMapping; readonly innerEdit: StringEdit; constructor(range: OffsetRangeMapping, innerEdit: StringEdit); toString(): string; } /** * Output of a diff computation. */ declare class DiffResult { /** * Parallel set of replacements transforming `original` into `modified`, * excluding any replacements that are part of a `Move`. * * When no moves are computed: `edits.apply(original) === modified`. */ readonly edits: AnnotatedStringEdit; /** * Detected text moves. Empty unless `DiffOptions.computeMoves` is set. */ readonly moves: readonly Move[]; /** * `true` if the algorithm aborted because of `maxComputationTimeMs`. * The result is still valid but may be coarser than ideal. */ readonly hitTimeout: boolean; constructor( /** * Parallel set of replacements transforming `original` into `modified`, * excluding any replacements that are part of a `Move`. * * When no moves are computed: `edits.apply(original) === modified`. */ edits: AnnotatedStringEdit, /** * Detected text moves. Empty unless `DiffOptions.computeMoves` is set. */ moves: readonly Move[], /** * `true` if the algorithm aborted because of `maxComputationTimeMs`. * The result is still valid but may be coarser than ideal. */ hitTimeout: boolean); } interface DiffOptions { /** * Algorithm hint. Pure-TS computer auto-selects based on input size if omitted. * The WASM computer currently ignores this hint. */ algorithm?: 'myers' | 'dynamic-programming'; /** Maximum computation time in milliseconds. 0 (default) means no timeout. */ maxComputationTimeMs?: number; /** Ignore leading and trailing whitespace differences. Default: false. */ ignoreTrimWhitespace?: boolean; /** Detect moved blocks of text. Default: false. */ computeMoves?: boolean; /** Extend diffs to subword boundaries. Default: false. */ extendToSubwords?: boolean; } interface IDiffComputer { computeDiff(original: string, modified: string, options?: DiffOptions): DiffResult; } interface CreateDiffComputerOptions { /** * Use the WASM-backed implementation. Loads the WASM module on first creation. * Default: false (pure-TS implementation). */ useWasm?: boolean; /** * Algorithm hint passed to the computer. */ algorithm?: 'myers' | 'dynamic-programming'; } declare function createDiffComputer(options?: CreateDiffComputerOptions): Promise; export { AnnotatedStringEdit, AnnotatedStringReplacement, DiffAnnotation, DiffResult, Move, OffsetRange, OffsetRangeMapping, StringEdit, StringReplacement, createDiffComputer }; export type { CreateDiffComputerOptions, DiffOptions, IDiffComputer, IEditData };