diff --git a/package.json b/package.json index d8349ce4a..31e5247eb 100644 --- a/package.json +++ b/package.json @@ -68,6 +68,7 @@ "@types/node": "22.7.4", "@types/swagger2openapi": "7.0.4", "axios": "1.7.7", + "openapi-types": "12.1.3", "tsup": "8.3.0", "vitest": "2.1.2" }, diff --git a/src/code-gen-process.ts b/src/code-gen-process.ts index a61f0e528..8f22e9fa6 100644 --- a/src/code-gen-process.ts +++ b/src/code-gen-process.ts @@ -162,7 +162,7 @@ export class CodeGenProcess { fileName: this.config.fileName, translateToJavaScript: this.config.toJS, customTranslator: this.config.customTranslator - ? new this.config.customTranslator(this) + ? new this.config.customTranslator() : null, utils: this.getRenderTemplateData().utils, }; diff --git a/src/commands/generate-templates/index.ts b/src/commands/generate-templates/index.ts index 28cd3f33f..119c551bb 100644 --- a/src/commands/generate-templates/index.ts +++ b/src/commands/generate-templates/index.ts @@ -1,8 +1,7 @@ -#!/usr/bin/env node - +import type { GenerateTemplatesParams } from "../../../types/index.js"; import { TemplatesGenProcess } from "./templates-gen-process.js"; -export async function generateTemplates(config) { +export async function generateTemplates(config: GenerateTemplatesParams) { const codeGenProcess = new TemplatesGenProcess(config); return await codeGenProcess.start(); } diff --git a/src/commands/generate-templates/templates-gen-process.ts b/src/commands/generate-templates/templates-gen-process.ts index 988732260..0bf654898 100644 --- a/src/commands/generate-templates/templates-gen-process.ts +++ b/src/commands/generate-templates/templates-gen-process.ts @@ -1,7 +1,10 @@ import path from "node:path"; import url from "node:url"; import { consola } from "consola"; -import type { GenerateTemplatesOutput } from "../../../types/index.js"; +import type { + GenerateTemplatesOutput, + GenerateTemplatesParams, +} from "../../../types/index.js"; import { FileSystem } from "../../util/file-system.js"; import { TemplatesGenConfig } from "./configuration.js"; @@ -22,7 +25,7 @@ export class TemplatesGenProcess { importTemplatePrefixes = ["@base", "@modular", "@default"]; - constructor(config) { + constructor(config: GenerateTemplatesParams) { this.config = new TemplatesGenConfig(config); this.fileSystem = new FileSystem(); } diff --git a/src/component-type-name-resolver.ts b/src/component-type-name-resolver.ts index 1ced36a9b..0c1f4da5c 100644 --- a/src/component-type-name-resolver.ts +++ b/src/component-type-name-resolver.ts @@ -6,7 +6,7 @@ import { getRandomInt } from "./util/random.js"; export class ComponentTypeNameResolver extends NameResolver { counter = 1; fallbackNameCounter = 1; - countersByVariant = new Map(); + countersByVariant = new Map(); constructor(config: CodeGenConfig, reservedNames: string[]) { super(config, reservedNames, (variants) => { @@ -15,7 +15,8 @@ export class ComponentTypeNameResolver extends NameResolver { if (!this.countersByVariant.has(randomVariant)) { this.countersByVariant.set(randomVariant, 0); } - const variantCounter = this.countersByVariant.get(randomVariant) + 1; + const variantCounter = + (this.countersByVariant.get(randomVariant) as number) + 1; this.countersByVariant.set(randomVariant, variantCounter); const dirtyResolvedName = `${randomVariant}${variantCounter}`; consola.debug( diff --git a/src/configuration.ts b/src/configuration.ts index 10631b6dd..e76ad495d 100644 --- a/src/configuration.ts +++ b/src/configuration.ts @@ -1,5 +1,6 @@ import * as cosmiconfig from "cosmiconfig"; import lodash from "lodash"; +import type { OpenAPI } from "openapi-types"; import * as typescript from "typescript"; import type { ExtractingOptions, @@ -9,6 +10,7 @@ import { ComponentTypeNameResolver } from "./component-type-name-resolver.js"; import * as CONSTANTS from "./constants.js"; import type { MonoSchemaParser } from "./schema-parser/mono-schema-parser.js"; import type { SchemaParser } from "./schema-parser/schema-parser.js"; +import type { Translator } from "./translators/translator.js"; import { objectAssign } from "./util/object-assign.js"; const TsKeyword = { @@ -162,7 +164,7 @@ export class CodeGenConfig { output = ""; url = ""; cleanOutput = false; - spec = null; + spec: OpenAPI.Document | null = null; fileName = "Api.ts"; authorizationToken: string | undefined; requestOptions = null; @@ -215,7 +217,7 @@ export class CodeGenConfig { emitDecoratorMetadata: true, skipLibCheck: true, }; - customTranslator; + customTranslator?: new () => Translator; Ts = { Keyword: structuredClone(TsKeyword), @@ -334,10 +336,10 @@ export class CodeGenConfig { primitiveTypes: Record< string, | string - | ((schema: any, parser: SchemaParser) => string) + | ((schema: OpenAPI.Document, parser: SchemaParser) => string) | ({ $default: string } & Record< string, - string | ((schema: any, parser: SchemaParser) => string) + string | ((schema: OpenAPI.Document, parser: SchemaParser) => string) >) > = { integer: () => this.Ts.Keyword.Number, @@ -419,11 +421,7 @@ export class CodeGenConfig { this.Ts.Keyword.Boolean, ]; this.jsEmptyTypes = [this.Ts.Keyword.Null, this.Ts.Keyword.Undefined]; - this.componentTypeNameResolver = new ComponentTypeNameResolver( - this, - null, - [], - ); + this.componentTypeNameResolver = new ComponentTypeNameResolver(this, []); } update = (update: Partial) => { diff --git a/src/schema-walker.ts b/src/schema-walker.ts index ee9740e7f..9c8248415 100644 --- a/src/schema-walker.ts +++ b/src/schema-walker.ts @@ -1,4 +1,5 @@ import lodash from "lodash"; +import type { OpenAPI } from "openapi-types"; import type { CodeGenConfig } from "./configuration.js"; import type { SwaggerSchemaResolver } from "./swagger-schema-resolver.js"; @@ -7,8 +8,8 @@ import type { SwaggerSchemaResolver } from "./swagger-schema-resolver.js"; export class SchemaWalker { config: CodeGenConfig; swaggerSchemaResolver: SwaggerSchemaResolver; - schemas = new Map>(); - caches = new Map>(); + schemas = new Map(); + caches = new Map(); constructor( config: CodeGenConfig, @@ -18,7 +19,7 @@ export class SchemaWalker { this.swaggerSchemaResolver = swaggerSchemaResolver; } - addSchema = (name: string, schema: Record) => { + addSchema = (name: string, schema: OpenAPI.Document) => { this.schemas.set(name, structuredClone(schema)); }; diff --git a/src/swagger-schema-resolver.ts b/src/swagger-schema-resolver.ts index 16e3526da..02ebd43c3 100644 --- a/src/swagger-schema-resolver.ts +++ b/src/swagger-schema-resolver.ts @@ -1,6 +1,7 @@ import { consola } from "consola"; import * as yaml from "js-yaml"; import lodash from "lodash"; +import type { OpenAPI, OpenAPIV2 } from "openapi-types"; import * as swagger2openapi from "swagger2openapi"; import type { CodeGenConfig } from "./configuration.js"; import type { FileSystem } from "./util/file-system.js"; @@ -20,7 +21,7 @@ export class SwaggerSchemaResolver { async create() { const { spec, patch, input, url, authorizationToken } = this.config; - if (this.config.spec) { + if (spec) { return await this.convertSwaggerObject(spec, { patch }); } @@ -35,11 +36,11 @@ export class SwaggerSchemaResolver { } convertSwaggerObject( - swaggerSchema: Record, + swaggerSchema: OpenAPI.Document, converterOptions: { patch?: boolean }, ): Promise<{ - usageSchema: Record; - originalSchema: Record; + usageSchema: OpenAPI.Document; + originalSchema: OpenAPI.Document; }> { return new Promise((resolve) => { const result = structuredClone(swaggerSchema); @@ -51,11 +52,11 @@ export class SwaggerSchemaResolver { result.info, ); - if (!result.openapi) { + if (!Object.hasOwn(result, "openapi")) { result.paths = lodash.merge({}, result.paths); swagger2openapi.convertObj( - result, + result as OpenAPIV2.Document, { ...converterOptions, warnOnly: true, @@ -95,7 +96,7 @@ export class SwaggerSchemaResolver { async fetchSwaggerSchemaFile( pathToSwagger: string, urlToSwagger: string, - authToken: string, + authToken?: string, ) { if (this.fileSystem.pathIsExist(pathToSwagger)) { return this.getSwaggerSchemaByPath(pathToSwagger); @@ -103,7 +104,7 @@ export class SwaggerSchemaResolver { consola.info(`try to get swagger by URL "${urlToSwagger}"`); return await this.request.download({ url: urlToSwagger, - authToken, + authToken: authToken, }); } diff --git a/src/templates-worker.ts b/src/templates-worker.ts index a547201da..98888ccdd 100644 --- a/src/templates-worker.ts +++ b/src/templates-worker.ts @@ -171,16 +171,18 @@ export class TemplatesWorker { .keys(this.config.templatePaths) .find((key) => path_.startsWith(`@${key}`)); - const rawPath = path.resolve( - path_.replace( - `@${foundTemplatePathKey}`, - this.config.templatePaths[foundTemplatePathKey], - ), - ); - const fixedPath = this.findTemplateWithExt(rawPath); + if (foundTemplatePathKey) { + const rawPath = path.resolve( + path_.replace( + `@${foundTemplatePathKey}`, + lodash.get(this.config.templatePaths, foundTemplatePathKey), + ), + ); + const fixedPath = this.findTemplateWithExt(rawPath); - if (fixedPath) { - return this.fileSystem.getFileContent(fixedPath); + if (fixedPath) { + return this.fileSystem.getFileContent(fixedPath); + } } const customPath = diff --git a/src/type-name-formatter.ts b/src/type-name-formatter.ts index 8704c2dad..11297e933 100644 --- a/src/type-name-formatter.ts +++ b/src/type-name-formatter.ts @@ -60,27 +60,28 @@ export class TypeNameFormatter { name: string, options: { type?: FormattingSchemaType }, ): string => { - const { type } = options || {}; - if (!this.isValidName(name)) { if (!/^[a-zA-Z_$]/g.test(name)) { const fixPrefix = - type === "enum-key" + options.type === "enum-key" ? this.config.fixInvalidEnumKeyPrefix : this.config.fixInvalidTypeNamePrefix; - name = `${fixPrefix} ${name}`; + return `${fixPrefix} ${name}`; } // specific replaces for TSOA 3.x - if (name.includes(".")) - name = name + if (name.includes(".")) { + return name .replace(/Exclude_keyof[A-Za-z]+/g, () => "ExcludeKeys") .replace(/%22~AND~%22/g, "And") .replace(/%22~OR~%22/g, "Or") .replace(/(\.?%22)|\./g, "_") .replace(/__+$/, ""); + } - if (name.includes("-")) name = lodash.startCase(name).replace(/ /g, ""); + if (name.includes("-")) { + return lodash.startCase(name).replace(/ /g, ""); + } } return name; diff --git a/types/index.ts b/types/index.ts index c36f5e3ea..97204ed89 100644 --- a/types/index.ts +++ b/types/index.ts @@ -1,4 +1,6 @@ +import type { ComponentTypeNameResolver } from "../src/component-type-name-resolver.js"; import type { MonoSchemaParser } from "../src/schema-parser/mono-schema-parser.js"; +import type { Translator } from "../src/translators/translator.js"; type HttpClientType = "axios" | "fetch"; @@ -209,7 +211,7 @@ interface GenerateApiParamsBase { * } * ``` */ - customTranslator?: new () => typeof import("../src/translators/translator.js").Translator; + customTranslator?: new () => Translator; /** fallback name for enum key resolver */ enumKeyResolverName?: string; /** fallback name for type name resolver */ @@ -655,14 +657,11 @@ export interface GenerateApiConfiguration { enumKeyResolverName: string; typeNameResolverName: string; specificArgNameResolverName: string; - /** do not use constructor args, it can break functionality of this property, just send class reference */ - customTranslator?: new ( - ...args: never[] - ) => typeof import("../src/translators/translator.js").Translator; + customTranslator?: new () => Translator; internalTemplateOptions: { addUtilRequiredKeysType: boolean; }; - componentTypeNameResolver: typeof import("../src/component-type-name-resolver.js").ComponentTypeNameResolver; + componentTypeNameResolver: ComponentTypeNameResolver; fileNames: { dataContracts: string; routeTypes: string; diff --git a/yarn.lock b/yarn.lock index 9a4933db6..308a9c160 100644 --- a/yarn.lock +++ b/yarn.lock @@ -2234,7 +2234,7 @@ __metadata: languageName: node linkType: hard -"openapi-types@npm:^12.1.0": +"openapi-types@npm:12.1.3, openapi-types@npm:^12.1.0": version: 12.1.3 resolution: "openapi-types@npm:12.1.3" checksum: 10c0/4ad4eb91ea834c237edfa6ab31394e87e00c888fc2918009763389c00d02342345195d6f302d61c3fd807f17723cd48df29b47b538b68375b3827b3758cd520f @@ -2802,6 +2802,7 @@ __metadata: js-yaml: "npm:^4.1.0" lodash: "npm:^4.17.21" nanoid: "npm:^3.3.7" + openapi-types: "npm:12.1.3" prettier: "npm:~3.3.3" swagger-schema-official: "npm:2.0.0-bab6bed" swagger2openapi: "npm:^7.0.8"