@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
JavaScript
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