Skip to content

Commit c634abc

Browse files
committed
feat: add scripts to filter and patch Shopware API schemas for compatibility
1 parent a3c2c2a commit c634abc

2 files changed

Lines changed: 96 additions & 0 deletions

File tree

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
// The full Shopware Admin API spec (adminapi.json, ~4MB, 409 schemas)
2+
// is so heavily cross-referenced and circular that openapi-zod-client
3+
// runs out of memory on it. Since only the Order entity schema is
4+
// needed for the webhook payloads, this script reduces the downloaded
5+
// spec before code generation:
6+
// - keeps the Order entity family and the leaf entities that matter
7+
// for order handling (addresses, states, currency) fully typed
8+
// - replaces $refs to any other entity with a permissive untyped
9+
// object, cutting the circular graph
10+
// This is acceptable for webhook payloads because Shopware business
11+
// events do not guarantee complete associations anyway (see
12+
// guides/plugins/apps/lifecycle/webhook.md in shopware/docs).
13+
// Runs as part of "generate:shopware-schemas" right after the download.
14+
import {readFileSync, writeFileSync} from "node:fs";
15+
16+
const KEEP_SCHEMAS = new Set([
17+
"Order",
18+
"OrderAddress",
19+
"OrderCustomer",
20+
"OrderDelivery",
21+
"OrderDeliveryPosition",
22+
"OrderLineItem",
23+
"OrderLineItemDownload",
24+
"OrderTransaction",
25+
"OrderTransactionCapture",
26+
"OrderTransactionCaptureRefund",
27+
"OrderTransactionCaptureRefundPosition",
28+
"StateMachineState",
29+
"Currency",
30+
"Country",
31+
"CountryState",
32+
"Salutation",
33+
]);
34+
35+
const input = new URL("../schemas/shopware-admin-openapi.json", import.meta.url);
36+
const output = new URL("../schemas/shopware-admin-openapi.filtered.json", import.meta.url);
37+
38+
const spec = JSON.parse(readFileSync(input, "utf8"));
39+
const allSchemas = spec.components.schemas;
40+
41+
for (const name of KEEP_SCHEMAS) {
42+
if (!(name in allSchemas)) {
43+
throw new Error(`Schema "${name}" not found in ${input}`);
44+
}
45+
}
46+
47+
// Replace $refs pointing outside KEEP_SCHEMAS with an untyped object.
48+
const stubForeignRefs = (node) => {
49+
if (Array.isArray(node)) {
50+
return node.map(stubForeignRefs);
51+
}
52+
if (node !== null && typeof node === "object") {
53+
const ref = node.$ref;
54+
if (typeof ref === "string") {
55+
const match = ref.match(/^#\/components\/schemas\/(.+)$/);
56+
if (match && !KEEP_SCHEMAS.has(match[1])) {
57+
return {type: "object", additionalProperties: true};
58+
}
59+
}
60+
return Object.fromEntries(Object.entries(node).map(([key, value]) => [key, stubForeignRefs(value)]));
61+
}
62+
return node;
63+
};
64+
65+
const filtered = {
66+
openapi: spec.openapi,
67+
info: spec.info,
68+
paths: {},
69+
components: {
70+
schemas: Object.fromEntries(
71+
[...KEEP_SCHEMAS].sort().map((name) => [name, stubForeignRefs(allSchemas[name])]),
72+
),
73+
},
74+
};
75+
76+
writeFileSync(output, JSON.stringify(filtered, null, 2));
77+
console.log(`Kept ${KEEP_SCHEMAS.size} of ${Object.keys(allSchemas).length} schemas: ${[...KEEP_SCHEMAS].sort().join(", ")}`);
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
// openapi-zod-client emits zod v3 code, but this project uses zod v4,
2+
// where z.record() requires an explicit key schema. Rewrites the
3+
// generated single-argument form z.record(Value) to
4+
// z.record(z.string(), Value).
5+
// The Shopware order schemas are mutually recursive, so the generator
6+
// wraps them in z.lazy() without type annotations, which fails the
7+
// typecheck under noImplicitAny (TS7022). Adds an explicit
8+
// z.ZodTypeAny annotation to those consts.
9+
// Runs as part of "generate:shopware-schemas" right after code generation.
10+
import {readFileSync, writeFileSync} from "node:fs";
11+
12+
const file = new URL("../src/generated/shopware-schemas.ts", import.meta.url);
13+
const source = readFileSync(file, "utf8");
14+
writeFileSync(
15+
file,
16+
source
17+
.replaceAll("z.record(", "z.record(z.string(), ")
18+
.replace(/^const (\w+) = z\.lazy\(/gm, "const $1: z.ZodTypeAny = z.lazy("),
19+
);

0 commit comments

Comments
 (0)