Skip to content

Instantly share code, notes, and snippets.

@blixt
Created September 8, 2025 20:17
Show Gist options
  • Select an option

  • Save blixt/52fa722f967247fa7fe5931ad0836b56 to your computer and use it in GitHub Desktop.

Select an option

Save blixt/52fa722f967247fa7fe5931ad0836b56 to your computer and use it in GitHub Desktop.

Revisions

  1. blixt created this gist Sep 8, 2025.
    48 changes: 48 additions & 0 deletions findAndReplace.ts
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,48 @@
    /**
    * Replaces old_string with new_string in the given code.
    * Validates that old_string appears exactly once to avoid ambiguous replacements.
    */
    export function findAndReplace(
    code: string,
    old_string: string,
    new_string: string,
    ): { success: true; result: string } | { success: false; error: string } {
    let pattern = old_string.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
    let occurrences = code.match(new RegExp(pattern, "g"))?.length ?? 0;
    let searchValue: string | RegExp = old_string;

    if (occurrences === 0) {
    // Try one more time but with flexible indentation. If our more general search pattern matches exactly one place
    // in the code, we will use it to replace the matching code.
    //
    // Note: We replace with [\t ] instead of \s here because otherwise it would also match the preceding newline.
    pattern = pattern.replace(/^\s+/gm, "([\\t ]+)");
    searchValue = new RegExp(pattern, "g");
    occurrences = code.match(searchValue)?.length ?? 0;
    if (occurrences === 0) {
    return {
    success: false,
    error: `The string "${old_string}" was not found in the code.`,
    };
    }
    if (occurrences > 1) {
    return {
    success: false,
    error: `The string "${old_string}" does not appear in the code. However, a similar string with different indentation exists. Please add more context and use exact indentation to avoid ambiguous replacements.`,
    };
    }
    }

    if (occurrences > 1) {
    return {
    success: false,
    error: `The string "${old_string}" appears ${occurrences} times in the code. Please be more specific to avoid ambiguous replacements.`,
    };
    }

    return {
    success: true,
    // Note: Using a function here also avoids the default behavior of replace changing "$$" to "$".
    result: code.replace(searchValue, (_, indent) => `${typeof indent === "string" ? indent : ""}${new_string}`),
    };
    }