|
| 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(", ")}`); |
0 commit comments