diff --git a/.changeset/dull-monkeys-help.md b/.changeset/dull-monkeys-help.md new file mode 100644 index 000000000..aa6f965bd --- /dev/null +++ b/.changeset/dull-monkeys-help.md @@ -0,0 +1,5 @@ +--- +"swagger-typescript-api": patch +--- + +added support x-propertyNames, propertyNames for object types diff --git a/src/schema-parser/base-schema-parsers/object.ts b/src/schema-parser/base-schema-parsers/object.ts index cad7346a3..6731c1e4f 100644 --- a/src/schema-parser/base-schema-parsers/object.ts +++ b/src/schema-parser/base-schema-parsers/object.ts @@ -82,12 +82,27 @@ export class ObjectSchemaParser extends MonoSchemaParser { }); if (additionalProperties) { + const propertyNamesSchema = + this.schemaUtils.getSchemaPropertyNamesSchema(schema); + let interfaceKeysContent: any; + + if (propertyNamesSchema) { + interfaceKeysContent = this.schemaParserFabric + .createSchemaParser({ + schema: propertyNamesSchema, + schemaPath: this.schemaPath, + }) + .getInlineParseContent(); + } else { + interfaceKeysContent = this.config.Ts.Keyword.String; + } + propertiesContent.push({ $$raw: { additionalProperties }, description: "", isRequired: false, field: this.config.Ts.InterfaceDynamicField( - this.config.Ts.Keyword.String, + interfaceKeysContent, this.config.Ts.Keyword.Any, ), }); diff --git a/src/schema-parser/base-schema-parsers/primitive.ts b/src/schema-parser/base-schema-parsers/primitive.ts index 4ed2c0e0a..417350e6e 100644 --- a/src/schema-parser/base-schema-parsers/primitive.ts +++ b/src/schema-parser/base-schema-parsers/primitive.ts @@ -8,18 +8,38 @@ export class PrimitiveSchemaParser extends MonoSchemaParser { this.schema || {}; if (type === this.config.Ts.Keyword.Object && additionalProperties) { - const fieldType = - typeof additionalProperties === "object" - ? this.schemaParserFabric - .createSchemaParser({ - schema: additionalProperties, - schemaPath: this.schemaPath, - }) - .getInlineParseContent() - : this.config.Ts.Keyword.Any; + const propertyNamesSchema = this.schemaUtils.getSchemaPropertyNamesSchema( + this.schema, + ); + + let recordKeysContent: any; + let recordValuesContent: any; + + if (propertyNamesSchema) { + recordKeysContent = this.schemaParserFabric + .createSchemaParser({ + schema: propertyNamesSchema, + schemaPath: this.schemaPath, + }) + .getInlineParseContent(); + } else { + recordKeysContent = this.config.Ts.Keyword.String; + } + + if (typeof additionalProperties === "object") { + recordValuesContent = this.schemaParserFabric + .createSchemaParser({ + schema: additionalProperties, + schemaPath: this.schemaPath, + }) + .getInlineParseContent(); + } else { + recordValuesContent = this.config.Ts.Keyword.Any; + } + contentType = this.config.Ts.RecordType( - this.config.Ts.Keyword.String, - fieldType, + recordKeysContent, + recordValuesContent, ); } diff --git a/src/schema-parser/schema-utils.ts b/src/schema-parser/schema-utils.ts index b731c8bb9..6663a0495 100644 --- a/src/schema-parser/schema-utils.ts +++ b/src/schema-parser/schema-utils.ts @@ -53,6 +53,11 @@ export class SchemaUtils { ); }; + getSchemaPropertyNamesSchema = (schema) => { + if (!schema) return null; + return schema.propertyNames || schema["x-propertyNames"] || null; + }; + getSchemaRefType = (schema) => { if (!this.isRefSchema(schema)) return null; return this.schemaComponentsMap.get(schema.$ref); diff --git a/tests/spec/propertyNames/__snapshots__/basic.test.ts.snap b/tests/spec/propertyNames/__snapshots__/basic.test.ts.snap new file mode 100644 index 000000000..d4b0c7c85 --- /dev/null +++ b/tests/spec/propertyNames/__snapshots__/basic.test.ts.snap @@ -0,0 +1,48 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`basic > propertyNames 1`] = ` +"/* eslint-disable */ +/* tslint:disable */ +// @ts-nocheck +/* + * --------------------------------------------------------------- + * ## THIS FILE WAS GENERATED VIA SWAGGER-TYPESCRIPT-API ## + * ## ## + * ## AUTHOR: acacode ## + * ## SOURCE: https://github.com/acacode/swagger-typescript-api ## + * --------------------------------------------------------------- + */ + +export enum KekEnum { + /** Creating */ + Creating = "creating", + /** created */ + Created = "created", + /** Starting */ + Starting = "starting", + /** Kkeke */ + Started = "started", + /** dsafads */ + Restarting = "restarting", + /** dasfds */ + Stopping = "stopping", + /** dadd */ + Stopped = "stopped", + /** xzxzxz */ + Deploy = "deploy", + /** axzxe */ + WaitDependency = "wait_dependency", + Updating = "updating", +} + +export type FooBarBazRoot = Record; + +export type FooBarBazNoAdditionalProperties = object; + +export type FooBarBazNoAdditionalPropertiesPrimitive = object; + +export interface FooBarBazNested { + dataCount?: Record; +} +" +`; diff --git a/tests/spec/propertyNames/basic.test.ts b/tests/spec/propertyNames/basic.test.ts new file mode 100644 index 000000000..8936041af --- /dev/null +++ b/tests/spec/propertyNames/basic.test.ts @@ -0,0 +1,36 @@ +import * as fs from "node:fs/promises"; +import * as os from "node:os"; +import * as path from "node:path"; + +import { afterAll, beforeAll, describe, expect, test } from "vitest"; + +import { generateApi } from "../../../src/index.js"; + +describe("basic", async () => { + let tmpdir = ""; + + beforeAll(async () => { + tmpdir = await fs.mkdtemp(path.join(os.tmpdir(), "swagger-typescript-api")); + }); + + afterAll(async () => { + await fs.rm(tmpdir, { recursive: true }); + }); + + test("propertyNames", async () => { + await generateApi({ + fileName: "schema", + input: path.resolve(import.meta.dirname, "schema.yml"), + output: tmpdir, + silent: true, + generateClient: false, + generateRouteTypes: true, + }); + + const content = await fs.readFile(path.join(tmpdir, "schema.ts"), { + encoding: "utf8", + }); + + expect(content).toMatchSnapshot(); + }); +}); diff --git a/tests/spec/propertyNames/schema.yml b/tests/spec/propertyNames/schema.yml new file mode 100644 index 000000000..cceb908fe --- /dev/null +++ b/tests/spec/propertyNames/schema.yml @@ -0,0 +1,55 @@ +openapi: 3.0.3 +info: + title: teesttt + version: 0.0.0 +security: + - registryCookieAuth: [] + - cookieAuth: [ ] +components: + schemas: + FooBarBazRoot: + type: object + propertyNames: + $ref: '#/components/schemas/KekEnum' + additionalProperties: + type: number + FooBarBazNoAdditionalProperties: + type: object + propertyNames: + $ref: '#/components/schemas/KekEnum' + FooBarBazNoAdditionalPropertiesPrimitive: + type: object + propertyNames: + type: number + FooBarBazNested: + type: object + properties: + dataCount: + type: object + propertyNames: + $ref: '#/components/schemas/KekEnum' + additionalProperties: + type: number + KekEnum: + type: string + enum: + - creating + - created + - starting + - started + - restarting + - stopping + - stopped + - deploy + - wait_dependency + - updating + x-enum-descriptions: + - Creating + - created + - Starting + - Kkeke + - dsafads + - dasfds + - dadd + - xzxzxz + - axzxe