private parse_update_file()

in codex-cli/src/utils/agent/apply-patch.ts [189:306]


  private parse_update_file(text: string): PatchAction {
    const action: PatchAction = { type: ActionType.UPDATE, chunks: [] };
    const fileLines = text.split("\n");
    let index = 0;

    while (
      !this.is_done([
        PATCH_SUFFIX,
        UPDATE_FILE_PREFIX,
        DELETE_FILE_PREFIX,
        ADD_FILE_PREFIX,
        END_OF_FILE_PREFIX,
      ])
    ) {
      const defStr = this.read_str("@@ ");
      let sectionStr = "";
      if (!defStr && this.lines[this.index] === "@@") {
        sectionStr = this.lines[this.index]!;
        this.index += 1;
      }
      if (!(defStr || sectionStr || index === 0)) {
        throw new DiffError(`Invalid Line:\n${this.lines[this.index]}`);
      }
      if (defStr.trim()) {
        let found = false;
        // ------------------------------------------------------------------
        // Equality helpers using the canonicalisation from find_context_core.
        // (We duplicate a minimal version here because the scope is local.)
        // ------------------------------------------------------------------
        const canonLocal = (s: string): string =>
          s.normalize("NFC").replace(
            /./gu,
            (c) =>
              (
                ({
                  "-": "-",
                  "\u2010": "-",
                  "\u2011": "-",
                  "\u2012": "-",
                  "\u2013": "-",
                  "\u2014": "-",
                  "\u2212": "-",
                  "\u0022": '"',
                  "\u201C": '"',
                  "\u201D": '"',
                  "\u201E": '"',
                  "\u00AB": '"',
                  "\u00BB": '"',
                  "\u0027": "'",
                  "\u2018": "'",
                  "\u2019": "'",
                  "\u201B": "'",
                  "\u00A0": " ",
                  "\u202F": " ",
                }) as Record<string, string>
              )[c] ?? c,
          );

        if (
          !fileLines
            .slice(0, index)
            .some((s) => canonLocal(s) === canonLocal(defStr))
        ) {
          for (let i = index; i < fileLines.length; i++) {
            if (canonLocal(fileLines[i]!) === canonLocal(defStr)) {
              index = i + 1;
              found = true;
              break;
            }
          }
        }
        if (
          !found &&
          !fileLines
            .slice(0, index)
            .some((s) => canonLocal(s.trim()) === canonLocal(defStr.trim()))
        ) {
          for (let i = index; i < fileLines.length; i++) {
            if (
              canonLocal(fileLines[i]!.trim()) === canonLocal(defStr.trim())
            ) {
              index = i + 1;
              this.fuzz += 1;
              found = true;
              break;
            }
          }
        }
      }

      const [nextChunkContext, chunks, endPatchIndex, eof] = peek_next_section(
        this.lines,
        this.index,
      );
      const [newIndex, fuzz] = find_context(
        fileLines,
        nextChunkContext,
        index,
        eof,
      );
      if (newIndex === -1) {
        const ctxText = nextChunkContext.join("\n");
        if (eof) {
          throw new DiffError(`Invalid EOF Context ${index}:\n${ctxText}`);
        } else {
          throw new DiffError(`Invalid Context ${index}:\n${ctxText}`);
        }
      }
      this.fuzz += fuzz;
      for (const ch of chunks) {
        ch.orig_index += newIndex;
        action.chunks.push(ch);
      }
      index = newIndex + nextChunkContext.length;
      this.index = endPatchIndex;
    }
    return action;
  }