@haddowg/json-api-codegen 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"src-B24cYyjM.mjs","names":["REF_PREFIX","JSON_API_MEDIA_TYPE","refName","isSchema","parse","parseYaml"],"sources":["../src/build-descriptor.ts","../src/provenance.ts","../src/emit.ts","../src/emit-schemas.ts","../src/reader.ts","../src/index.ts"],"sourcesContent":["import type {\n ActionDescriptor,\n ApiDescriptor,\n AtomicDescriptor,\n Cardinality,\n ClientIdPolicy,\n CountableDescriptor,\n PaginatorKind,\n RelationDescriptor,\n RelationMutations,\n ResourceDescriptor,\n} from '@haddowg/json-api-client'\nimport { ATOMIC_EXT } from '@haddowg/json-api-client'\nimport type {\n HttpMethod,\n OpenApiDocument,\n OperationObject,\n PathItemObject,\n SchemaObject,\n SchemaOrBool,\n} from './openapi'\n\nconst REF_PREFIX = '#/components/schemas/'\nconst JSON_API_MEDIA_TYPE = 'application/vnd.api+json'\n\n/** Sort a record's keys for deterministic, snapshot-stable output. */\nfunction sortRecord<V>(record: Record<string, V>): Record<string, V> {\n const out: Record<string, V> = {}\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n for (const key of Object.keys(record).sort()) {\n out[key] = record[key]!\n }\n return out\n}\n\n/** Resolve a local schema name from a `#/components/schemas/X` ref. */\nfunction refName(ref: string): string | undefined {\n return ref.startsWith(REF_PREFIX) ? ref.slice(REF_PREFIX.length) : undefined\n}\n\nfunction isSchema(value: SchemaOrBool | undefined): value is SchemaObject {\n return typeof value === 'object' && value !== null\n}\n\n/** The set of `type` keys a JSON type node declares, with `\"null\"` removed. */\nfunction typeKeys(type: string | readonly string[] | undefined): string[] {\n if (type === undefined) {\n return []\n }\n return (Array.isArray(type) ? type : [type]).filter((t) => t !== 'null')\n}\n\nexport class DescriptorBuilder {\n private readonly schemas: Record<string, SchemaObject>\n private readonly paths: Record<string, PathItemObject>\n /** Lazily-built wire-type -> collection-level paginator kind (for per-relation divergence, D6a). */\n private typePaginators?: Map<string, PaginatorKind>\n\n constructor(private readonly doc: OpenApiDocument) {\n this.schemas = doc.components?.schemas ?? {}\n this.paths = doc.paths ?? {}\n }\n\n /**\n * The collection-level paginator kind for a WIRE type (`tracks`), memoised. Resolves each\n * resource schema's wire type (its `type.const`) to the paginator of its collection GET — the\n * baseline a per-relation related-endpoint paginator is compared against (D6a).\n */\n private typePaginator(wireType: string): PaginatorKind {\n if (this.typePaginators === undefined) {\n this.typePaginators = new Map()\n for (const [name, schema] of Object.entries(this.schemas)) {\n const type = this.resourceType(name, schema)\n if (type !== undefined) {\n this.typePaginators.set(type, this.paginator(name.slice(0, -'Resource'.length)))\n }\n }\n }\n return this.typePaginators.get(wireType) ?? 'none'\n }\n\n build(): ApiDescriptor {\n const out: Record<string, ResourceDescriptor> = {}\n for (const [name, schema] of Object.entries(this.schemas)) {\n const wireType = this.resourceType(name, schema)\n if (wireType === undefined) {\n continue\n }\n const base = name.slice(0, -'Resource'.length)\n const collection = this.collectionPath(base)\n const actions = collection ? this.actions(collection) : {}\n const descriptor: ResourceDescriptor = {\n attributes: this.attributes(base),\n relations: this.relations(schema, collection),\n paths: this.operationPaths(base),\n paginator: this.paginator(base),\n clientId: this.clientId(base),\n }\n const countable = this.countable(collection)\n if (countable !== undefined) {\n descriptor.countable = countable\n }\n const includable = this.includable(collection)\n if (includable !== undefined) {\n descriptor.includable = includable\n }\n const sortable = this.sortable(collection)\n if (sortable !== undefined) {\n descriptor.sortable = sortable\n }\n const filterable = this.filterable(collection)\n if (filterable !== undefined) {\n descriptor.filterable = filterable\n }\n if (Object.keys(actions).length > 0) {\n descriptor.actions = actions\n }\n // A synthetic stub for an unregistered related type — core's `permissiveResourceObject`\n // emits a `<Rel>Resource` carrying ONLY a `type` const (no `id`/`attributes`) so linkage\n // refs resolve — is reachable only through a parent's `.related()` (which works via the\n // parent's own paths). Admitting it would surface a fully-typed top-level `client.<stub>`\n // whose every method throws, so drop it (D27). A REAL registered resource carries the full\n // `type/id/attributes/…` object shape and stays, even with no attributes/collection of its\n // own; only the type-const-only stub (with no operation paths) is dropped.\n const isTypeOnlyStub = Object.keys(schema.properties ?? {}).every((prop) => prop === 'type')\n if (isTypeOnlyStub && Object.keys(descriptor.paths).length === 0) {\n continue\n }\n out[wireType] = descriptor\n }\n return sortRecord(out)\n }\n\n /**\n * The server-level Atomic Operations capability: the path whose `POST` requestBody\n * declares the atomic ext media type ({@link ATOMIC_EXT}). `null` when no such endpoint\n * exists. Server-level, so it rides {@link buildAtomic}, not the per-type descriptor.\n */\n buildAtomic(): AtomicDescriptor | null {\n for (const [path, item] of Object.entries(this.paths)) {\n const content = item.post?.requestBody?.content ?? {}\n if (Object.keys(content).some(isAtomicMediaType)) {\n return { path }\n }\n }\n return null\n }\n\n /**\n * A resource schema is one whose name ends in `Resource` (but not\n * `ResourceIdentifier`) and carries `properties.type.const` (a string) — that const\n * is the descriptor key (the wire type). Never inferred from the schema name.\n */\n private resourceType(name: string, schema: SchemaObject): string | undefined {\n if (!name.endsWith('Resource') || name.endsWith('ResourceIdentifier')) {\n return undefined\n }\n const constValue = schema.properties?.['type']\n if (isSchema(constValue) && typeof constValue.const === 'string') {\n return constValue.const\n }\n return undefined\n }\n\n /** Follow a `$ref` to its identifier/resource schema and read `properties.type.const`. */\n private resolveConst(ref: string): string | undefined {\n const target = refName(ref)\n if (target === undefined) {\n return undefined\n }\n const typeProp = this.schemas[target]?.properties?.['type']\n return isSchema(typeProp) && typeof typeProp.const === 'string' ? typeProp.const : undefined\n }\n\n private attributes(base: string): Record<string, string> {\n const attrs = this.schemas[`${base}Attributes`]\n const props = attrs?.properties\n if (props === undefined) {\n return {}\n }\n const out: Record<string, string> = {}\n for (const [name, prop] of Object.entries(props)) {\n if (isSchema(prop)) {\n out[name] = formatHint(prop)\n }\n }\n return sortRecord(out)\n }\n\n private relations(\n resource: SchemaObject,\n collection: string | undefined,\n ): Record<string, RelationDescriptor> {\n const relProps = isSchema(resource.properties?.['relationships'])\n ? resource.properties['relationships'].properties\n : undefined\n if (relProps === undefined) {\n return {}\n }\n const out: Record<string, RelationDescriptor> = {}\n for (const [name, prop] of Object.entries(relProps)) {\n if (!isSchema(prop) || typeof prop.$ref !== 'string') {\n continue\n }\n const component = this.schemas[refName(prop.$ref) ?? '']\n const descriptor = component ? this.relationFromComponent(component) : undefined\n if (descriptor === undefined) {\n // A relationship component the codegen can't parse (an unknown linkage shape) is\n // dropped silently otherwise — a drift class (the grammar has grown pivot/polymorphic/\n // nested forms), so warn rather than emit a client missing the relation (D28).\n // eslint-disable-next-line no-console\n console.warn(\n `json-api codegen: relationship \"${name}\" has an unrecognized linkage shape; dropping it from the descriptor.`,\n )\n continue\n }\n out[name] =\n collection === undefined\n ? descriptor\n : this.withRelationExposure(descriptor, collection, name)\n }\n return sortRecord(out)\n }\n\n /**\n * The per-relation mutation capability, derived from the HTTP methods the relationship\n * endpoint (`{collection}/{id}/relationships/{rel}`) advertises. For a to-many:\n * `add` <- POST, `remove` <- DELETE, `replace` <- PATCH. For a to-one: `set` <- PATCH.\n * Only `true` verbs are emitted (a missing verb is simply absent). Returns `undefined`\n * when the relation exposes no relationship endpoint at all.\n */\n private relationMutations(\n collection: string,\n rel: string,\n cardinality: RelationDescriptor['cardinality'],\n ): RelationMutations | undefined {\n const item = this.paths[`${collection}/{id}/relationships/${rel}`]\n if (item === undefined) {\n return undefined\n }\n const mutations: RelationMutations = {}\n if (cardinality === 'many') {\n if (item.post) {\n mutations.add = true\n }\n if (item.delete) {\n mutations.remove = true\n }\n if (item.patch) {\n mutations.replace = true\n }\n } else if (item.patch) {\n mutations.set = true\n }\n return mutations\n }\n\n /**\n * Attach the per-relation endpoint-exposure signal to a relation descriptor (D24). The bundle\n * can suppress a relation's related or relationship endpoint (`withoutRelatedEndpoint()` /\n * `withoutRelationshipEndpoint()`, ADR 0027), which the OpenAPI reflects by simply omitting that\n * relation's path — but codegen synthesizes generic `{rel}` templates, erasing the per-relation\n * distinction. So mark `related: false` / `relationship: false` when this relation's specific\n * path is absent, and ALWAYS emit an explicit `mutations` object (the verb flags when the\n * relationship endpoint exists, else `{}`) so the client gates a suppressed relation OFF rather\n * than failing open (offering `.get()`/`.related()`/mutations that 404).\n */\n private withRelationExposure(\n descriptor: RelationDescriptor,\n collection: string,\n name: string,\n ): RelationDescriptor {\n const out: RelationDescriptor = { ...descriptor }\n const relatedGet = this.operation(`${collection}/{id}/${name}`, 'get')\n if (relatedGet === undefined) {\n out.related = false\n }\n const mutations = this.relationMutations(collection, name, descriptor.cardinality)\n if (mutations === undefined) {\n out.relationship = false\n out.mutations = {}\n } else {\n out.mutations = mutations\n }\n // The related/relationship reads may advertise their own `withCount` (`_self_` + the relation's\n // countable relations) with a negotiation profile — capture it so a typed `.related()`/`.get()`\n // can send `withCount` and negotiate the profile the endpoint requires (D3).\n const countable =\n withCountParam(relatedGet) ??\n withCountParam(this.operation(`${collection}/{id}/relationships/${name}`, 'get'))\n if (countable !== undefined) {\n out.countable = countable\n }\n // A to-many related endpoint can advertise a DIFFERENT paginator than the related type's\n // top-level collection (D6a). Read the related-endpoint kind (preferring the related over the\n // relationship endpoint) and carry it ONLY when it diverges from the related type's collection\n // paginator — the client falls back to that type's paginator otherwise, so parity stays silent.\n if (descriptor.cardinality === 'many') {\n const relatedKind =\n this.paginatorKindOf(relatedGet) === 'none'\n ? this.paginatorKindOf(this.operation(`${collection}/{id}/relationships/${name}`, 'get'))\n : this.paginatorKindOf(relatedGet)\n const relatedType = descriptor.types[0]\n const typeKind = relatedType !== undefined ? this.typePaginator(relatedType) : 'none'\n if (relatedKind !== 'none' && relatedKind !== typeKind) {\n out.paginator = relatedKind\n }\n }\n return out\n }\n\n /**\n * Collect the custom actions for a type from its `{collection}/-actions/{name}` and\n * `{collection}/{id}/-actions/{name}` paths. The action name is the last segment; scope\n * is `resource` when the path carries `/{id}/`, else `collection`. `input` is `document`\n * (a JSON:API requestBody), `none` (no requestBody) or `raw` (a non-JSON:API body);\n * `output` is `document` (a 2xx returns a JSON:API document) or `none` (only `204`).\n */\n private actions(collection: string): Record<string, ActionDescriptor> {\n const out: Record<string, ActionDescriptor> = {}\n const collectionPrefix = `${collection}/-actions/`\n const resourcePrefix = `${collection}/{id}/-actions/`\n for (const [path, item] of Object.entries(this.paths)) {\n let scope: ActionDescriptor['scope']\n let name: string\n if (path.startsWith(resourcePrefix)) {\n scope = 'resource'\n name = path.slice(resourcePrefix.length)\n } else if (path.startsWith(collectionPrefix)) {\n scope = 'collection'\n name = path.slice(collectionPrefix.length)\n } else {\n continue\n }\n // The action name is a single trailing segment.\n if (name.length === 0 || name.includes('/')) {\n continue\n }\n // An action is invoked over one HTTP method; the bundle lets an author declare a\n // non-POST method, so read the advertised operation (POST-preferred) rather than only\n // `post` — else a GET/PATCH/DELETE-only action would silently vanish from the client.\n const picked = pickOperation(item)\n if (picked === undefined) {\n // eslint-disable-next-line no-console\n console.warn(\n `json-api codegen: custom action path \"${path}\" advertises no usable operation; skipping.`,\n )\n continue\n }\n const { method, op } = picked\n const input = actionInput(op)\n const output = actionOutput(op)\n const action: ActionDescriptor = { scope, path, input, output }\n // Only carried when non-POST (POST is the runtime default), keeping the common descriptor tiny.\n if (method !== 'post') {\n action.method = method.toUpperCase()\n }\n // A document input names its resource type so the client can accept FLAT input and build the\n // envelope (+ remap 422 pointers), matching `create`/`update` ergonomics.\n if (input === 'document') {\n const inputType = this.documentPrimary(actionRequestRef(op))?.type\n if (inputType !== undefined) {\n action.inputType = inputType\n }\n }\n // A document output names its primary resource type + cardinality so the client materialises\n // the response into that resource view (matching reads), not the raw wire envelope.\n if (output === 'document') {\n const primary = this.documentPrimary(this.firstOkJsonApiRef(op))\n if (primary !== undefined) {\n action.outputType = primary.type\n action.outputCardinality = primary.cardinality\n }\n }\n // A raw-input action carries its declared (non-JSON:API) media type so the client sends\n // the right `Content-Type` rather than a wildcard the server may reject.\n if (input === 'raw') {\n const contentType = rawContentType(op)\n if (contentType !== undefined) {\n action.contentType = contentType\n }\n }\n out[name] = action\n }\n return sortRecord(out)\n }\n\n /**\n * The wire type (and cardinality) of a document component's primary `data` — a `$ref` to a\n * resource, an inline object carrying `properties.type.const` (a create-request body), or an\n * array of resource/identifier refs (a collection). `undefined` when the type can't be resolved.\n */\n private documentPrimary(\n ref: string | undefined,\n ): { type: string; cardinality: Cardinality } | undefined {\n if (typeof ref !== 'string') {\n return undefined\n }\n const component = refName(ref)\n const data = component === undefined ? undefined : this.schemas[component]?.properties?.['data']\n if (!isSchema(data)) {\n return undefined\n }\n if (isSchema(data.items)) {\n const itemRef = data.items.$ref\n const many = typeof itemRef === 'string' ? this.resolveConst(itemRef) : undefined\n return many === undefined ? undefined : { type: many, cardinality: 'many' }\n }\n const one = this.dataConst(data)\n return one === undefined ? undefined : { type: one, cardinality: 'one' }\n }\n\n /** The wire type of a single `data` schema — a `$ref` to a resource, or an inline `type.const`. */\n private dataConst(data: SchemaObject): string | undefined {\n if (typeof data.$ref === 'string') {\n return this.resolveConst(data.$ref)\n }\n const typeProp = data.properties?.['type']\n return isSchema(typeProp) && typeof typeProp.const === 'string' ? typeProp.const : undefined\n }\n\n /** The `$ref` of the first 2xx JSON:API response body on an operation (the output document). */\n private firstOkJsonApiRef(op: OperationObject): string | undefined {\n for (const [code, response] of Object.entries(op.responses ?? {})) {\n if (!code.startsWith('2')) {\n continue\n }\n const ref = response.content?.[JSON_API_MEDIA_TYPE]?.schema?.$ref\n if (typeof ref === 'string') {\n return ref\n }\n }\n return undefined\n }\n\n /** Resolve a relationship component's `data` into a {@link RelationDescriptor}. */\n private relationFromComponent(component: SchemaObject): RelationDescriptor | undefined {\n const data = component.properties?.['data']\n if (!isSchema(data)) {\n return undefined\n }\n\n // to-many: data.type === 'array'\n if (data.type === 'array') {\n const items = data.items\n if (items === undefined) {\n return undefined\n }\n if (typeof items.$ref === 'string') {\n // monomorphic to-many\n const type = this.resolveConst(items.$ref)\n return type === undefined ? undefined : { cardinality: 'many', types: [type], pivot: false }\n }\n if (Array.isArray(items.allOf)) {\n // pivot to-many: the $ref is the allOf entry that carries it\n const type = this.constFromAllOf(items.allOf)\n if (type === undefined) {\n return undefined\n }\n const relation: RelationDescriptor = { cardinality: 'many', types: [type], pivot: true }\n const pivotFields = this.pivotFieldsFromAllOf(items.allOf)\n if (pivotFields !== undefined) {\n relation.pivotFields = pivotFields\n }\n return relation\n }\n if (Array.isArray(items.anyOf)) {\n // polymorphic to-many\n return { cardinality: 'many', types: this.constsFromRefs(items.anyOf), pivot: false }\n }\n return undefined\n }\n\n // to-one: data.anyOf with the non-null entries being $refs (or pivot allOfs);\n // a polymorphic to-one nests its $refs one level deeper in another anyOf.\n if (Array.isArray(data.anyOf)) {\n const types: string[] = []\n let pivot = false\n let pivotFields: Record<string, string> | undefined\n for (const entry of data.anyOf) {\n if (typeof entry.$ref === 'string') {\n const type = this.resolveConst(entry.$ref)\n if (type !== undefined) {\n types.push(type)\n }\n } else if (Array.isArray(entry.allOf)) {\n const type = this.constFromAllOf(entry.allOf)\n if (type !== undefined) {\n types.push(type)\n pivot = true\n pivotFields = this.pivotFieldsFromAllOf(entry.allOf)\n }\n } else if (Array.isArray(entry.anyOf)) {\n // polymorphic to-one: the non-null entry is itself an anyOf of $refs\n types.push(...this.constsFromRefs(entry.anyOf))\n }\n }\n if (types.length === 0) {\n return undefined\n }\n const relation: RelationDescriptor = { cardinality: 'one', types, pivot }\n if (pivotFields !== undefined) {\n relation.pivotFields = pivotFields\n }\n return relation\n }\n\n return undefined\n }\n\n /**\n * Extract the pivot field-shape from a pivot `allOf` — the entry carrying\n * `properties.meta.properties.pivot.properties` (a `belongsToMany` member's `meta.pivot`), as a\n * field-name → wire-format-hint map (D33). Returns `undefined` when the allOf carries no pivot\n * property block.\n */\n private pivotFieldsFromAllOf(allOf: readonly SchemaObject[]): Record<string, string> | undefined {\n for (const entry of allOf) {\n const meta = entry.properties?.['meta']\n const pivot = isSchema(meta) ? meta.properties?.['pivot'] : undefined\n const props = isSchema(pivot) ? pivot.properties : undefined\n if (props === undefined) {\n continue\n }\n const out: Record<string, string> = {}\n for (const [name, schema] of Object.entries(props)) {\n if (isSchema(schema)) {\n out[name] = formatHint(schema)\n }\n }\n return Object.keys(out).length > 0 ? sortRecord(out) : undefined\n }\n return undefined\n }\n\n /** Pull the related type from the `$ref` entry of an `allOf` (the pivot shape). */\n private constFromAllOf(allOf: readonly SchemaObject[]): string | undefined {\n for (const entry of allOf) {\n if (typeof entry.$ref === 'string') {\n const type = this.resolveConst(entry.$ref)\n if (type !== undefined) {\n return type\n }\n }\n }\n return undefined\n }\n\n /** Resolve every `$ref` entry in a list to its wire type. */\n private constsFromRefs(entries: readonly SchemaObject[]): string[] {\n const types: string[] = []\n for (const entry of entries) {\n if (typeof entry.$ref === 'string') {\n const type = this.resolveConst(entry.$ref)\n if (type !== undefined) {\n types.push(type)\n }\n }\n }\n return types\n }\n\n private clientId(base: string): ClientIdPolicy {\n const create = this.schemas[`${base}CreateRequest`]\n const data = isSchema(create?.properties?.['data']) ? create.properties['data'] : undefined\n if (data === undefined) {\n return 'forbidden'\n }\n if (data.properties?.['id'] === false) {\n return 'forbidden'\n }\n return data.required?.includes('id') ? 'required' : 'optional'\n }\n\n /**\n * Find the collection path for a type, then derive each per-operation path that\n * actually exists. The collection path P is the one whose POST requestBody refs\n * `<Base>CreateRequest`, else the GET whose 200 response refs `<Base>Collection`.\n */\n private operationPaths(base: string): Record<string, string> {\n const collection = this.collectionPath(base)\n const out: Record<string, string> = {}\n if (collection === undefined) {\n return out\n }\n\n if (this.operation(collection, 'get')) {\n out['fetchMany'] = collection\n }\n if (this.operation(collection, 'post')) {\n out['create'] = collection\n }\n\n const item = `${collection}/{id}`\n if (this.operation(item, 'get')) {\n out['fetchOne'] = item\n }\n if (this.operation(item, 'patch')) {\n out['update'] = item\n }\n if (this.operation(item, 'delete')) {\n out['delete'] = item\n }\n\n if (this.hasRelatedPath(collection)) {\n out['fetchRelated'] = `${collection}/{id}/{rel}`\n }\n if (this.hasRelationshipPath(collection)) {\n out['fetchRelationship'] = `${collection}/{id}/relationships/{rel}`\n }\n\n return sortRecord(out)\n }\n\n private collectionPath(base: string): string | undefined {\n let byCollection: string | undefined\n for (const [path, item] of Object.entries(this.paths)) {\n const post = item.post\n if (post && refEndsWith(this.requestBodyRef(post), `${base}CreateRequest`)) {\n return path\n }\n // Only a genuine top-level collection qualifies for the response-ref fallback —\n // a parent-scoped *related* collection (e.g. `/users/{id}/playlists`) also refs\n // `<Base>Collection` but is not a fetchMany endpoint for that type.\n if (\n byCollection === undefined &&\n !path.includes('/{id}/') &&\n refEndsWith(this.okResponseRef(item.get), `${base}Collection`)\n ) {\n byCollection = path\n }\n }\n return byCollection\n }\n\n /** Any `P/{id}/<rel>` related path (excludes relationships/ and custom `-actions`). */\n private hasRelatedPath(collection: string): boolean {\n const prefix = `${collection}/{id}/`\n return Object.keys(this.paths).some((path) => {\n if (!path.startsWith(prefix)) {\n return false\n }\n const rest = path.slice(prefix.length)\n return rest.length > 0 && !rest.includes('/') && !rest.startsWith('-')\n })\n }\n\n private hasRelationshipPath(collection: string): boolean {\n const prefix = `${collection}/{id}/relationships/`\n return Object.keys(this.paths).some(\n (path) => path.startsWith(prefix) && !path.slice(prefix.length).includes('/'),\n )\n }\n\n /** Detect the paginator kind from the fetchMany operation's query parameter names. */\n private paginator(base: string): PaginatorKind {\n const collection = this.collectionPath(base)\n return this.paginatorKindOf(this.operation(collection ?? '', 'get'), collection)\n }\n\n /**\n * Detect the paginator kind an operation advertises from its `page[...]` query parameter names.\n * `page[number]`+`page[size]` = `page`; `page[offset]`+`page[limit]` = `offset`; either cursor\n * bound (`page[after]`/`page[before]`) = `cursor` (link-driven, D44); anything else = `none`.\n * `label` (a path, for the drift warning) names the endpoint when page params match no known kind.\n */\n private paginatorKindOf(op: OperationObject | undefined, label?: string): PaginatorKind {\n const names = this.queryParamNames(op)\n if (names.has('page[number]') && names.has('page[size]')) {\n return 'page'\n }\n if (names.has('page[offset]') && names.has('page[limit]')) {\n return 'offset'\n }\n // Cursor pagination advertises page[after]/page[before] (the CursorPaginator wire form) — the\n // client's cursor navigation is link-driven, so either bound present marks the kind (D44).\n if (names.has('page[after]') || names.has('page[before]')) {\n return 'cursor'\n }\n // Page params present but matching no known kind = a drift the client would silently treat\n // as unpaginated (losing $page/$next); warn rather than swallow it (D28).\n if (label !== undefined && [...names].some((name) => name.startsWith('page['))) {\n // eslint-disable-next-line no-console\n console.warn(\n `json-api codegen: endpoint \"${label}\" advertises page parameters matching no known paginator kind; treating it as unpaginated.`,\n )\n }\n return 'none'\n }\n\n /**\n * The `withCount` capability (Countable profile) for a type's COLLECTION read (`list`): the\n * count tokens (`schema.items.enum`) + the negotiation profile (`x-profile`) carried by the\n * collection GET's `withCount` query parameter. Returns `undefined` when the collection\n * doesn't exist or advertises no `withCount`. The profile URI is never hardcoded — it is read\n * from the parameter's `x-profile`.\n *\n * Deliberately scoped to the collection GET only. The per-endpoint token sets differ\n * (a collection counts e.g. `tracks`; a related/relationship endpoint counts `_self_` and its\n * own relations), so a single per-type `countable` can only honestly describe one endpoint.\n * The fluent surface exposes `withCount` on `list` (the collection), so `countable` mirrors\n * that endpoint — a related-GET fallback would advertise tokens `list` cannot legally send.\n */\n private countable(collection: string | undefined): CountableDescriptor | undefined {\n if (collection === undefined) {\n return undefined\n }\n return withCountParam(this.operation(collection, 'get'))\n }\n\n /**\n * The relation paths the read endpoints accept in `include` — the `include` query\n * parameter's `schema.items.enum` (already including nested dotted paths) on the collection\n * GET. Returns `undefined` when the collection advertises no `include` (nothing includable).\n *\n * Read from the collection GET to mirror {@see sortable}/{@see filterable}: the whole builder\n * is collection-centric (a type with no collection path gets no `paths` at all), and the bundle\n * advertises the same `include` enum on the collection and single-resource GETs.\n */\n private includable(collection: string | undefined): readonly string[] | undefined {\n if (collection === undefined) {\n return undefined\n }\n const tokens = paramItemsEnum(this.operation(collection, 'get'), 'include')\n return tokens !== undefined && tokens.length > 0 ? tokens : undefined\n }\n\n /**\n * The sort tokens the COLLECTION read accepts — the `sort` query parameter's\n * `schema.items.enum` (signed field names) on the collection GET. Returns `undefined` when\n * the collection advertises no `sort` parameter (sorting unsupported).\n */\n private sortable(collection: string | undefined): readonly string[] | undefined {\n if (collection === undefined) {\n return undefined\n }\n const tokens = paramItemsEnum(this.operation(collection, 'get'), 'sort')\n return tokens !== undefined && tokens.length > 0 ? tokens : undefined\n }\n\n /**\n * The filter keys the COLLECTION read accepts in `filter[...]` (the `filter[<key>]` parameter\n * names, `<key>` extracted), sorted for deterministic output. Returns `undefined` when the\n * collection advertises no `filter[...]` parameters (filtering unsupported). Value shapes are\n * deliberately not captured — `filter` values stay `unknown` (out of scope for v0.1).\n */\n private filterable(collection: string | undefined): readonly string[] | undefined {\n if (collection === undefined) {\n return undefined\n }\n const keys: string[] = []\n for (const param of this.operation(collection, 'get')?.parameters ?? []) {\n const name = param.name\n if (typeof name === 'string' && name.startsWith('filter[') && name.endsWith(']')) {\n keys.push(name.slice('filter['.length, -1))\n }\n }\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n return keys.length > 0 ? keys.sort() : undefined\n }\n\n private queryParamNames(op: OperationObject | undefined): Set<string> {\n const names = new Set<string>()\n for (const param of op?.parameters ?? []) {\n if (typeof param.name === 'string') {\n names.add(param.name)\n }\n }\n return names\n }\n\n private operation(path: string, method: HttpMethod): OperationObject | undefined {\n return this.paths[path]?.[method]\n }\n\n private requestBodyRef(op: OperationObject | undefined): string | undefined {\n return op?.requestBody?.content?.['application/vnd.api+json']?.schema?.$ref\n }\n\n private okResponseRef(op: OperationObject | undefined): string | undefined {\n return op?.responses?.['200']?.content?.['application/vnd.api+json']?.schema?.$ref\n }\n}\n\n/** A schema's wire format hint: explicit `format`, else the JSON type, else a ref-enum is `string`. */\nfunction formatHint(schema: SchemaObject): string {\n if (typeof schema.format === 'string') {\n return schema.format\n }\n const types = typeKeys(schema.type)\n if (types.length > 0) {\n return types[0]!\n }\n // A $ref (typically an enum component) renders as a string union.\n if (typeof schema.$ref === 'string') {\n return 'string'\n }\n return 'unknown'\n}\n\nfunction refEndsWith(ref: string | undefined, suffix: string): boolean {\n return ref !== undefined && refName(ref) === suffix\n}\n\n/**\n * Read the {@link CountableDescriptor} off an operation's `withCount` query parameter: the\n * count tokens from its `schema.items.enum` and the negotiation profile from `x-profile`.\n * Returns `undefined` when the operation has no `withCount` parameter, or when one is present\n * but carries no `x-profile` (a `withCount` we can't tell a client how to negotiate). An empty\n * or absent token enum yields `[]` tokens (the profile alone is still actionable).\n */\nfunction withCountParam(op: OperationObject | undefined): CountableDescriptor | undefined {\n for (const param of op?.parameters ?? []) {\n if (param.name !== 'withCount') {\n continue\n }\n const profile = param['x-profile']\n if (typeof profile !== 'string') {\n return undefined\n }\n const enumValues = param.schema?.items?.enum\n const tokens = Array.isArray(enumValues)\n ? enumValues.filter((v): v is string => typeof v === 'string')\n : []\n return { tokens, profile }\n }\n return undefined\n}\n\n/**\n * The string members of an array-valued query parameter's `schema.items.enum` (the shape the\n * `include` and `sort` parameters use). Returns `undefined` when the operation carries no\n * parameter of that name, or one whose schema declares no enum.\n */\nfunction paramItemsEnum(\n op: OperationObject | undefined,\n paramName: string,\n): readonly string[] | undefined {\n for (const param of op?.parameters ?? []) {\n if (param.name !== paramName) {\n continue\n }\n const enumValues = param.schema?.items?.enum\n return Array.isArray(enumValues)\n ? enumValues.filter((v): v is string => typeof v === 'string')\n : undefined\n }\n return undefined\n}\n\n/**\n * True for the Atomic Operations ext media type — `application/vnd.api+json` carrying the\n * atomic `ext` parameter ({@link ATOMIC_EXT}). Tolerant of quoting/whitespace so any of\n * `ext=\"…\"` / `ext=…` matches.\n */\nfunction isAtomicMediaType(mediaType: string): boolean {\n return mediaType.startsWith(JSON_API_MEDIA_TYPE) && mediaType.includes(ATOMIC_EXT)\n}\n\n/** The HTTP methods an action operation may be advertised under, in resolution preference order. */\nconst ACTION_METHODS: readonly HttpMethod[] = ['post', 'get', 'put', 'patch', 'delete']\n\n/**\n * The single operation an action is invoked over: POST when advertised (the common default), else\n * the first advertised method. `undefined` when the path item carries no operation at all.\n */\nfunction pickOperation(\n item: PathItemObject,\n): { method: HttpMethod; op: OperationObject } | undefined {\n const available = ACTION_METHODS.filter((method) => item[method] !== undefined)\n const method = available.includes('post') ? 'post' : available[0]\n if (method === undefined) {\n return undefined\n }\n const op = item[method]\n return op === undefined ? undefined : { method, op }\n}\n\n/** The body shape a custom action accepts: a JSON:API document, none, or a raw payload. */\nfunction actionInput(op: OperationObject): ActionDescriptor['input'] {\n const content = op.requestBody?.content\n if (content === undefined || Object.keys(content).length === 0) {\n return 'none'\n }\n return JSON_API_MEDIA_TYPE in content ? 'document' : 'raw'\n}\n\n/** The `$ref` of an action's JSON:API request body (a `document` input), or `undefined`. */\nfunction actionRequestRef(op: OperationObject): string | undefined {\n const ref = op.requestBody?.content?.[JSON_API_MEDIA_TYPE]?.schema?.$ref\n return typeof ref === 'string' ? ref : undefined\n}\n\n/** The declared media type of a `raw`-input action — the first non-JSON:API content type. */\nfunction rawContentType(op: OperationObject): string | undefined {\n const content = op.requestBody?.content\n if (content === undefined) {\n return undefined\n }\n return Object.keys(content).find((mediaType) => mediaType !== JSON_API_MEDIA_TYPE)\n}\n\n/**\n * What a custom action returns from its first 2xx response: a `meta`-only document (a `$ref` to the\n * shared `MetaDocument` — no `data`), a resource `document` (any other JSON:API body), or `none`\n * (only a `204`).\n */\nfunction actionOutput(op: OperationObject): ActionDescriptor['output'] {\n for (const [code, response] of Object.entries(op.responses ?? {})) {\n if (!code.startsWith('2')) {\n continue\n }\n const schema = response.content?.[JSON_API_MEDIA_TYPE]?.schema\n if (schema === undefined) {\n continue\n }\n return typeof schema.$ref === 'string' && refName(schema.$ref) === 'MetaDocument'\n ? 'meta'\n : 'document'\n }\n return 'none'\n}\n\n/** Build the {@link ApiDescriptor} from a parsed OpenAPI document. */\nexport function buildDescriptor(doc: OpenApiDocument): ApiDescriptor {\n return new DescriptorBuilder(doc).build()\n}\n\n/** Detect the server-level Atomic Operations capability (`null` when none). */\nexport function buildAtomic(doc: OpenApiDocument): AtomicDescriptor | null {\n return new DescriptorBuilder(doc).buildAtomic()\n}\n","import { createHash } from 'node:crypto'\nimport type { OpenApiDocument } from './openapi'\n\n/**\n * A deterministic provenance record identifying the spec a client was generated from.\n * Stamped into every generated artifact's header so a reader (and the `--check` drift\n * gate) can tell which spec produced the committed output. Deliberately timestamp-free\n * — the same spec must always produce byte-identical output so `--check` can compare.\n */\nexport interface Provenance {\n /** `<title> <version>` from the document's `info` (falls back to `unknown` parts). */\n readonly source: string\n /** The first declared server URL, or `undefined` when none is declared. */\n readonly server: string | undefined\n /** A SHA-256 (first 16 hex chars) of the canonicalised source document. */\n readonly hash: string\n}\n\n/**\n * Canonicalise a JSON value with object keys sorted recursively, so the content hash is\n * insensitive to key ordering in the served document (two byte-different-but-equivalent\n * specs hash the same). Arrays keep their order (it is significant in OpenAPI).\n */\nfunction canonicalise(value: unknown): unknown {\n if (Array.isArray(value)) {\n return value.map(canonicalise)\n }\n if (value !== null && typeof value === 'object') {\n const out: Record<string, unknown> = {}\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n for (const key of Object.keys(value).sort()) {\n out[key] = canonicalise((value as Record<string, unknown>)[key])\n }\n return out\n }\n return value\n}\n\n/** A SHA-256 over an arbitrary JSON value (canonicalised), truncated to 16 hex chars (64 bits). */\nexport function hashJson(value: unknown): string {\n return createHash('sha256')\n .update(JSON.stringify(canonicalise(value)))\n .digest('hex')\n .slice(0, 16)\n}\n\n/**\n * Derive the provenance record for a source OpenAPI document. The `source` identifier is\n * `<info.title> <info.version>` (each part `unknown` when absent); the `hash` is a stable\n * content hash of the whole document.\n */\nexport function deriveProvenance(doc: OpenApiDocument): Provenance {\n const title = doc.info?.title ?? 'unknown'\n const version = doc.info?.version ?? 'unknown'\n return {\n source: `${title} ${version}`,\n server: doc.servers?.[0]?.url,\n hash: hashJson(doc),\n }\n}\n\n/**\n * Render the provenance record as the JSDoc header lines stamped into a generated artifact\n * (each already prefixed with ` * `). Deterministic: no timestamp, so re-generating from the\n * same spec yields byte-identical output.\n */\nexport function provenanceLines(provenance: Provenance): string[] {\n const lines = [` * Source spec: ${provenance.source}`, ` * Spec hash: ${provenance.hash}`]\n if (provenance.server !== undefined) {\n lines.splice(1, 0, ` * Server: ${provenance.server}`)\n }\n return lines\n}\n","import {\n type ActionDescriptor,\n type ApiDescriptor,\n type AtomicDescriptor,\n HANDLE_RESERVED,\n type ResourceDescriptor,\n} from '@haddowg/json-api-client'\nimport { buildAtomic } from './build-descriptor'\nimport type { OpenApiDocument, SchemaObject, SchemaOrBool } from './openapi'\nimport { deriveProvenance, provenanceLines, type Provenance } from './provenance'\n\nconst REF_PREFIX = '#/components/schemas/'\nconst JSON_API_MEDIA_TYPE = 'application/vnd.api+json'\n\n/** A loose JSON:API document shape — the fallback an action body/result types as when its component can't be resolved. */\nconst LOOSE_DOCUMENT = 'Record<string, unknown>'\n\n/** A relation name that will later collide with a fluent-surface verb. */\nexport interface VerbCollision {\n type: string\n relation: string\n}\n\n/**\n * The reserved relation names: the members the read handle actually shadows (kept in sync\n * via the runtime's {@link HANDLE_RESERVED}) plus the future Phase-3 write verbs. A relation\n * named like any of these must route through `.rel(name)`, so the codegen warns at build time.\n * (`type`/`id` from {@link HANDLE_RESERVED} can never be JSON:API relation names.)\n */\nconst RESERVED_VERBS = new Set<string>([\n ...HANDLE_RESERVED,\n 'update',\n 'delete',\n 'create',\n 'list',\n 'actions',\n])\n\n/**\n * Find relations whose name shadows a reserved fluent-surface member (a handle accessor or a\n * future write verb). Such relations are routed via `.rel(name)`; the codegen warns at build time.\n */\nexport function detectVerbCollisions(descriptor: ApiDescriptor): VerbCollision[] {\n const collisions: VerbCollision[] = []\n for (const type of Object.keys(descriptor)) {\n for (const relation of Object.keys(descriptor[type]!.relations)) {\n if (RESERVED_VERBS.has(relation)) {\n collisions.push({ type, relation })\n }\n }\n }\n return collisions\n}\n\nfunction refName(ref: string): string | undefined {\n return ref.startsWith(REF_PREFIX) ? ref.slice(REF_PREFIX.length) : undefined\n}\n\nfunction isSchema(value: SchemaOrBool | undefined): value is SchemaObject {\n return typeof value === 'object' && value !== null\n}\n\n/** PascalCase a JSON:API wire type for use in a TS identifier (e.g. `public-profiles` -> `PublicProfiles`). */\nfunction pascalCase(value: string): string {\n return value\n .split(/[^a-zA-Z0-9]+/)\n .filter((part) => part.length > 0)\n .map((part) => part.charAt(0).toUpperCase() + part.slice(1))\n .join('')\n}\n\n/** Emit a JSON-string literal (used for keys that aren't bare identifiers and enum members). */\nfunction quote(value: string): string {\n return JSON.stringify(value)\n}\n\n/** True when a string is a safe bare object-key identifier. */\nfunction isIdentifier(value: string): boolean {\n return /^[A-Za-z_$][A-Za-z0-9_$]*$/.test(value)\n}\n\nfunction objectKey(value: string): string {\n return isIdentifier(value) ? value : quote(value)\n}\n\n/**\n * Render a description as a JSDoc comment at the given indent — single-line when it fits,\n * a block otherwise. Returns `undefined` for empty text. Neutralises any `*\\/` so a\n * description can never terminate the comment early.\n */\nfunction jsDoc(text: string | undefined, indent: string): string | undefined {\n const trimmed = text?.trim()\n if (!trimmed) {\n return undefined\n }\n const lines = trimmed.replace(/\\*\\//g, '* /').split('\\n')\n if (lines.length === 1) {\n return `${indent}/** ${lines[0]} */`\n }\n return [\n `${indent}/**`,\n ...lines.map((line) => `${indent} * ${line}`.trimEnd()),\n `${indent} */`,\n ].join('\\n')\n}\n\nexport class Emitter {\n private readonly schemas: Record<string, SchemaObject>\n /** Wire type -> the schema `Base` (the `<Base>Resource` name minus `Resource`). */\n private readonly baseByType: Map<string, string>\n /** Enum component names referenced by an attribute, in first-seen order. */\n private readonly usedEnums = new Map<string, SchemaObject>()\n /**\n * Component-schema names whose dedicated interface is emitted (e.g. `AlbumsAttributes`,\n * `AlbumsCreateAttributes`). A `$ref` to one of these resolves to the interface name\n * rather than being re-expanded structurally — so an action envelope nests the precise,\n * already-named attribute type. Populated as interfaces are emitted.\n */\n private readonly emittedInterfaces = new Set<string>()\n /** Component names mid-expansion in {@link tsType} — a cycle guard for self/mutually-referential `$ref`s. */\n private readonly expanding = new Set<string>()\n /**\n * The per-action alias names actually emitted, keyed `type -> actionName -> { input?; output? }`.\n * Populated by {@link actionTypeAliases}; consumed by {@link actionTypesMap} so the action\n * type-map only references aliases that exist (a `none` input/output contributes neither).\n */\n private readonly actionAliasNames = new Map<\n string,\n Map<string, { input?: string; output?: string }>\n >()\n\n /** Provenance of the source document, stamped into the generated header for drift tracking. */\n private readonly provenance: Provenance\n\n constructor(\n private readonly doc: OpenApiDocument,\n private readonly descriptor: ApiDescriptor,\n private readonly atomic: AtomicDescriptor | null,\n ) {\n this.schemas = doc.components?.schemas ?? {}\n this.baseByType = this.indexBases()\n this.provenance = deriveProvenance(doc)\n }\n\n /** Map each declared wire type back to the `Base` of its resource schema. */\n private indexBases(): Map<string, string> {\n const out = new Map<string, string>()\n for (const [name, schema] of Object.entries(this.schemas)) {\n if (!name.endsWith('Resource') || name.endsWith('ResourceIdentifier')) {\n continue\n }\n const typeProp = schema.properties?.['type']\n if (isSchema(typeProp) && typeof typeProp.const === 'string') {\n out.set(typeProp.const, name.slice(0, -'Resource'.length))\n }\n }\n return out\n }\n\n emit(): string {\n // Resolve enums first so the alias block (which depends on `usedEnums`) is populated.\n const interfaces = Object.keys(this.descriptor).map((type) => this.attributeInterface(type))\n const writeInterfaces = Object.keys(this.descriptor).flatMap((type) =>\n this.writeAttributeInterfaces(type),\n )\n // Action input/output aliases reference component schemas; resolve them (this also\n // records any enums they reach) before the enum block is emitted.\n const actionAliases = this.actionTypeAliases()\n const enums = this.enumAliases()\n\n const parts = [\n this.header(),\n this.imports(),\n ...(enums ? [enums] : []),\n ...interfaces,\n ...writeInterfaces,\n ...actionAliases,\n this.attributesMap(),\n this.writeAttributesMap(),\n this.actionTypesMap(),\n this.resourceMap(),\n 'export type ResourceMap = typeof resourceMap',\n this.atomicConst(),\n this.boundFactory(),\n ]\n return `${parts.join('\\n\\n')}\\n`\n }\n\n private header(): string {\n return [\n '/**',\n ' * AUTO-GENERATED by @haddowg/json-api-codegen — do not edit by hand.',\n ' * Regenerate from the source OpenAPI document instead.',\n ' *',\n ...provenanceLines(this.provenance),\n ' */',\n ].join('\\n')\n }\n\n private imports(): string {\n return [\n 'import {',\n ' type ApiDescriptor,',\n ' type ClientOptions,',\n ' createClient as createClientRuntime,',\n \"} from '@haddowg/json-api-client'\",\n ].join('\\n')\n }\n\n /** Per-type attribute interface, e.g. `export interface AlbumsAttributes { ... }`. */\n private attributeInterface(type: string): string {\n const base = this.baseByType.get(type)\n const props = base ? this.schemas[`${base}Attributes`]?.properties : undefined\n // Drive field order off the (sorted) descriptor so output stays deterministic; read\n // attributes are always present (every member required, no optional marker).\n const fields = Object.keys(this.descriptor[type]!.attributes)\n return this.renderInterface(`${pascalCase(type)}Attributes`, props, fields, () => true)\n }\n\n /**\n * The per-type WRITE attribute interfaces — `<Pascal>CreateAttributes` and\n * `<Pascal>UpdateAttributes` — from the `<Base>CreateAttributes`/`<Base>UpdateAttributes`\n * components (readOnly fields are already excluded vs the read attributes by the bundle).\n * Create marks a field required iff it sits in the component's `required`; Update makes\n * every field optional. A read-only type (no create/update component) contributes nothing.\n */\n private writeAttributeInterfaces(type: string): string[] {\n const base = this.baseByType.get(type)\n if (base === undefined) {\n return []\n }\n const pascal = pascalCase(type)\n const out: string[] = []\n\n const create = this.schemas[`${base}CreateAttributes`]\n if (create !== undefined) {\n const required = new Set(create.required ?? [])\n // Sort the schema's own property keys (no descriptor to order write fields).\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n const fields = Object.keys(create.properties ?? {}).sort()\n out.push(\n this.renderInterface(`${pascal}CreateAttributes`, create.properties, fields, (field) =>\n required.has(field),\n ),\n )\n }\n\n const update = this.schemas[`${base}UpdateAttributes`]\n if (update !== undefined) {\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n const fields = Object.keys(update.properties ?? {}).sort()\n out.push(\n this.renderInterface(`${pascal}UpdateAttributes`, update.properties, fields, () => false),\n )\n }\n\n return out\n }\n\n /**\n * Per-action input/output type aliases for every type that declares custom actions. An\n * action whose `input`/`output` resolves to a component schema gets a named alias\n * (`<Pascal><Action>Input` / `<Pascal><Action>Output`) expanding that component via the\n * shared {@link tsType} machinery — a `none` input/output (no body / a `204`) contributes\n * no alias. Deterministic order: types, then action names (the descriptor is sorted).\n */\n private actionTypeAliases(): string[] {\n const out: string[] = []\n for (const type of Object.keys(this.descriptor)) {\n const actions = this.descriptor[type]?.actions\n if (actions === undefined) {\n continue\n }\n const pascal = pascalCase(type)\n for (const [actionName, action] of Object.entries(actions)) {\n const member = `${pascal}${pascalCase(actionName)}`\n const names: { input?: string; output?: string } = {}\n const inputType = this.actionBodyType(action, 'input')\n if (inputType !== undefined) {\n out.push(`export type ${member}Input = ${inputType}`)\n names.input = `${member}Input`\n }\n const outputType = this.actionBodyType(action, 'output')\n if (outputType !== undefined) {\n out.push(`export type ${member}Output = ${outputType}`)\n names.output = `${member}Output`\n }\n if (names.input !== undefined || names.output !== undefined) {\n let byAction = this.actionAliasNames.get(type)\n if (byAction === undefined) {\n byAction = new Map()\n this.actionAliasNames.set(type, byAction)\n }\n byAction.set(actionName, names)\n }\n }\n }\n return out\n }\n\n /**\n * Emit the `ActionTypes` interface wiring the emitted per-action aliases onto the typed\n * action surface — `type -> actionName -> { input?; output? }`, the client's fourth type\n * argument. So `client.albums.id(id).actions.reissue(body)` takes `AlbumsReissueInput` and\n * resolves `AlbumsReissueOutput` rather than a loose `Record<string,unknown>` / `unknown`.\n * Only actions whose alias was emitted appear (a `none`-input/output action contributes the\n * absent side, which the runtime types fall back to loosely). Emits `{}` when none exist.\n */\n private actionTypesMap(): string {\n const typeLines: string[] = []\n for (const type of Object.keys(this.descriptor)) {\n const byAction = this.actionAliasNames.get(type)\n if (byAction === undefined || byAction.size === 0) {\n continue\n }\n const actionLines: string[] = []\n for (const [actionName, names] of byAction) {\n const members: string[] = []\n if (names.input !== undefined) {\n members.push(`input: ${names.input}`)\n }\n if (names.output !== undefined) {\n members.push(`output: ${names.output}`)\n }\n actionLines.push(` ${objectKey(actionName)}: { ${members.join('; ')} }`)\n }\n typeLines.push(` ${objectKey(type)}: {\\n${actionLines.join('\\n')}\\n }`)\n }\n if (typeLines.length === 0) {\n return 'export interface ActionTypes {}'\n }\n return `export interface ActionTypes {\\n${typeLines.join('\\n')}\\n}`\n }\n\n /**\n * The TS type alias (if any) for an action's request body.\n *\n * An action's RESULT and its FLAT input are derived at the type level from the descriptor\n * (`outputType`/`outputCardinality` → the materialised resource view; `inputType` → the\n * `CreateInput` of that type), so no `output` alias is emitted and a `document` input whose\n * resource type resolves emits no `input` alias either. Only a bespoke command document (a\n * `document` input with no resolvable `inputType`) keeps a raw-envelope alias as its typed body,\n * expanded via {@link tsType} (falling back to a loose JSON:API document shape).\n */\n private actionBodyType(action: ActionDescriptor, side: 'input' | 'output'): string | undefined {\n if (side === 'output' || action.input !== 'document' || action.inputType !== undefined) {\n return undefined\n }\n const op = this.doc.paths?.[action.path]?.post\n const ref = op?.requestBody?.content?.[JSON_API_MEDIA_TYPE]?.schema?.$ref\n if (typeof ref !== 'string') {\n return LOOSE_DOCUMENT\n }\n const target = refName(ref)\n const resolved = target ? this.schemas[target] : undefined\n return resolved ? this.tsType(resolved) : LOOSE_DOCUMENT\n }\n\n /** Emit the server-level atomic capability constant (`{ path }` or `null`). */\n private atomicConst(): string {\n const doc = [\n '/**',\n ' * The server-level Atomic Operations endpoint (the atomic ext media type), or `null`',\n ' * when this server exposes none. The runtime `client.atomic` builder posts the batch here.',\n ' */',\n ].join('\\n')\n const value = this.atomic === null ? 'null' : `${this.literal(this.atomic, 0)} as const`\n return `${doc}\\nexport const atomic = ${value}`\n }\n\n /**\n * Render an attribute interface from a property map, a field order, and a `required`\n * predicate (true => no `?`). Shared by the read and write attribute interfaces so the\n * tsType/JSDoc logic stays in one place.\n */\n private renderInterface(\n name: string,\n props: Record<string, SchemaOrBool> | undefined,\n fields: readonly string[],\n required: (field: string) => boolean,\n ): string {\n const lines: string[] = []\n for (const field of fields) {\n const schema = props?.[field]\n const tsType = isSchema(schema) ? this.tsType(schema) : 'unknown'\n const doc = isSchema(schema) ? jsDoc(schema.description, ' ') : undefined\n if (doc) {\n lines.push(doc)\n }\n const optional = required(field) ? '' : '?'\n lines.push(` ${objectKey(field)}${optional}: ${tsType}`)\n }\n\n this.emittedInterfaces.add(name)\n if (lines.length === 0) {\n return `export interface ${name} {}`\n }\n return `export interface ${name} {\\n${lines.join('\\n')}\\n}`\n }\n\n /** Map a JSON Schema attribute node to a precise TypeScript type. */\n private tsType(schema: SchemaObject): string {\n // A reference: an enum -> its emitted union alias; an emitted attribute interface ->\n // its interface name (so an action envelope nests precise attribute types); else\n // structural expansion of the referenced component, falling back to unknown. A\n // `expanding` guard breaks any cyclic/self-referential component chain.\n if (typeof schema.$ref === 'string') {\n const target = refName(schema.$ref)\n const resolved = target ? this.schemas[target] : undefined\n if (target && resolved && Array.isArray(resolved.enum)) {\n this.usedEnums.set(target, resolved)\n return target\n }\n if (target && this.emittedInterfaces.has(target)) {\n return target\n }\n if (resolved === undefined || target === undefined || this.expanding.has(target)) {\n return 'unknown'\n }\n this.expanding.add(target)\n const expanded = this.tsType(resolved)\n this.expanding.delete(target)\n return expanded\n }\n\n const types = Array.isArray(schema.type) ? schema.type : schema.type ? [schema.type] : []\n const nullable = types.includes('null')\n const base = this.baseTsType(\n schema,\n types.filter((t) => t !== 'null'),\n )\n return nullable ? `${base} | null` : base\n }\n\n /** The non-nullable TS type for the declared JSON type(s). */\n private baseTsType(schema: SchemaObject, types: readonly string[]): string {\n // An inline enum (string literals without a $ref).\n if (Array.isArray(schema.enum) && schema.enum.length > 0) {\n return schema.enum.map((value) => quote(String(value))).join(' | ')\n }\n if (types.length === 0) {\n return 'unknown'\n }\n const mapped = types.map((t) => this.scalarOrComposite(schema, t))\n // De-dupe while preserving order.\n return [...new Set(mapped)].join(' | ')\n }\n\n private scalarOrComposite(schema: SchemaObject, type: string): string {\n switch (type) {\n case 'string': {\n return 'string'\n }\n case 'number':\n case 'integer': {\n return 'number'\n }\n case 'boolean': {\n return 'boolean'\n }\n case 'object': {\n return this.objectType(schema)\n }\n case 'array': {\n return this.arrayType(schema)\n }\n default: {\n return 'unknown'\n }\n }\n }\n\n /** A nested object type from its `properties` (falls back to an index signature). */\n private objectType(schema: SchemaObject): string {\n const props = schema.properties\n if (props === undefined) {\n return 'Record<string, unknown>'\n }\n const required = new Set(schema.required ?? [])\n const members: string[] = []\n for (const [name, prop] of Object.entries(props)) {\n if (!isSchema(prop)) {\n continue\n }\n const optional = required.has(name) ? '' : '?'\n members.push(`${objectKey(name)}${optional}: ${this.tsType(prop)}`)\n }\n if (members.length === 0) {\n return 'Record<string, unknown>'\n }\n return `{ ${members.join('; ')} }`\n }\n\n private arrayType(schema: SchemaObject): string {\n const items = schema.items\n const element = isSchema(items) ? this.tsType(items) : 'unknown'\n // Wrap unions so `(A | B)[]` reads correctly.\n return /[|&]/.test(element) ? `(${element})[]` : `${element}[]`\n }\n\n /** Union aliases for every enum component an attribute referenced, sorted by name. */\n private enumAliases(): string | undefined {\n if (this.usedEnums.size === 0) {\n return undefined\n }\n // oxlint-disable-next-line no-array-sort -- sorting a freshly-created key array\n const names = [...this.usedEnums.keys()].sort()\n return names\n .map((name) => {\n const schema = this.usedEnums.get(name)!\n const values = schema.enum ?? []\n const union = values.map((value) => quote(String(value))).join(' | ')\n const alias = `export type ${name} = ${union}`\n const doc = jsDoc(this.enumDoc(schema), '')\n return doc ? `${doc}\\n${alias}` : alias\n })\n .join('\\n\\n')\n }\n\n /**\n * Documentation for an enum alias: a per-value list built from `x-enum-descriptions`\n * (the richest hover DX, since a union alias can't carry per-member JSDoc), falling\n * back to the component's own `description`.\n */\n private enumDoc(schema: SchemaObject): string | undefined {\n const values = schema.enum ?? []\n const descriptions = schema['x-enum-descriptions']\n if (Array.isArray(descriptions) && descriptions.length === values.length && values.length > 0) {\n return values\n .map((value, i) => `- \\`${String(value)}\\` — ${String(descriptions[i])}`)\n .join('\\n')\n }\n return schema.description\n }\n\n /**\n * Emit the `Attributes` interface mapping each wire type to its per-type attribute\n * interface. The runtime descriptor only carries coarse format hints; this is how the\n * precise per-type attribute types reach the bound client (passed as the second type\n * argument to the runtime factory).\n */\n private attributesMap(): string {\n const lines = Object.keys(this.descriptor).map(\n (type) => ` ${objectKey(type)}: ${pascalCase(type)}Attributes`,\n )\n return `export interface Attributes {\\n${lines.join('\\n')}\\n}`\n }\n\n /**\n * Emit the `WriteAttributes` interface mapping each writable wire type to its\n * `{ create; update }` attribute pair. A read-only type (no create/update component)\n * contributes no entry, so the bound client only exposes writes where the API allows\n * them. Passed as the third type argument to the runtime factory.\n */\n private writeAttributesMap(): string {\n const lines: string[] = []\n for (const type of Object.keys(this.descriptor)) {\n const base = this.baseByType.get(type)\n const hasCreate = base !== undefined && this.schemas[`${base}CreateAttributes`] !== undefined\n const hasUpdate = base !== undefined && this.schemas[`${base}UpdateAttributes`] !== undefined\n if (!hasCreate && !hasUpdate) {\n continue\n }\n const pascal = pascalCase(type)\n const members: string[] = []\n if (hasCreate) {\n members.push(`create: ${pascal}CreateAttributes`)\n }\n if (hasUpdate) {\n members.push(`update: ${pascal}UpdateAttributes`)\n }\n lines.push(` ${objectKey(type)}: { ${members.join('; ')} }`)\n }\n if (lines.length === 0) {\n return 'export interface WriteAttributes {}'\n }\n return `export interface WriteAttributes {\\n${lines.join('\\n')}\\n}`\n }\n\n /** Emit the descriptor as a literal `as const satisfies ApiDescriptor`. */\n private resourceMap(): string {\n const body = this.literal(this.descriptor as Record<string, unknown>, 0)\n return `export const resourceMap = ${body} as const satisfies ApiDescriptor`\n }\n\n /** Render a JSON-serialisable descriptor value as deterministic TS object-literal source. */\n private literal(value: unknown, depth: number): string {\n const indent = ' '.repeat(depth)\n const inner = ' '.repeat(depth + 1)\n\n if (Array.isArray(value)) {\n if (value.length === 0) {\n return '[]'\n }\n const items = value.map((item) => `${inner}${this.literal(item, depth + 1)}`)\n return `[\\n${items.join(',\\n')}\\n${indent}]`\n }\n\n if (value !== null && typeof value === 'object') {\n const entries = Object.entries(value as Record<string, unknown>)\n if (entries.length === 0) {\n return '{}'\n }\n const lines = entries.map(\n ([key, v]) => `${inner}${objectKey(key)}: ${this.literal(v, depth + 1)}`,\n )\n return `{\\n${lines.join(',\\n')}\\n${indent}}`\n }\n\n return JSON.stringify(value)\n }\n\n private boundFactory(): string {\n return [\n '/**',\n ' * Descriptor-bound client factory; wraps the generic runtime with this API’s `resourceMap`.',\n ' * The server-level `atomic` capability is threaded in by default so `client.atomic` is wired',\n ' * (a caller may still override it via `options.atomic`).',\n ' */',\n 'export const createClient = (options: ClientOptions) =>',\n ' createClientRuntime<typeof resourceMap, Attributes, WriteAttributes, ActionTypes>(',\n ' resourceMap,',\n ' {',\n ' atomic,',\n ' ...options,',\n ' },',\n ' )',\n ].join('\\n')\n }\n}\n\n/**\n * Generate the full source of the client module for a document + its built descriptor.\n * The server-level atomic capability is derived from the document (override via `atomic`).\n */\nexport function emit(\n doc: OpenApiDocument,\n descriptor: ApiDescriptor,\n atomic: AtomicDescriptor | null = buildAtomic(doc),\n): string {\n return new Emitter(doc, descriptor, atomic).emit()\n}\n\n/** Re-export so callers can reference the resource descriptor shape if needed. */\nexport type { ResourceDescriptor }\n","import { hashJson } from './provenance'\nimport type { SchemaBundle } from './reader'\n\n/**\n * Emit the per-type JSON Schema map as a standalone generated artifact:\n *\n * ```ts\n * export const schemas = { <type>: { …json schema… }, … } as const\n * ```\n *\n * The values are the raw, self-contained resource-object JSON Schema documents the bundle\n * serves at `GET /schemas.json` — suitable to hand straight to a validation engine via the\n * opt-in `validate?` seam (ADR 0004). This is a separate file from the client so the main\n * descriptor/client output is unaffected when `--schemas` is absent.\n *\n * The schemas are emitted as JSON (deterministic, key order preserved) so the artifact is\n * stable to diff; `as const` keeps the literal shapes narrow.\n */\nexport function emitSchemas(bundle: SchemaBundle): string {\n return `${[header(bundle), body(bundle)].join('\\n\\n')}\\n`\n}\n\nfunction header(bundle: SchemaBundle): string {\n return [\n '/**',\n ' * AUTO-GENERATED by @haddowg/json-api-codegen — do not edit by hand.',\n ' * Per-type JSON Schemas for the opt-in validation seam; regenerate from the source bundle.',\n ' *',\n ` * Schema hash: ${hashJson(bundle)}`,\n ' */',\n ].join('\\n')\n}\n\nfunction body(bundle: SchemaBundle): string {\n // `JSON.stringify` with two-space indent gives deterministic, diff-friendly output while\n // preserving the bundle's key order. The raw schema objects are valid TS object literals.\n const json = JSON.stringify(bundle, null, 2)\n return `export const schemas = ${json} as const`\n}\n","import { readFile } from 'node:fs/promises'\nimport { parse as parseYaml } from 'yaml'\nimport type { OpenApiDocument } from './openapi'\nimport type { SchemaObject } from './openapi'\n\n/** A self-contained JSON Schema document, keyed by JSON:API type, as served at `GET /schemas.json`. */\nexport type SchemaBundle = Record<string, SchemaObject>\n\n/** True when the input looks like an http(s) URL rather than a local path. */\nfunction isHttpUrl(input: string): boolean {\n return /^https?:\\/\\//i.test(input)\n}\n\n/** Decide YAML vs JSON by extension first, then by a cheap content sniff. */\nfunction looksLikeYaml(source: string, text: string): boolean {\n if (/\\.ya?ml$/i.test(source)) {\n return true\n }\n if (/\\.json$/i.test(source)) {\n return false\n }\n // No decisive extension: JSON documents start with `{`/`[` once trimmed.\n return !/^\\s*[{[]/.test(text)\n}\n\nfunction parse<T>(source: string, text: string, label: string): T {\n const doc = looksLikeYaml(source, text) ? parseYaml(text) : JSON.parse(text)\n if (doc === null || typeof doc !== 'object') {\n throw new Error(`${label} at ${source} did not parse to an object`)\n }\n return doc as T\n}\n\n/**\n * Fetch (URL) or read (file) `input`, then parse it as JSON or YAML (decided by extension,\n * falling back to a content sniff). Shared by the OpenAPI and JSON Schema readers.\n */\nasync function readSource<T>(input: string, label: string): Promise<T> {\n if (isHttpUrl(input)) {\n const res = await fetch(input)\n if (!res.ok) {\n throw new Error(`Failed to fetch ${label} from ${input}: ${res.status}`)\n }\n return parse<T>(input, await res.text(), label)\n }\n\n return parse<T>(input, await readFile(input, 'utf8'), label)\n}\n\n/**\n * Read an OpenAPI document from an http(s) URL or a local file path. Supports both JSON\n * and YAML (decided by extension, falling back to a content sniff).\n */\nexport async function readDocument(input: string): Promise<OpenApiDocument> {\n return readSource<OpenApiDocument>(input, 'OpenAPI document')\n}\n\n/**\n * Read the bundle's JSON Schema bundle (`GET /schemas.json`) from an http(s) URL or a\n * local file path — a map keyed by JSON:API type, each value a self-contained JSON Schema\n * 2020-12 resource-object document. Supports both JSON and YAML, like {@link readDocument}.\n */\nexport async function readSchemas(input: string): Promise<SchemaBundle> {\n return readSource<SchemaBundle>(input, 'JSON Schema bundle')\n}\n","/**\n * @haddowg/json-api-codegen — reads the bundle's OpenAPI 3.1 document (from a URL or\n * a local file) and emits the runtime descriptor + derived types + a bound\n * `createClient` (ADR 0001). Optionally reads the bundle's JSON Schemas to wire the\n * opt-in validation seam.\n *\n * The spec is fully self-describing for our needs (see CONTEXT.md): type identity is\n * `properties.type.const`; relationships, cardinality and related types come from the\n * relationship components' `data`; allowed `?include` paths are a bounded, pre-expanded\n * enum per endpoint; the create client-id policy is encoded in the create request\n * schema (`id: false` / required / optional).\n */\n\nimport { mkdir, readFile, writeFile } from 'node:fs/promises'\nimport { dirname } from 'node:path'\nimport { buildDescriptor } from './build-descriptor'\nimport { detectVerbCollisions, emit } from './emit'\nimport { emitSchemas } from './emit-schemas'\nimport { readDocument, readSchemas } from './reader'\n\nexport { buildAtomic, buildDescriptor, DescriptorBuilder } from './build-descriptor'\nexport { detectVerbCollisions, emit, Emitter } from './emit'\nexport type { VerbCollision } from './emit'\nexport { emitSchemas } from './emit-schemas'\nexport type * from './openapi'\nexport { deriveProvenance, hashJson, provenanceLines } from './provenance'\nexport type { Provenance } from './provenance'\nexport { readDocument, readSchemas } from './reader'\nexport type { SchemaBundle } from './reader'\n\nexport interface CodegenConfig {\n /** OpenAPI document source: an http(s) URL or a local file path. */\n input: string\n /** Output file (or directory) for the generated client. */\n output: string\n /** Server name to target (the spec is per-server). Defaults to the default server. */\n server?: string\n /** JSON Schema source for the validation seam (URL or path). Off when omitted. */\n schemas?: string\n /**\n * Drift-check mode: regenerate in-memory and compare against the committed `output`\n * (and its schema artifact when `schemas` is set) instead of writing. Nothing is\n * written; {@link check} reports whether the committed artifacts are up to date.\n */\n check?: boolean\n}\n\n/** One artifact's drift status: the file it stands for, and whether it is up to date. */\nexport interface ArtifactDrift {\n /** The committed artifact path (the client output, or its schema sibling). */\n path: string\n /** True when the committed file matches the freshly generated content. */\n upToDate: boolean\n}\n\n/** The outcome of a {@link check} run: `ok` iff every checked artifact is up to date. */\nexport interface CheckResult {\n ok: boolean\n artifacts: ArtifactDrift[]\n}\n\n/**\n * The schema-artifact path beside a client output path: `client.gen.ts` -> `client.schemas.gen.ts`\n * (any `.gen.ts`/`.ts` suffix is preserved; a suffix-less path just gains `.schemas`).\n */\nexport function schemasOutputPath(output: string): string {\n if (output.endsWith('.gen.ts')) {\n return `${output.slice(0, -'.gen.ts'.length)}.schemas.gen.ts`\n }\n if (output.endsWith('.ts')) {\n return `${output.slice(0, -'.ts'.length)}.schemas.ts`\n }\n return `${output}.schemas`\n}\n\n/** One rendered artifact: its target path and the freshly generated content. */\ninterface RenderedArtifact {\n path: string\n content: string\n}\n\n/**\n * Read the source spec(s), build the descriptor and render every generated artifact in\n * memory (the client source first, then the schema artifact when `config.schemas` is set)\n * — the shared core of {@link generate} (which writes them) and {@link check} (which\n * compares them). Verb-collision warnings are emitted here so both paths surface them.\n */\nasync function render(config: CodegenConfig): Promise<RenderedArtifact[]> {\n const doc = await readDocument(config.input)\n const descriptor = buildDescriptor(doc)\n\n for (const { type, relation } of detectVerbCollisions(descriptor)) {\n console.warn(\n `[json-api-codegen] \"${type}\" has a relation named \"${relation}\" which collides with a ` +\n 'reserved verb on the resource handle; it will be reachable via .rel(\"' +\n `${relation}\") in the fluent client.`,\n )\n }\n\n const artifacts: RenderedArtifact[] = [{ path: config.output, content: emit(doc, descriptor) }]\n\n if (config.schemas !== undefined) {\n const bundle = await readSchemas(config.schemas)\n artifacts.push({ path: schemasOutputPath(config.output), content: emitSchemas(bundle) })\n }\n\n return artifacts\n}\n\n/**\n * Read the OpenAPI document, build the runtime descriptor, emit the generated client\n * module and write it to `config.output` (creating parent directories as needed).\n *\n * When `config.schemas` is set, also read the bundle's JSON Schema bundle and write a\n * separate per-type schema artifact (`<output>.schemas.gen.ts`) beside the client, wiring\n * the opt-in validation seam (ADR 0004). The main client output is unchanged either way.\n *\n * `config.server` is metadata-only for now: the served document is already per-server,\n * so the caller selects the server by pointing `input` at the right document.\n *\n * Returns the generated client source. When `config.check` is set nothing is written;\n * call {@link check} instead for the drift-gate result.\n */\nexport async function generate(config: CodegenConfig): Promise<string> {\n const artifacts = await render(config)\n await mkdir(dirname(config.output), { recursive: true })\n for (const { path, content } of artifacts) {\n await writeFile(path, content, 'utf8')\n }\n // The first artifact is always the client source.\n return artifacts[0]!.content\n}\n\n/**\n * Drift gate: regenerate every artifact in memory and compare it byte-for-byte against the\n * committed file on disk, WITHOUT writing anything. A missing committed file counts as drift\n * (not up to date). Returns per-artifact status plus an aggregate `ok` (true iff all match) —\n * the CI drift check reads `ok` and exits non-zero when it is false.\n */\nexport async function check(config: CodegenConfig): Promise<CheckResult> {\n const artifacts = await render(config)\n const results: ArtifactDrift[] = []\n for (const { path, content } of artifacts) {\n let committed: string | undefined\n try {\n committed = await readFile(path, 'utf8')\n } catch {\n committed = undefined\n }\n results.push({ path, upToDate: committed === content })\n }\n return { ok: results.every((r) => r.upToDate), artifacts: results }\n}\n"],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,57 @@
1
+ {
2
+ "name": "@haddowg/json-api-codegen",
3
+ "version": "1.0.0",
4
+ "description": "CLI that reads the json-api-symfony OpenAPI spec (+ JSON Schemas) and emits a typed client descriptor.",
5
+ "license": "MIT",
6
+ "author": "Gregory Haddow (https://github.com/haddowg)",
7
+ "homepage": "https://haddowg.github.io/json-api-ts/",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/haddowg/json-api-ts.git",
11
+ "directory": "packages/codegen"
12
+ },
13
+ "bugs": "https://github.com/haddowg/json-api-ts/issues",
14
+ "keywords": [
15
+ "json-api",
16
+ "jsonapi",
17
+ "typescript",
18
+ "openapi",
19
+ "codegen",
20
+ "code-generation",
21
+ "cli",
22
+ "api"
23
+ ],
24
+ "type": "module",
25
+ "bin": {
26
+ "json-api-codegen": "./dist/cli.mjs",
27
+ "japi": "./dist/cli.mjs"
28
+ },
29
+ "exports": {
30
+ ".": {
31
+ "import": {
32
+ "types": "./dist/index.d.mts",
33
+ "default": "./dist/index.mjs"
34
+ }
35
+ }
36
+ },
37
+ "types": "./dist/index.d.mts",
38
+ "files": [
39
+ "dist"
40
+ ],
41
+ "engines": {
42
+ "node": ">=20"
43
+ },
44
+ "publishConfig": {
45
+ "access": "public",
46
+ "provenance": true
47
+ },
48
+ "dependencies": {
49
+ "yaml": "^2.7.0",
50
+ "@haddowg/json-api-client": "^1.0.0"
51
+ },
52
+ "scripts": {
53
+ "build": "tsdown",
54
+ "typecheck": "tsc --noEmit -p tsconfig.typecheck.json",
55
+ "lint:publish": "publint --strict && attw --pack . --profile esm-only"
56
+ }
57
+ }