diff --git a/src/generate-api-types.test.ts b/src/generate-api-types.test.ts index 587c5a9..f779fdc 100644 --- a/src/generate-api-types.test.ts +++ b/src/generate-api-types.test.ts @@ -119,6 +119,112 @@ export const Schema: OneSchema = { }, }, }; +`, + }, + { + input: { + spec: { + Resources: { + Fruit: { + type: 'object', + additionalProperties: false, + required: ['name', 'price'], + properties: { + name: { type: 'string' }, + price: { type: 'number' }, + }, + }, + // This resource is not referenced by any endpoint, but should be + // included in the generated types. + Pet: { + type: 'object', + // type-level comments should be preserved. + description: 'A pet from the animal kingdom.', + additionalProperties: false, + required: ['name', 'age', 'species'], + properties: { + name: { + type: 'string', + // field-level comments should be preserved. + description: 'The name of the pet as given by the owner.', + }, + age: { type: 'number' }, + species: { type: 'string' }, + }, + }, + }, + Endpoints: { + 'GET /fruits': { + Name: 'getPosts', + Request: {}, + Response: { + type: 'array', + items: { + $ref: '#/definitions/Fruit', + }, + }, + }, + }, + }, + }, + expected: `/* eslint-disable */ +import type { OneSchema } from "@lifeomic/one-schema"; + +export type Endpoints = { + "GET /fruits": { + Request: unknown; + PathParams: {}; + Response: Fruit[]; + }; +}; + +export type Fruit = { + name: string; + price: number; +}; +/** + * A pet from the animal kingdom. + */ +export type Pet = { + /** + * The name of the pet as given by the owner. + */ + name: string; + age: number; + species: string; +}; + +export const Schema: OneSchema = { + Resources: { + Fruit: { + type: "object", + additionalProperties: false, + required: ["name", "price"], + properties: { name: { type: "string" }, price: { type: "number" } }, + }, + Pet: { + type: "object", + description: "A pet from the animal kingdom.", + additionalProperties: false, + required: ["name", "age", "species"], + properties: { + name: { + type: "string", + description: "The name of the pet as given by the owner.", + }, + age: { type: "number" }, + species: { type: "string" }, + }, + }, + }, + Endpoints: { + "GET /fruits": { + Name: "getPosts", + Request: {}, + Response: { type: "array", items: { $ref: "#/definitions/Fruit" } }, + }, + }, +}; `, }, ]; diff --git a/src/generate-endpoints.ts b/src/generate-endpoints.ts index 0e313a4..958a31b 100644 --- a/src/generate-endpoints.ts +++ b/src/generate-endpoints.ts @@ -57,6 +57,7 @@ export const generateEndpointTypes = async ({ await compile(deepCopy(masterSchema), '', { format: false, bannerComment: '', + unreachableDefinitions: true, }) ) /** @@ -73,5 +74,25 @@ export const generateEndpointTypes = async ({ const name = matched.split(' ')[2]; return `export type ${name} = {`; }) + /** + * When the json-schema-to-typescript `unreachableDefinitions` setting is `true`, it outputs + * some ugly comments on the generated types, so we remove them. + * + * Relevant GitHub issue in json-schema-to-typescript: + * https://github.com/bcherny/json-schema-to-typescript/issues/428 + */ + .replace( + /^\s*\/\*\*\s+\* This interface was referenced by `.*`'s JSON-Schema\s+\* via the `definition` ".*"\.\s+\*\//gm, + '', + ) + /** + * Same as above ^^^ but handling the case where the ugly comment is appended to an already + * existing comment. We keep the original comment but remove json-schema-to-typescript's ugly + * addition. + */ + .replace( + /\n\s*\*\s+\* This interface was referenced by `.*`'s JSON-Schema\s+\* via the `definition` ".*"\./gm, + '', + ) ); };