From 00a3078148e90a2d45648891f96158378c2561ce Mon Sep 17 00:00:00 2001 From: N0zoM1z0 <1705004398@qq.com> Date: Fri, 17 Jul 2026 02:00:39 +0800 Subject: [PATCH] fix(build): preserve native generated-file line endings Treat CRLF and LF as equivalent when checking committed text artifacts so Windows package lifecycles do not report false drift. When real generated content changes, retain the existing artifact's line-ending convention and cover both check and update behavior with a focused regression test. --- scripts/lib/generated-file.mjs | 15 +++++++++++++-- tests/productCatalog.test.ts | 25 +++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 2 deletions(-) diff --git a/scripts/lib/generated-file.mjs b/scripts/lib/generated-file.mjs index e3af72793..d7df714c6 100644 --- a/scripts/lib/generated-file.mjs +++ b/scripts/lib/generated-file.mjs @@ -6,6 +6,13 @@ const isMissing = (cause) => "code" in cause && cause.code === "ENOENT"; +const normalizeLineEndings = (value) => value.replaceAll("\r\n", "\n"); + +const preserveLineEndings = (source, existing) => + existing?.includes("\r\n") === true + ? normalizeLineEndings(source).replaceAll("\n", "\r\n") + : source; + /** Compare or update one generated text artifact with actionable diagnostics. */ export const ensureGeneratedFile = async ({ path, @@ -19,11 +26,15 @@ export const ensureGeneratedFile = async ({ } catch (cause) { if (!isMissing(cause)) throw cause; } - if (existing === source) return { changed: false }; + if ( + existing !== undefined && + normalizeLineEndings(existing) === normalizeLineEndings(source) + ) + return { changed: false }; if (check) throw new Error( `${path} is missing or stale. Run \`${generateCommand}\` and commit the result.`, ); - await writeFile(path, source, "utf8"); + await writeFile(path, preserveLineEndings(source, existing), "utf8"); return { changed: true }; }; diff --git a/tests/productCatalog.test.ts b/tests/productCatalog.test.ts index 78042b434..7f39ea40a 100644 --- a/tests/productCatalog.test.ts +++ b/tests/productCatalog.test.ts @@ -234,4 +234,29 @@ describe("canonical product catalog", () => { ).resolves.toEqual({ changed: true }); expect(await readFile(path, "utf8")).toBe("current\n"); }); + + it("accepts and preserves native generated-file line endings", async () => { + const directory = await mkdtemp(join(tmpdir(), "rea-generated-eol-")); + temporaryRoots.push(directory); + const path = join(directory, "catalog.json"); + await writeFile(path, "current\r\n", "utf8"); + await expect( + ensureGeneratedFile({ + path, + source: "current\n", + check: true, + generateCommand: "npm run docs:generate", + }), + ).resolves.toEqual({ changed: false }); + expect(await readFile(path, "utf8")).toBe("current\r\n"); + await expect( + ensureGeneratedFile({ + path, + source: "updated\n", + check: false, + generateCommand: "npm run docs:generate", + }), + ).resolves.toEqual({ changed: true }); + expect(await readFile(path, "utf8")).toBe("updated\r\n"); + }); });