UNPKG

@kubb/plugin-oas

Version:

OpenAPI Specification (OAS) plugin for Kubb, providing core functionality for parsing and processing OpenAPI/Swagger schemas for code generation.

268 lines (267 loc) 9.72 kB
import "./chunk--u3MIqq1.js"; import { n as getBanner, r as camelCase, t as getFooter } from "./getFooter-Pw3tLCiV.js"; import { n as withRequiredRequestBodySchema, r as SchemaGenerator, s as getSchemaFactory, t as isRequestBodyRequired } from "./requestBody-pRavthCw.js"; import { n as schemaKeywords } from "./SchemaMapper-CqMkO2T1.js"; import { isOptional } from "@kubb/oas"; //#region ../../internals/utils/src/reserved.ts /** * Returns `true` when `name` is a syntactically valid JavaScript variable name. */ function isValidVarName(name) { try { new Function(`var ${name}`); } catch { return false; } return true; } //#endregion //#region ../../internals/utils/src/urlPath.ts /** * Parses and transforms an OpenAPI/Swagger path string into various URL formats. * * @example * const p = new URLPath('/pet/{petId}') * p.URL // '/pet/:petId' * p.template // '`/pet/${petId}`' */ var URLPath = class { /** The raw OpenAPI/Swagger path string, e.g. `/pet/{petId}`. */ path; #options; constructor(path, options = {}) { this.path = path; this.#options = options; } /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */ get URL() { return this.toURLPath(); } /** Returns `true` when `path` is a fully-qualified URL (e.g. starts with `https://`). */ get isURL() { try { return !!new URL(this.path).href; } catch { return false; } } /** * Converts the OpenAPI path to a TypeScript template literal string. * * @example * new URLPath('/pet/{petId}').template // '`/pet/${petId}`' * new URLPath('/account/monetary-accountID').template // '`/account/${monetaryAccountId}`' */ get template() { return this.toTemplateString(); } /** Returns the path and its extracted params as a structured `URLObject`, or as a stringified expression when `stringify` is set. */ get object() { return this.toObject(); } /** Returns a map of path parameter names, or `undefined` when the path has no parameters. */ get params() { return this.getParams(); } #transformParam(raw) { const param = isValidVarName(raw) ? raw : camelCase(raw); return this.#options.casing === "camelcase" ? camelCase(param) : param; } /** Iterates over every `{param}` token in `path`, calling `fn` with the raw token and transformed name. */ #eachParam(fn) { for (const match of this.path.matchAll(/\{([^}]+)\}/g)) { const raw = match[1]; fn(raw, this.#transformParam(raw)); } } toObject({ type = "path", replacer, stringify } = {}) { const object = { url: type === "path" ? this.toURLPath() : this.toTemplateString({ replacer }), params: this.getParams() }; if (stringify) { if (type === "template") return JSON.stringify(object).replaceAll("'", "").replaceAll(`"`, ""); if (object.params) return `{ url: '${object.url}', params: ${JSON.stringify(object.params).replaceAll("'", "").replaceAll(`"`, "")} }`; return `{ url: '${object.url}' }`; } return object; } /** * Converts the OpenAPI path to a TypeScript template literal string. * An optional `replacer` can transform each extracted parameter name before interpolation. * * @example * new URLPath('/pet/{petId}').toTemplateString() // '`/pet/${petId}`' */ toTemplateString({ prefix = "", replacer } = {}) { return `\`${prefix}${this.path.split(/\{([^}]+)\}/).map((part, i) => { if (i % 2 === 0) return part; const param = this.#transformParam(part); return `\${${replacer ? replacer(param) : param}}`; }).join("")}\``; } /** * Extracts all `{param}` segments from the path and returns them as a key-value map. * An optional `replacer` transforms each parameter name in both key and value positions. * Returns `undefined` when no path parameters are found. */ getParams(replacer) { const params = {}; this.#eachParam((_raw, param) => { const key = replacer ? replacer(param) : param; params[key] = key; }); return Object.keys(params).length > 0 ? params : void 0; } /** Converts the OpenAPI path to Express-style colon syntax, e.g. `/pet/{petId}` → `/pet/:petId`. */ toURLPath() { return this.path.replace(/\{([^}]+)\}/g, ":$1"); } }; //#endregion //#region src/utils/getComments.ts function getComments(operation) { return [ operation.getDescription() && `@description ${operation.getDescription()}`, operation.getSummary() && `@summary ${operation.getSummary()}`, operation.path && `{@link ${new URLPath(operation.path).URL}}`, operation.isDeprecated() && "@deprecated" ].filter((x) => Boolean(x)).flatMap((text) => { return text.split(/\r?\n/).map((line) => line.trim()); }).filter((x) => Boolean(x)); } //#endregion //#region src/utils/getImports.ts /** * Get imports from a schema tree by extracting all ref schemas that are importable */ function getImports(tree) { const refs = SchemaGenerator.deepSearch(tree, schemaKeywords.ref); if (!refs) return []; return refs.map((item) => { if (!item.args.path || !item.args.isImportable) return; return { name: [item.args.name], path: item.args.path }; }).filter((x) => x !== void 0); } //#endregion //#region src/utils/getParams.ts /** * * @deprecated * TODO move to operationManager hook */ function getASTParams(operationSchema, { typed = false, casing, override } = {}) { if (!operationSchema || !operationSchema.schema.properties || !operationSchema.name) return []; const requiredFields = Array.isArray(operationSchema.schema.required) ? operationSchema.schema.required : []; return Object.entries(operationSchema.schema.properties).map(([name]) => { const accessName = casing === "camelcase" ? camelCase(name) : name; const data = { name, enabled: !!name, required: requiredFields.includes(name), type: typed ? `${operationSchema.name}["${accessName}"]` : void 0 }; return override ? override(data) : data; }); } function getPathParams(operationSchema, options = {}) { return getASTParams(operationSchema, options).reduce((acc, curr) => { if (curr.name && curr.enabled) { let name = curr.name; if (options.casing === "camelcase") name = camelCase(name); else if (!isValidVarName(name)) name = camelCase(name); acc[name] = { default: curr.default, type: curr.type, optional: !curr.required }; } return acc; }, {}); } /** * Get a mapping of camelCase parameter names to their original names * Used for mapping function parameters to backend parameter names */ function getParamsMapping(operationSchema, options = {}) { if (!operationSchema || !operationSchema.schema.properties) return; const allEntries = []; let hasTransformation = false; Object.entries(operationSchema.schema.properties).forEach(([originalName]) => { let transformedName = originalName; if (options.casing === "camelcase") transformedName = camelCase(originalName); else if (!isValidVarName(originalName)) transformedName = camelCase(originalName); allEntries.push([originalName, transformedName]); if (transformedName !== originalName) hasTransformation = true; }); if (options.casing === "camelcase" && hasTransformation) return Object.fromEntries(allEntries); const mapping = {}; allEntries.forEach(([originalName, transformedName]) => { if (transformedName !== originalName) mapping[originalName] = transformedName; }); return Object.keys(mapping).length > 0 ? mapping : void 0; } //#endregion //#region src/utils/getSchemas.ts /** * Collect schemas from OpenAPI components (schemas, responses, requestBodies) * and return them in dependency order along with name mapping for collision resolution. * * This function is a wrapper around the oas.getSchemas() method for backward compatibility. * New code should use oas.getSchemas() directly. * * @deprecated Use oas.getSchemas() instead */ function getSchemas({ oas, contentType, includes = [ "schemas", "requestBodies", "responses" ], collisionDetection }) { return oas.getSchemas({ contentType, includes, collisionDetection }); } //#endregion //#region src/utils/paramsCasing.ts /** * Apply casing transformation to schema properties * Only transforms property names, not nested schemas */ function applyParamsCasing(schema, casing) { if (!casing || !schema.properties) return schema; const transformedProperties = {}; const transformedRequired = []; Object.entries(schema.properties).forEach(([originalName, propertySchema]) => { let transformedName = originalName; if (casing === "camelcase") transformedName = camelCase(originalName); else if (!isValidVarName(originalName)) transformedName = camelCase(originalName); transformedProperties[transformedName] = propertySchema; }); if (Array.isArray(schema.required)) schema.required.forEach((originalName) => { let transformedName = originalName; if (casing === "camelcase") transformedName = camelCase(originalName); else if (!isValidVarName(originalName)) transformedName = camelCase(originalName); transformedRequired.push(transformedName); }); return { ...schema, properties: transformedProperties, ...transformedRequired.length > 0 && { required: transformedRequired } }; } /** * Check if this schema is a parameter schema (pathParams, queryParams, or headerParams) * Only these should be transformed, not response/data/body */ function isParameterSchema(schemaName) { const lowerName = schemaName.toLowerCase(); return lowerName.includes("pathparams") || lowerName.includes("queryparams") || lowerName.includes("headerparams"); } //#endregion export { applyParamsCasing, getBanner, getComments, getFooter, getImports, getParamsMapping, getPathParams, getSchemaFactory, getSchemas, isOptional, isParameterSchema, isRequestBodyRequired, withRequiredRequestBodySchema }; //# sourceMappingURL=utils.js.map