refactor(ecommerce): extract platform rules and prompt builders

This commit is contained in:
2026-06-15 14:35:40 +08:00
parent 45e6534ee1
commit f30e585cfa
7 changed files with 848 additions and 547 deletions
@@ -12,18 +12,23 @@ import {
} from "./ratioUtils";
describe("normalizeRatioToken", () => {
it("converts fullwidth and mojibake characters", () => {
it("normalizes non-breaking spaces", () => {
expect(normalizeRatioToken("800\u00a0\u00a0px")).toBe("800 px");
});
it("replaces * with ×", () => {
it("replaces plain separators with the normal multiplication sign", () => {
expect(normalizeRatioToken("800*800")).toBe("800×800");
});
it("replaces mojibake 脳 with ×", () => {
expect(normalizeRatioToken("800脳800")).toBe("800×800");
it("replaces legacy mojibake multiply signs", () => {
expect(normalizeRatioToken("800\u8133800")).toBe("800×800");
});
it("replaces fullwidth colon", () => {
it("replaces fullwidth and legacy mojibake colons", () => {
expect(normalizeRatioToken("11")).toBe("1:1");
expect(normalizeRatioToken("1\u951b?1")).toBe("1:1");
});
it("collapses whitespace and trims", () => {
expect(normalizeRatioToken(" 1 : 1 ")).toBe("1 : 1");
});
@@ -34,10 +39,12 @@ describe("greatestCommonDivisor", () => {
expect(greatestCommonDivisor(12, 8)).toBe(4);
expect(greatestCommonDivisor(1920, 1080)).toBe(120);
});
it("handles zero with fallback to 1", () => {
expect(greatestCommonDivisor(0, 5)).toBe(5);
expect(greatestCommonDivisor(0, 0)).toBe(1);
});
it("handles negatives via abs", () => {
expect(greatestCommonDivisor(-12, 8)).toBe(4);
});
@@ -47,9 +54,11 @@ describe("formatAspectRatio", () => {
it("reduces 1920x1080 to 16:9", () => {
expect(formatAspectRatio(1920, 1080)).toBe("16:9");
});
it("reduces 750x1000 to 3:4", () => {
expect(formatAspectRatio(750, 1000)).toBe("3:4");
});
it("reduces 800x800 to 1:1", () => {
expect(formatAspectRatio(800, 800)).toBe("1:1");
});
@@ -59,13 +68,16 @@ describe("getQuickSetRatioValue", () => {
it("passes through a canonical quick-set value", () => {
expect(getQuickSetRatioValue("1:1")).toBe("1:1");
});
it("derives from a WxH size string", () => {
expect(getQuickSetRatioValue("1920×1080px")).toBe("16:9");
expect(getQuickSetRatioValue("750×1000px")).toBe("3:4");
});
it("derives from a raw ratio string", () => {
expect(getQuickSetRatioValue("9:16")).toBe("9:16");
});
it("falls back to 1:1 for unparseable input", () => {
expect(getQuickSetRatioValue("unknown")).toBe("1:1");
});
@@ -75,8 +87,13 @@ describe("formatRatioDisplayValue", () => {
it("formats a WxHpx string with aspect suffix", () => {
expect(formatRatioDisplayValue("1000×1000px 1:1")).toBe("1000×1000px\u00a0\u00a0\u00a01:1");
});
it("reformats 800×800px without explicit aspect", () => {
expect(formatRatioDisplayValue("800×800px")).toBe("800×800px\u00a0\u00a0\u00a01:1");
it("reformats 800x800px without explicit aspect", () => {
expect(formatRatioDisplayValue("800x800px")).toBe("800×800px\u00a0\u00a0\u00a01:1");
});
it("replaces legacy mojibake product image labels", () => {
expect(formatRatioDisplayValue("\u935f\u55d7\u6427\u9365?")).toBe("商品图");
});
});
@@ -87,6 +104,7 @@ describe("getRatioDisplayParts", () => {
aspect: "1:1",
});
});
it("uses 自适应 when no aspect present", () => {
const parts = getRatioDisplayParts("原图");
expect(parts.aspect).toBe("自适应");
@@ -97,6 +115,7 @@ describe("parseRatioToAspectCss", () => {
it("extracts CSS aspect-ratio", () => {
expect(parseRatioToAspectCss("1000×1000px 1:1")).toBe("1000 / 1000");
});
it("falls back to 1 / 1", () => {
expect(parseRatioToAspectCss("no numbers")).toBe("1 / 1");
});
@@ -106,18 +125,23 @@ describe("toSupportedImageApiRatio", () => {
it("snaps square to 1:1", () => {
expect(toSupportedImageApiRatio(800, 800)).toBe("1:1");
});
it("snaps 750x1000 to 3:4", () => {
expect(toSupportedImageApiRatio(750, 1000)).toBe("3:4");
});
it("snaps 1920x1080 to 16:9", () => {
expect(toSupportedImageApiRatio(1920, 1080)).toBe("16:9");
});
it("snaps 1080x1920 to 9:16", () => {
expect(toSupportedImageApiRatio(1080, 1920)).toBe("9:16");
});
it("snaps 800x600 to 4:3", () => {
expect(toSupportedImageApiRatio(800, 600)).toBe("4:3");
});
it("returns 1:1 for non-finite or non-positive", () => {
expect(toSupportedImageApiRatio(NaN, 100)).toBe("1:1");
expect(toSupportedImageApiRatio(0, 100)).toBe("1:1");
@@ -130,13 +154,16 @@ describe("normalizeRatioForApi", () => {
expect(normalizeRatioForApi("1000×1000px 1:1")).toBe("1:1");
expect(normalizeRatioForApi("750×1000px 3:4")).toBe("3:4");
});
it("derives ratio from a bare size string", () => {
expect(normalizeRatioForApi("1920×1080px")).toBe("16:9");
});
it("returns 1:1 for unparseable input", () => {
expect(normalizeRatioForApi("")).toBe("1:1");
expect(normalizeRatioForApi("无尺寸信息")).toBe("1:1");
});
it("uses the last explicit ratio when multiple present", () => {
expect(normalizeRatioForApi("4:3 16:9")).toBe("16:9");
});