@zimic/http
Version:
Next-gen TypeScript-first HTTP utilities
1,171 lines (1,158 loc) • 57.6 kB
JavaScript
import filesystem from 'fs/promises';
import path from 'path';
import ts3 from 'typescript';
import color from 'picocolors';
var __defProp = Object.defineProperty;
var __name = (target, value) => __defProp(target, "name", { value, configurable: true });
// ../zimic-utils/dist/chunk-2D3UJWOA.mjs
var __defProp2 = Object.defineProperty;
var __name2 = /* @__PURE__ */ __name((target, value) => __defProp2(target, "name", { value, configurable: true }), "__name");
// ../zimic-utils/dist/chunk-WC2DBWWR.mjs
function isDefined(value) {
return value !== void 0 && value !== null;
}
__name(isDefined, "isDefined");
__name2(isDefined, "isDefined");
var isDefined_default = isDefined;
function isNeverType(type) {
return type.kind === ts3.SyntaxKind.NeverKeyword;
}
__name(isNeverType, "isNeverType");
function isUnknownType(type) {
return type.kind === ts3.SyntaxKind.UnknownKeyword;
}
__name(isUnknownType, "isUnknownType");
function isNullType(type) {
return type.kind === ts3.SyntaxKind.NullKeyword;
}
__name(isNullType, "isNullType");
function createBlobType() {
return ts3.factory.createTypeReferenceNode("Blob");
}
__name(createBlobType, "createBlobType");
function createNullType() {
return ts3.factory.createLiteralTypeNode(ts3.factory.createNull());
}
__name(createNullType, "createNullType");
function createImportSpecifier(importName) {
return ts3.factory.createImportSpecifier(false, void 0, ts3.factory.createIdentifier(importName));
}
__name(createImportSpecifier, "createImportSpecifier");
function createImportDeclaration(importSpecifiers, moduleName, options) {
return ts3.factory.createImportDeclaration(
void 0,
ts3.factory.createImportClause(
options.typeOnly ? ts3.SyntaxKind.TypeKeyword : void 0,
void 0,
ts3.factory.createNamedImports(importSpecifiers)
),
ts3.factory.createStringLiteral(moduleName)
);
}
__name(createImportDeclaration, "createImportDeclaration");
// src/types/schema.ts
var HTTP_METHODS = Object.freeze(["GET", "POST", "PUT", "PATCH", "DELETE", "HEAD", "OPTIONS"]);
// ../zimic-utils/dist/logging/Logger.mjs
var Logger = class _Logger {
static {
__name(this, "_Logger");
}
static {
__name2(this, "Logger");
}
prefix;
raw;
constructor(options = {}) {
const { prefix } = options;
this.prefix = prefix;
this.raw = prefix ? new _Logger({ ...options, prefix: void 0 }) : this;
}
logWithLevel(level, ...messages) {
if (this.prefix) {
console[level](this.prefix, ...messages);
} else {
console[level](...messages);
}
}
info(...messages) {
this.logWithLevel("log", ...messages);
}
warn(...messages) {
this.logWithLevel("warn", ...messages);
}
error(...messages) {
this.logWithLevel("error", ...messages);
}
table(headers, rows) {
const columnLengths = headers.map((header) => {
let maxValueLength = header.title.length;
for (const row of rows) {
const value = row[header.property];
if (value.length > maxValueLength) {
maxValueLength = value.length;
}
}
return maxValueLength;
});
const formattedRows = [];
const horizontalLine = columnLengths.map((length) => "\u2500".repeat(length));
formattedRows.push(horizontalLine, []);
for (let headerIndex = 0; headerIndex < headers.length; headerIndex++) {
const header = headers[headerIndex];
const columnLength = columnLengths[headerIndex];
const value = header.title;
formattedRows.at(-1)?.push(value.padEnd(columnLength, " "));
}
formattedRows.push(horizontalLine);
for (const row of rows) {
formattedRows.push([]);
for (let headerIndex = 0; headerIndex < headers.length; headerIndex++) {
const header = headers[headerIndex];
const columnLength = columnLengths[headerIndex];
const value = row[header.property];
formattedRows.at(-1)?.push(value.padEnd(columnLength, " "));
}
}
formattedRows.push(horizontalLine);
const formattedTable = formattedRows.map((row, index) => {
const isFirstLine = index === 0;
if (isFirstLine) {
return `\u250C\u2500${row.join("\u2500\u252C\u2500")}\u2500\u2510`;
}
const isLineAfterHeaders = index === 2;
if (isLineAfterHeaders) {
return `\u251C\u2500${row.join("\u2500\u253C\u2500")}\u2500\u2524`;
}
const isLastLine = index === formattedRows.length - 1;
if (isLastLine) {
return `\u2514\u2500${row.join("\u2500\u2534\u2500")}\u2500\u2518`;
}
return `\u2502 ${row.join(" \u2502 ")} \u2502`;
}).join("\n");
this.logWithLevel("log", formattedTable);
}
};
var Logger_default = Logger;
var logger = new Logger_default({
prefix: color.cyan("[@zimic/http]")
});
function createOperationsIdentifierText(serviceName) {
return `${serviceName}Operations`;
}
__name(createOperationsIdentifierText, "createOperationsIdentifierText");
function createOperationsIdentifier(serviceName) {
return ts3.factory.createIdentifier(createOperationsIdentifierText(serviceName));
}
__name(createOperationsIdentifier, "createOperationsIdentifier");
function isOperationsDeclaration(node) {
return node !== void 0 && ts3.isInterfaceDeclaration(node) && node.name.text === "operations";
}
__name(isOperationsDeclaration, "isOperationsDeclaration");
function isOperation(node) {
return ts3.isPropertySignature(node) && (ts3.isIdentifier(node.name) || ts3.isStringLiteral(node.name)) && node.type !== void 0 && ts3.isTypeLiteralNode(node.type);
}
__name(isOperation, "isOperation");
function normalizeOperation(operation, context) {
if (!isOperation(operation)) {
return void 0;
}
const newType = normalizeTypeLiteralMethodType(operation.type, context);
return ts3.factory.updatePropertySignature(
operation,
operation.modifiers,
operation.name,
operation.questionToken,
newType
);
}
__name(normalizeOperation, "normalizeOperation");
function normalizeOperations(operations, context) {
const newIdentifier = createOperationsIdentifier(context.serviceName);
const newMembers = operations.members.map((operation) => normalizeOperation(operation, context)).filter(isDefined_default);
return ts3.factory.updateInterfaceDeclaration(
operations,
operations.modifiers,
newIdentifier,
operations.typeParameters,
operations.heritageClauses,
newMembers
);
}
__name(normalizeOperations, "normalizeOperations");
function removeOperationIfUnreferenced(operation, context) {
if (!isOperation(operation)) {
return void 0;
}
const operationName = operation.name.text;
const isReferenced = context.referencedTypes.operations.has(operationName);
if (isReferenced) {
context.referencedTypes.operations.delete(operationName);
return operation;
}
return void 0;
}
__name(removeOperationIfUnreferenced, "removeOperationIfUnreferenced");
function removeUnreferencedOperations(operations, context) {
const newMembers = operations.members.map((operation) => removeOperationIfUnreferenced(operation, context)).filter(isDefined_default);
context.referencedTypes.operations.clear();
if (newMembers.length === 0) {
return void 0;
}
return ts3.factory.updateInterfaceDeclaration(
operations,
operations.modifiers,
operations.name,
operations.typeParameters,
operations.heritageClauses,
newMembers
);
}
__name(removeUnreferencedOperations, "removeUnreferencedOperations");
// src/typegen/openapi/transform/methods.ts
function isMethod(node) {
return ts3.isPropertySignature(node) && ts3.isIdentifier(node.name) && node.type !== void 0 && (ts3.isTypeLiteralNode(node.type) || ts3.isIndexedAccessTypeNode(node.type));
}
__name(isMethod, "isMethod");
function isMethodMember(node) {
return ts3.isPropertySignature(node) && ts3.isIdentifier(node.name) && node.type !== void 0 && (ts3.isTypeLiteralNode(node.type) || ts3.isIndexedAccessTypeNode(node.type) || isNeverType(node.type));
}
__name(isMethodMember, "isMethodMember");
function isRequestMember(node) {
return ts3.isPropertySignature(node) && ts3.isIdentifier(node.name) && node.type !== void 0 && !isNeverType(node.type);
}
__name(isRequestMember, "isRequestMember");
function isRequestHeaders(node) {
return isRequestMember(node) && node.name.text === "headers" && ts3.isTypeLiteralNode(node.type);
}
__name(isRequestHeaders, "isRequestHeaders");
function isNormalizedRequestHeaders(node) {
return isRequestMember(node) && node.name.text === "headers" && ts3.isTypeLiteralNode(node.type);
}
__name(isNormalizedRequestHeaders, "isNormalizedRequestHeaders");
function isRequestParameters(node) {
return isRequestMember(node) && node.name.text === "parameters" && ts3.isTypeLiteralNode(node.type);
}
__name(isRequestParameters, "isRequestParameters");
function isContentPropertySignature(node) {
return isRequestMember(node) && node.name.text === "content" && ts3.isTypeLiteralNode(node.type);
}
__name(isContentPropertySignature, "isContentPropertySignature");
function isContentMember(node) {
return ts3.isPropertySignature(node) && (ts3.isIdentifier(node.name) || ts3.isStringLiteral(node.name)) && node.type !== void 0 && !isNeverType(node.type);
}
__name(isContentMember, "isContentMember");
function isResponse(node) {
return ts3.isPropertySignature(node) && (ts3.isIdentifier(node.name) || ts3.isStringLiteral(node.name) || ts3.isNumericLiteral(node.name)) && node.type !== void 0;
}
__name(isResponse, "isResponse");
function removeRedundantNullUnionIfNecessary(type) {
const containsRedundantNullUnion = ts3.isUnionTypeNode(type) && type.types.some((type2) => {
const isNull = ts3.isLiteralTypeNode(type2) && isNullType(type2.literal);
return isNull;
}) && type.types.some((type2) => {
return ts3.isParenthesizedTypeNode(type2) && ts3.isUnionTypeNode(type2.type) && type2.type.types.some((subType) => {
const isNull = ts3.isLiteralTypeNode(subType) && isNullType(subType.literal);
return isNull;
});
});
if (!containsRedundantNullUnion) {
return type;
}
const typesWithoutRedundantNullUnion = type.types.filter((type2) => {
const isNull = ts3.isLiteralTypeNode(type2) && isNullType(type2.literal);
return !isNull;
}).flatMap((type2) => {
if (ts3.isParenthesizedTypeNode(type2) && ts3.isUnionTypeNode(type2.type)) {
return type2.type.types;
}
return [type2];
});
return ts3.factory.createUnionTypeNode(typesWithoutRedundantNullUnion);
}
__name(removeRedundantNullUnionIfNecessary, "removeRedundantNullUnionIfNecessary");
function wrapFormDataContentType(type, context) {
context.typeImports.http.add("HttpFormData");
return ts3.factory.createTypeReferenceNode(ts3.factory.createIdentifier("HttpFormData"), [
renameComponentReferences(type, context)
]);
}
__name(wrapFormDataContentType, "wrapFormDataContentType");
function wrapURLEncodedContentType(type, context) {
context.typeImports.http.add("HttpSearchParams");
return ts3.factory.createTypeReferenceNode(ts3.factory.createIdentifier("HttpSearchParams"), [
renameComponentReferences(type, context)
]);
}
__name(wrapURLEncodedContentType, "wrapURLEncodedContentType");
function normalizeRequestBodyMember(requestBodyMember, context, options) {
if (!isContentMember(requestBodyMember)) {
return void 0;
}
const newIdentifier = ts3.factory.createIdentifier("body");
const contentType = requestBodyMember.name.text;
let newType = removeRedundantNullUnionIfNecessary(renameComponentReferences(requestBodyMember.type, context));
if (contentType === "multipart/form-data") {
newType = wrapFormDataContentType(newType, context);
} else if (contentType === "x-www-form-urlencoded") {
newType = wrapURLEncodedContentType(newType, context);
}
return {
contentTypeName: contentType,
propertySignature: ts3.factory.updatePropertySignature(
requestBodyMember,
requestBodyMember.modifiers,
newIdentifier,
options.questionToken,
newType
)
};
}
__name(normalizeRequestBodyMember, "normalizeRequestBodyMember");
function normalizeHeaders(headers) {
const newHeaderMembers = headers.members.filter((header) => {
if (ts3.isIndexSignatureDeclaration(header)) {
return false;
}
if (ts3.isPropertySignature(header)) {
return header.type !== void 0 && !isUnknownType(header.type);
}
return true;
});
if (newHeaderMembers.length === 0) {
return void 0;
}
return ts3.factory.updateTypeLiteralNode(headers, ts3.factory.createNodeArray(newHeaderMembers));
}
__name(normalizeHeaders, "normalizeHeaders");
function normalizeRequestHeaders(requestHeader) {
if (!isRequestHeaders(requestHeader)) {
return void 0;
}
const newType = normalizeHeaders(requestHeader.type);
if (!newType) {
return void 0;
}
return ts3.factory.updatePropertySignature(
requestHeader,
requestHeader.modifiers,
requestHeader.name,
requestHeader.questionToken,
newType
);
}
__name(normalizeRequestHeaders, "normalizeRequestHeaders");
function createHeaderForUnionByContentType(existingHeader, contentTypeName) {
const existingHeaderMembers = existingHeader?.type.members ?? [];
const contentTypeIdentifier = ts3.factory.createIdentifier('"content-type"');
const contentTypeValue = ts3.factory.createLiteralTypeNode(ts3.factory.createStringLiteral(contentTypeName));
const newHeaderType = ts3.factory.createTypeLiteralNode([
ts3.factory.createPropertySignature(void 0, contentTypeIdentifier, void 0, contentTypeValue),
...existingHeaderMembers
]);
return ts3.factory.createPropertySignature(
existingHeader?.modifiers,
ts3.factory.createIdentifier("headers"),
void 0,
newHeaderType
);
}
__name(createHeaderForUnionByContentType, "createHeaderForUnionByContentType");
function normalizeContentType(contentType, context, options) {
const { bodyQuestionToken } = options;
if (ts3.isIndexedAccessTypeNode(contentType)) {
return renameComponentReferences(contentType, context);
}
if (!ts3.isTypeLiteralNode(contentType)) {
return contentType;
}
const newHeader = contentType.members.map(normalizeRequestHeaders).find(isDefined_default);
const newBodyMembers = contentType.members.flatMap((body) => {
if (isContentPropertySignature(body)) {
return body.type.members.map((member) => normalizeRequestBodyMember(member, context, { questionToken: bodyQuestionToken })).filter(isDefined_default);
}
return [];
});
if (newBodyMembers.length === 0) {
const newMembers = [newHeader].filter(isDefined_default);
return ts3.factory.updateTypeLiteralNode(contentType, ts3.factory.createNodeArray(newMembers));
} else {
const bodyMemberUnionTypes = newBodyMembers.map((bodyMember) => {
const headerMember = createHeaderForUnionByContentType(newHeader, bodyMember.contentTypeName);
return ts3.factory.createTypeLiteralNode([headerMember, bodyMember.propertySignature]);
});
return ts3.factory.createUnionTypeNode(bodyMemberUnionTypes);
}
}
__name(normalizeContentType, "normalizeContentType");
function normalizeRequest(request, context) {
const newIdentifier = ts3.factory.createIdentifier("request");
const newType = normalizeContentType(request.type, context, {
bodyQuestionToken: request.questionToken
});
if (request.questionToken && ts3.isIndexedAccessTypeNode(request.type) && ts3.isLiteralTypeNode(request.type.indexType) && (ts3.isIdentifier(request.type.indexType.literal) || ts3.isStringLiteral(request.type.indexType.literal))) {
const referencedComponentName = request.type.indexType.literal.text;
context.pendingActions.components.requests.toMarkBodyAsOptional.add(referencedComponentName);
}
return ts3.factory.updatePropertySignature(request, request.modifiers, newIdentifier, void 0, newType);
}
__name(normalizeRequest, "normalizeRequest");
function normalizeResponseType(responseType, context, options) {
const { questionToken } = options;
if (!ts3.isTypeLiteralNode(responseType)) {
return responseType;
}
return normalizeContentType(responseType, context, { bodyQuestionToken: questionToken });
}
__name(normalizeResponseType, "normalizeResponseType");
var NON_NUMERIC_RESPONSE_STATUS_TO_MAPPED_TYPE = {
default: "HttpStatusCode",
"1xx": "HttpStatusCode.Information",
"2xx": "HttpStatusCode.Success",
"3xx": "HttpStatusCode.Redirection",
"4xx": "HttpStatusCode.ClientError",
"5xx": "HttpStatusCode.ServerError"
};
function normalizeResponse(response, context, options = {}) {
const { isComponent: isComponent2 = false } = options;
if (!isResponse(response)) {
return void 0;
}
const newType = normalizeResponseType(response.type, context, {
questionToken: response.questionToken
});
const statusCodeOrComponentName = response.name.text;
const isNumericStatusCode = /^\d+$/.test(statusCodeOrComponentName);
const shouldReuseIdentifier = isComponent2 || isNumericStatusCode;
let newSignature;
if (shouldReuseIdentifier) {
newSignature = ts3.factory.updatePropertySignature(
response,
response.modifiers,
response.name,
response.questionToken,
newType
);
} else {
const statusCode = statusCodeOrComponentName.toLowerCase();
const mappedType = NON_NUMERIC_RESPONSE_STATUS_TO_MAPPED_TYPE[statusCode];
if (!mappedType) {
logger.warn(
`Warning: Response has a non-standard status code: ${color.yellow(response.name.text)}. Consider replacing it with a number (e.g. '200'), a pattern ('1xx', '2xx', '3xx', '4xx', or '5xx'), or 'default'.`
);
return void 0;
}
context.typeImports.http.add("HttpStatusCode");
const newIdentifier = ts3.factory.createIdentifier(`[StatusCode in ${mappedType}]`);
newSignature = ts3.factory.updatePropertySignature(
response,
response.modifiers,
newIdentifier,
response.questionToken,
newType
);
}
return {
newSignature,
statusCode: {
value: statusCodeOrComponentName,
isNumeric: isNumericStatusCode
}
};
}
__name(normalizeResponse, "normalizeResponse");
function normalizeResponses(responses, context) {
if (isNeverType(responses.type) || !ts3.isTypeLiteralNode(responses.type)) {
return void 0;
}
const newIdentifier = ts3.factory.createIdentifier("response");
const newQuestionToken = void 0;
const newMembers = responses.type.members.map((response) => normalizeResponse(response, context), context).filter(isDefined_default);
const sortedNewMembers = Array.from(newMembers).sort((response, otherResponse) => {
return response.statusCode.value.localeCompare(otherResponse.statusCode.value);
});
const isEveryStatusCodeNumeric = sortedNewMembers.every((response) => response.statusCode.isNumeric);
let newType;
if (isEveryStatusCodeNumeric) {
newType = ts3.factory.updateTypeLiteralNode(
responses.type,
ts3.factory.createNodeArray(sortedNewMembers.map((response) => response.newSignature))
);
} else {
context.typeImports.http.add("MergeHttpResponsesByStatusCode");
const typeMembersToMerge = sortedNewMembers.reduce(
(members, response) => {
if (response.statusCode.isNumeric) {
members.numeric.push(response.newSignature);
} else {
members.nonNumeric.push(response.newSignature);
}
return members;
},
{ numeric: [], nonNumeric: [] }
);
const numericTypeLiteral = ts3.factory.createTypeLiteralNode(typeMembersToMerge.numeric);
const nonNumericTypeLiterals = typeMembersToMerge.nonNumeric.map(
(response) => ts3.factory.createTypeLiteralNode([response])
);
const mergeWrapper = ts3.factory.createIdentifier("MergeHttpResponsesByStatusCode");
newType = ts3.factory.createTypeReferenceNode(mergeWrapper, [
ts3.factory.createTupleTypeNode([numericTypeLiteral, ...nonNumericTypeLiterals])
]);
}
return ts3.factory.updatePropertySignature(
responses,
responses.modifiers,
newIdentifier,
newQuestionToken,
renameComponentReferences(newType, context)
);
}
__name(normalizeResponses, "normalizeResponses");
function normalizeMethodMember(methodMember, context) {
if (isMethodMember(methodMember)) {
if (methodMember.name.text === "requestBody") {
return normalizeRequest(methodMember, context);
}
if (methodMember.name.text === "responses") {
return normalizeResponses(methodMember, context);
}
return methodMember;
}
return void 0;
}
__name(normalizeMethodMember, "normalizeMethodMember");
function normalizeRequestQueryWithParameters(requestMember, context) {
const newIdentifier = ts3.factory.createIdentifier("searchParams");
const newQuestionToken = void 0;
const newType = renameComponentReferences(requestMember.type, context);
return ts3.factory.updatePropertySignature(
requestMember,
requestMember.modifiers,
newIdentifier,
newQuestionToken,
newType
);
}
__name(normalizeRequestQueryWithParameters, "normalizeRequestQueryWithParameters");
function normalizeRequestHeadersWithParameters(requestMember, context) {
const newIdentifier = ts3.factory.createIdentifier("headers");
const newQuestionToken = void 0;
const newType = renameComponentReferences(requestMember.type, context);
return ts3.factory.updatePropertySignature(
requestMember,
requestMember.modifiers,
newIdentifier,
newQuestionToken,
newType
);
}
__name(normalizeRequestHeadersWithParameters, "normalizeRequestHeadersWithParameters");
function normalizeRequestMemberWithParameters(requestMember, context) {
if (!isRequestMember(requestMember) || requestMember.name.text === "path") {
return void 0;
}
if (requestMember.name.text === "query") {
return normalizeRequestQueryWithParameters(requestMember, context);
}
if (requestMember.name.text === "header") {
return normalizeRequestHeadersWithParameters(requestMember, context);
}
return requestMember;
}
__name(normalizeRequestMemberWithParameters, "normalizeRequestMemberWithParameters");
function mergeRequestHeadersMember(headers, otherHeaders) {
const newType = ts3.factory.updateTypeLiteralNode(
headers.type,
ts3.factory.createNodeArray([...otherHeaders.type.members, ...headers.type.members])
);
return ts3.factory.updatePropertySignature(
headers,
headers.modifiers,
headers.name,
headers.questionToken,
newType
);
}
__name(mergeRequestHeadersMember, "mergeRequestHeadersMember");
function mergeRequestHeadersMembers(members) {
let mergedHeaders;
let firstHeadersIndex;
const mergedHeadersMembers = members.map((member, index) => {
if (!member || !isNormalizedRequestHeaders(member)) {
return member;
}
if (firstHeadersIndex === void 0 || !mergedHeaders) {
firstHeadersIndex = index;
mergedHeaders = member;
return member;
}
mergedHeaders = mergeRequestHeadersMember(mergedHeaders, member);
return void 0;
});
if (firstHeadersIndex !== void 0) {
mergedHeadersMembers[firstHeadersIndex] = mergedHeaders;
}
return mergedHeadersMembers.filter(isDefined_default);
}
__name(mergeRequestHeadersMembers, "mergeRequestHeadersMembers");
function mergeRequestAndParameterTypes(requestType, methodMembers, context) {
const parameters = methodMembers.find(isRequestParameters);
const parametersMembers = parameters ? parameters.type.members : [];
const requestMembers = ts3.isTypeLiteralNode(requestType) ? requestType.members : [];
const newMembers = mergeRequestHeadersMembers(
[...parametersMembers, ...requestMembers].map((member) => {
return normalizeRequestMemberWithParameters(member, context);
})
);
if (newMembers.length === 0) {
return void 0;
}
return ts3.factory.createTypeLiteralNode(newMembers);
}
__name(mergeRequestAndParameterTypes, "mergeRequestAndParameterTypes");
function normalizeRequestTypeWithParameters(requestType, methodMembers, context) {
if (ts3.isUnionTypeNode(requestType)) {
const newTypes = requestType.types.map((type) => normalizeRequestTypeWithParameters(type, methodMembers, context)).filter(isDefined_default);
return ts3.factory.updateUnionTypeNode(requestType, ts3.factory.createNodeArray(newTypes));
}
if (ts3.isIndexedAccessTypeNode(requestType)) {
const newType = normalizeRequestTypeWithParameters(ts3.factory.createTypeLiteralNode([]), methodMembers, context);
return ts3.factory.createIntersectionTypeNode([requestType, newType].filter(isDefined_default));
}
return mergeRequestAndParameterTypes(requestType, methodMembers, context);
}
__name(normalizeRequestTypeWithParameters, "normalizeRequestTypeWithParameters");
function normalizeMethodMemberWithParameters(methodMember, methodMembers, context) {
if (!ts3.isIdentifier(methodMember.name) || !methodMember.type) {
return void 0;
}
if (methodMember.name.text === "request") {
const newType = normalizeRequestTypeWithParameters(methodMember.type, methodMembers, context);
if (!newType) {
return void 0;
}
return ts3.factory.updatePropertySignature(
methodMember,
methodMember.modifiers,
methodMember.name,
void 0,
newType
);
}
if (methodMember.name.text === "response") {
return methodMember;
}
return void 0;
}
__name(normalizeMethodMemberWithParameters, "normalizeMethodMemberWithParameters");
function normalizeTypeLiteralMethodType(methodType, context) {
const newMembers = methodType.members.map((member) => normalizeMethodMember(member, context)).filter(isDefined_default).map((member, _index, partialMembers) => normalizeMethodMemberWithParameters(member, partialMembers, context)).filter(isDefined_default);
return ts3.factory.updateTypeLiteralNode(methodType, ts3.factory.createNodeArray(newMembers));
}
__name(normalizeTypeLiteralMethodType, "normalizeTypeLiteralMethodType");
function normalizeIndexedAccessMethodType(methodType, context) {
const isOperationsReference = ts3.isTypeReferenceNode(methodType.objectType) && ts3.isIdentifier(methodType.objectType.typeName) && methodType.objectType.typeName.text === "operations";
if (!isOperationsReference) {
return methodType;
}
const newIdentifier = createOperationsIdentifier(context.serviceName);
const newObjectType = ts3.factory.createTypeReferenceNode(newIdentifier, methodType.objectType.typeArguments);
const hasIndexTypeName = ts3.isLiteralTypeNode(methodType.indexType) && (ts3.isIdentifier(methodType.indexType.literal) || ts3.isStringLiteral(methodType.indexType.literal));
if (hasIndexTypeName) {
const operationName = methodType.indexType.literal.text;
context.referencedTypes.operations.add(operationName);
}
return ts3.factory.updateIndexedAccessTypeNode(methodType, newObjectType, methodType.indexType);
}
__name(normalizeIndexedAccessMethodType, "normalizeIndexedAccessMethodType");
function normalizeMethod(method, context, options) {
if (!isMethod(method)) {
return void 0;
}
const methodName = method.name.text.toUpperCase();
if (!HTTP_METHODS.includes(methodName)) {
return void 0;
}
const pathMethodCompareString = `${methodName} ${options.pathName}`;
const matchesPositiveFilters = context.filters.paths.positive.length === 0 || context.filters.paths.positive.some((filter) => filter.test(pathMethodCompareString));
const matchesNegativeFilters = context.filters.paths.negative.length > 0 && context.filters.paths.negative.some((filter) => filter.test(pathMethodCompareString));
if (!matchesPositiveFilters || matchesNegativeFilters) {
return void 0;
}
const newIdentifier = ts3.factory.createIdentifier(methodName);
const newType = ts3.isTypeLiteralNode(method.type) ? normalizeTypeLiteralMethodType(method.type, context) : normalizeIndexedAccessMethodType(method.type, context);
return ts3.factory.updatePropertySignature(method, method.modifiers, newIdentifier, method.questionToken, newType);
}
__name(normalizeMethod, "normalizeMethod");
function createPathsIdentifier(serviceName) {
return ts3.factory.createIdentifier(`${serviceName}Schema`);
}
__name(createPathsIdentifier, "createPathsIdentifier");
function isPathsDeclaration(node) {
return node !== void 0 && (ts3.isInterfaceDeclaration(node) || ts3.isTypeAliasDeclaration(node)) && node.name.text === "paths";
}
__name(isPathsDeclaration, "isPathsDeclaration");
function isPath(node) {
return ts3.isPropertySignature(node) && (ts3.isIdentifier(node.name) || ts3.isStringLiteral(node.name)) && node.type !== void 0 && (ts3.isTypeLiteralNode(node.type) || ts3.isIndexedAccessTypeNode(node.type));
}
__name(isPath, "isPath");
function normalizePathNameWithParameters(pathName) {
return pathName.replace(/{([^}]+)}/g, ":$1");
}
__name(normalizePathNameWithParameters, "normalizePathNameWithParameters");
function normalizePath(path4, context, options = {}) {
const { isComponent: isComponent2 = false } = options;
if (!isPath(path4)) {
return void 0;
}
const newPathName = isComponent2 ? path4.name.text : normalizePathNameWithParameters(path4.name.text);
const newIdentifier = isComponent2 ? path4.name : ts3.factory.createStringLiteral(newPathName);
let newType;
if (ts3.isTypeLiteralNode(path4.type)) {
const newMethods = path4.type.members.map((method) => normalizeMethod(method, context, { pathName: newPathName })).filter(isDefined_default);
if (newMethods.length === 0) {
return void 0;
}
newType = ts3.factory.updateTypeLiteralNode(path4.type, ts3.factory.createNodeArray(newMethods));
} else {
newType = renameComponentReferences(path4.type, context);
}
return ts3.factory.updatePropertySignature(path4, path4.modifiers, newIdentifier, path4.questionToken, newType);
}
__name(normalizePath, "normalizePath");
function wrapPathsType(type, context) {
context.typeImports.http.add("HttpSchema");
const httpSchemaPathsWrapper = ts3.factory.createIdentifier("HttpSchema");
return ts3.factory.createTypeReferenceNode(httpSchemaPathsWrapper, [type]);
}
__name(wrapPathsType, "wrapPathsType");
function normalizePaths(pathsOrTypeAlias, context) {
const newIdentifier = createPathsIdentifier(context.serviceName);
const paths = ts3.isTypeAliasDeclaration(pathsOrTypeAlias) ? ts3.factory.createInterfaceDeclaration(pathsOrTypeAlias.modifiers, pathsOrTypeAlias.name, void 0, void 0, []) : pathsOrTypeAlias;
const newMembers = paths.members.map((path4) => normalizePath(path4, context)).filter(isDefined_default);
const newType = ts3.factory.createTypeLiteralNode(newMembers);
return ts3.factory.createTypeAliasDeclaration(
paths.modifiers,
newIdentifier,
paths.typeParameters,
wrapPathsType(newType, context)
);
}
__name(normalizePaths, "normalizePaths");
// src/typegen/openapi/transform/components.ts
function createComponentsIdentifierText(serviceName) {
return `${serviceName}Components`;
}
__name(createComponentsIdentifierText, "createComponentsIdentifierText");
function createComponentsIdentifier(serviceName) {
return ts3.factory.createIdentifier(createComponentsIdentifierText(serviceName));
}
__name(createComponentsIdentifier, "createComponentsIdentifier");
function isComponentsDeclaration(node, context) {
const componentIdentifiers = ["components", createComponentsIdentifierText(context.serviceName)];
return node !== void 0 && ts3.isInterfaceDeclaration(node) && componentIdentifiers.includes(node.name.text);
}
__name(isComponentsDeclaration, "isComponentsDeclaration");
function isComponentGroup(node) {
return ts3.isPropertySignature(node) && node.type !== void 0 && ts3.isTypeLiteralNode(node.type) && ts3.isIdentifier(node.name);
}
__name(isComponentGroup, "isComponentGroup");
function isComponent(node) {
return ts3.isPropertySignature(node) && node.type !== void 0 && !isNeverType(node.type) && (ts3.isIdentifier(node.name) || ts3.isStringLiteral(node.name));
}
__name(isComponent, "isComponent");
function isRequestComponent(node) {
return ts3.isTypeLiteralNode(node.type);
}
__name(isRequestComponent, "isRequestComponent");
function unchangedIndexedAccessTypeNode(node) {
return node;
}
__name(unchangedIndexedAccessTypeNode, "unchangedIndexedAccessTypeNode");
function visitComponentReferences(node, context, options) {
const { onComponentReference, renameComponentReference = unchangedIndexedAccessTypeNode } = options;
if (isUnknownType(node)) {
return ts3.factory.createKeywordTypeNode(ts3.SyntaxKind.AnyKeyword);
}
if (ts3.isTypeReferenceNode(node)) {
const newTypeArguments = node.typeArguments?.map((type) => visitComponentReferences(type, context, options));
return ts3.factory.updateTypeReferenceNode(node, node.typeName, ts3.factory.createNodeArray(newTypeArguments));
}
if (ts3.isArrayTypeNode(node)) {
const newElementType = visitComponentReferences(node.elementType, context, options);
return ts3.factory.updateArrayTypeNode(node, newElementType);
}
if (ts3.isTupleTypeNode(node)) {
const newElements = node.elements.map((element) => visitComponentReferences(element, context, options));
return ts3.factory.updateTupleTypeNode(node, ts3.factory.createNodeArray(newElements));
}
if (ts3.isUnionTypeNode(node)) {
const newTypes = node.types.map((type) => visitComponentReferences(type, context, options));
return ts3.factory.updateUnionTypeNode(node, ts3.factory.createNodeArray(newTypes));
}
if (ts3.isIntersectionTypeNode(node)) {
const newTypes = node.types.map((type) => visitComponentReferences(type, context, options));
return ts3.factory.updateIntersectionTypeNode(node, ts3.factory.createNodeArray(newTypes));
}
if (ts3.isParenthesizedTypeNode(node)) {
const newType = visitComponentReferences(node.type, context, options);
return ts3.factory.updateParenthesizedType(node, newType);
}
if (ts3.isTypeLiteralNode(node)) {
const newMembers = node.members.map((member) => {
if (ts3.isPropertySignature(member) && member.type) {
const newType = visitComponentReferences(member.type, context, options);
return ts3.factory.updatePropertySignature(member, member.modifiers, member.name, member.questionToken, newType);
}
if (ts3.isIndexSignatureDeclaration(member)) {
const newType = visitComponentReferences(member.type, context, options);
return ts3.factory.updateIndexSignature(member, member.modifiers, member.parameters, newType);
}
return member;
});
return ts3.factory.updateTypeLiteralNode(node, ts3.factory.createNodeArray(newMembers));
}
if (ts3.isIndexedAccessTypeNode(node)) {
const isRootIndexedAccess = context.isComponentIndexedAccess ?? true;
if (ts3.isIndexedAccessTypeNode(node.objectType)) {
const childContext = { ...context, isComponentIndexedAccess: false };
const newObjectType = visitComponentReferences(node.objectType, childContext, options);
const newNode = ts3.factory.updateIndexedAccessTypeNode(node, newObjectType, node.indexType);
if (childContext.partialComponentPath && childContext.partialComponentPath.length > 0) {
const hasIndexTypeName = ts3.isLiteralTypeNode(node.indexType) && (ts3.isIdentifier(node.indexType.literal) || ts3.isStringLiteral(node.indexType.literal));
if (hasIndexTypeName) {
const componentName = node.indexType.literal.text;
childContext.partialComponentPath.push(componentName);
}
if (isRootIndexedAccess) {
const componentGroupName = childContext.partialComponentPath[0];
const componentName = childContext.partialComponentPath.slice(1).join(".");
const componentPath = `${componentGroupName}.${componentName}`;
onComponentReference(newNode, componentPath);
}
}
return newNode;
}
const componentIdentifiers = ["components", createComponentsIdentifierText(context.serviceName)];
const isComponentIndexedAccess = ts3.isTypeReferenceNode(node.objectType) && ts3.isIdentifier(node.objectType.typeName) && componentIdentifiers.includes(node.objectType.typeName.text) && ts3.isLiteralTypeNode(node.indexType) && (ts3.isIdentifier(node.indexType.literal) || ts3.isStringLiteral(node.indexType.literal));
if (isComponentIndexedAccess) {
const isRawComponent = node.objectType.typeName.text === "components";
const componentGroupName = node.indexType.literal.text;
const newNode = isRawComponent ? renameComponentReference(node, {
objectType: node.objectType,
indexType: node.indexType,
componentGroupName
}) : node;
const newNodeHasComponentGroupName = ts3.isLiteralTypeNode(newNode.indexType) && (ts3.isIdentifier(newNode.indexType.literal) || ts3.isStringLiteral(newNode.indexType.literal));
if (newNodeHasComponentGroupName) {
const newComponentGroupName = newNode.indexType.literal.text;
context.partialComponentPath = [newComponentGroupName];
}
return newNode;
}
}
return node;
}
__name(visitComponentReferences, "visitComponentReferences");
function normalizeComponentGroupName(rawComponentGroupName) {
if (rawComponentGroupName === "requestBodies") {
return "requests";
}
return rawComponentGroupName;
}
__name(normalizeComponentGroupName, "normalizeComponentGroupName");
function renameComponentReferences(node, context) {
return visitComponentReferences(node, context, {
onComponentReference(_node, componentPath) {
context.referencedTypes.components.add(componentPath);
},
renameComponentReference(node2, { indexType, objectType, componentGroupName }) {
const newIdentifier = createComponentsIdentifier(context.serviceName);
const newObjectType = ts3.factory.updateTypeReferenceNode(objectType, newIdentifier, objectType.typeArguments);
const newComponentGroupName = normalizeComponentGroupName(componentGroupName);
const newIndexType = ts3.factory.updateLiteralTypeNode(
indexType,
ts3.factory.createStringLiteral(newComponentGroupName)
);
return ts3.factory.updateIndexedAccessTypeNode(node2, newObjectType, newIndexType);
}
});
}
__name(renameComponentReferences, "renameComponentReferences");
function processPendingRequestComponentActions(component, context) {
const pendingRequestActions = context.pendingActions.components.requests;
const componentName = component.name.text;
const shouldBeMarkedAsOptional = pendingRequestActions.toMarkBodyAsOptional.has(componentName);
const bodyQuestionToken = shouldBeMarkedAsOptional ? ts3.factory.createToken(ts3.SyntaxKind.QuestionToken) : component.questionToken;
pendingRequestActions.toMarkBodyAsOptional.delete(componentName);
return { bodyQuestionToken };
}
__name(processPendingRequestComponentActions, "processPendingRequestComponentActions");
function normalizeRequestComponent(component, context) {
if (!isRequestComponent(component)) {
return void 0;
}
const { bodyQuestionToken } = processPendingRequestComponentActions(component, context);
const newType = normalizeContentType(component.type, context, { bodyQuestionToken });
return ts3.factory.updatePropertySignature(
component,
component.modifiers,
component.name,
component.questionToken,
newType
);
}
__name(normalizeRequestComponent, "normalizeRequestComponent");
function normalizeComponent(component, componentGroupName, context) {
if (!isComponent(component)) {
return void 0;
}
if (componentGroupName === "requests") {
return normalizeRequestComponent(component, context);
}
if (componentGroupName === "responses") {
const responseComponent = normalizeResponse(component, context, { isComponent: true });
return responseComponent?.newSignature;
}
if (componentGroupName === "pathItems") {
return normalizePath(component, context, { isComponent: true });
}
return ts3.factory.updatePropertySignature(
component,
component.modifiers,
component.name,
component.questionToken,
renameComponentReferences(component.type, context)
);
}
__name(normalizeComponent, "normalizeComponent");
function normalizeComponentGroup(componentGroup, context) {
if (!isComponentGroup(componentGroup)) {
return void 0;
}
const componentGroupName = normalizeComponentGroupName(componentGroup.name.text);
const newIdentifier = ts3.factory.createIdentifier(componentGroupName);
const newComponents = componentGroup.type.members.map((component) => normalizeComponent(component, componentGroupName, context)).filter(isDefined_default);
const newType = ts3.factory.updateTypeLiteralNode(componentGroup.type, ts3.factory.createNodeArray(newComponents));
return ts3.factory.updatePropertySignature(
componentGroup,
componentGroup.modifiers,
newIdentifier,
componentGroup.questionToken,
newType
);
}
__name(normalizeComponentGroup, "normalizeComponentGroup");
function normalizeComponents(components, context) {
const newIdentifier = createComponentsIdentifier(context.serviceName);
const newMembers = components.members.map((componentGroup) => normalizeComponentGroup(componentGroup, context)).filter(isDefined_default);
return ts3.factory.updateInterfaceDeclaration(
components,
components.modifiers,
newIdentifier,
components.typeParameters,
components.heritageClauses,
newMembers
);
}
__name(normalizeComponents, "normalizeComponents");
function populateReferencedComponents(components, context) {
const pathsToVisit = new Set(context.referencedTypes.components);
while (pathsToVisit.size > 0) {
const previousPathsToVisit = new Set(pathsToVisit);
pathsToVisit.clear();
for (const componentGroup of components.members) {
if (!isComponentGroup(componentGroup)) {
continue;
}
const componentGroupName = normalizeComponentGroupName(componentGroup.name.text);
for (const component of componentGroup.type.members) {
if (!isComponent(component)) {
continue;
}
const componentName = component.name.text;
const componentPath = `${componentGroupName}.${componentName}`;
const isComponentToVisit = previousPathsToVisit.has(componentPath);
if (!isComponentToVisit) {
continue;
}
context.referencedTypes.components.add(componentPath);
visitComponentReferences(component.type, context, {
onComponentReference(_node, componentPath2) {
const isKnownReferencedComponent = context.referencedTypes.components.has(componentPath2);
if (!isKnownReferencedComponent) {
pathsToVisit.add(componentPath2);
}
}
});
}
}
}
}
__name(populateReferencedComponents, "populateReferencedComponents");
function removeComponentIfUnreferenced(component, componentGroupName, context) {
if (!isComponent(component)) {
return void 0;
}
const componentName = component.name.text;
const componentPath = `${componentGroupName}.${componentName}`;
if (context.referencedTypes.components.has(componentPath)) {
context.referencedTypes.components.delete(componentPath);
return component;
}
return void 0;
}
__name(removeComponentIfUnreferenced, "removeComponentIfUnreferenced");
function removeUnreferencedComponentsInGroup(componentGroup, context) {
if (!isComponentGroup(componentGroup)) {
return void 0;
}
const componentGroupName = normalizeComponentGroupName(componentGroup.name.text);
const newComponents = componentGroup.type.members.map((component) => removeComponentIfUnreferenced(component, componentGroupName, context)).filter(isDefined_default);
if (newComponents.length === 0) {
return void 0;
}
return ts3.factory.updatePropertySignature(
componentGroup,
componentGroup.modifiers,
componentGroup.name,
componentGroup.questionToken,
ts3.factory.updateTypeLiteralNode(componentGroup.type, ts3.factory.createNodeArray(newComponents))
);
}
__name(removeUnreferencedComponentsInGroup, "removeUnreferencedComponentsInGroup");
function removeUnreferencedComponents(components, context) {
const newComponentGroups = components.members.map((componentGroup) => removeUnreferencedComponentsInGroup(componentGroup, context)).filter(isDefined_default);
context.referencedTypes.components.clear();
if (newComponentGroups.length === 0) {
return void 0;
}
return ts3.factory.updateInterfaceDeclaration(
components,
components.modifiers,
components.name,
components.typeParameters,
components.heritageClauses,
newComponentGroups
);
}
__name(removeUnreferencedComponents, "removeUnreferencedComponents");
// src/utils/strings.ts
function convertToPascalCase(value) {
return value.replace(/(?:^|[^A-Za-z\d])([A-Za-z\d])/g, (_match, letter) => letter.toUpperCase());
}
__name(convertToPascalCase, "convertToPascalCase");
// ../zimic-utils/dist/data/isNonEmpty.mjs
function isNonEmpty(value) {
return isDefined_default(value) && value !== "";
}
__name(isNonEmpty, "isNonEmpty");
__name2(isNonEmpty, "isNonEmpty");
var isNonEmpty_default = isNonEmpty;
// ../zimic-utils/dist/url/createRegExpFromWildcardPath.mjs
function prepareURLForRegex(url) {
const encodedURL = encodeURI(url);
return encodedURL.replace(/([.()*?+$\\])/g, "\\$1");
}
__name(prepareURLForRegex, "prepareURLForRegex");
__name2(prepareURLForRegex, "prepareURLForRegex");
function createRegExpFromWildcardPath(path4, options) {
const pathWithReplacedWildcards = prepareURLForRegex(path4).replace(/^\/+|\/+$/g, "").replace(/\\\*/g, "*").replace(/\*\*\/\*/g, "**").replace(/(^|[^*])\*([^*]|$)/g, "$1[^/]*$2").replace(/\*\*/g, ".*");
return new RegExp(`^${options.prefix}/*${pathWithReplacedWildcards}/*$`);
}
__name(createRegExpFromWildcardPath, "createRegExpFromWildcardPath");
__name2(createRegExpFromWildcardPath, "createRegExpFromWildcardPath");
var createRegExpFromWildcardPath_default = createRegExpFromWildcardPath;
var HTTP_METHOD_OPTIONS = HTTP_METHODS.join("|");
var MODIFIER_GROUP = "(?<modifier>!?)";
var METHOD_FILTER_GROUP = `(?<method>(?:\\*|(?:${HTTP_METHOD_OPTIONS})(?:,\\s*(?:${HTTP_METHOD_OPTIONS}))*))`;
var PATH_FILTER_GROUP = "(?<path>.+)";
var FILTER_REGEX = new RegExp(`^${MODIFIER_GROUP}\\s*${METHOD_FILTER_GROUP}\\s+${PATH_FILTER_GROUP}$`, "i");
function parseRawFilter(rawFilter) {
const filterMatch = rawFilter.match(FILTER_REGEX);
const { modifier: filterModifier, method: filteredMethodsOrWildcard, path: filteredPath } = filterMatch?.groups ?? {};
const isValidFilter = !filteredMethodsOrWildcard || !filteredPath;
if (isValidFilter) {
logger.warn(`Warning: Filter could not be parsed and was ignored: ${color.yellow(rawFilter)}`);
return void 0;
}
const methodFilterGroup = `(?:${filteredMethodsOrWildcard.toUpperCase().replace(/,/g, "|").replace(/\*/g, ".*")}) `;
const isNegativeMatch = filterModifier === "!";
return {
expression: createRegExpFromWildcardPath_default(filteredPath, { prefix: methodFilterGroup }),
isNegativeMatch
};
}
__name(parseRawFilter, "parseRawFilter");
function groupParsedFiltersByMatch(parsedFilters) {
return parsedFilters.reduce(
(groupedFilters, filter) => {
if (filter) {
if (filter.isNegativeMatch) {
groupedFilters.negative.push(filter.expression);
} else {
groupedFilters.positive.push(filter.expression);
}
}
return groupedFilters;
},
{ positive: [], negative: [] }
);
}
__name(groupParsedFiltersByMatch, "groupParsedFiltersByMatch");
async function readPathFiltersFromFile(filePath) {
const fileContent = await filesystem.readFile(path.resolve(filePath), "utf-8");
const fileContentWithoutComments = fileContent.replace(/#.*$/gm, "");
const filters = fileContentWithoutComments.split("\n");
return filters;
}
__name(readPathFiltersFromFile, "readPathFiltersFromFile");
function ignoreEmptyFilters(filters) {
return filters.map((line) => line.trim()).filter(isNonEmpty_default);
}
__name(ignoreEmptyFilters, "ignoreEmptyFilters");
// src/typegen/openapi/transform/context.ts
function createTypeTransformationContext(serviceName, rawFilters) {
const parsedFilters = rawFilters.map(parseRawFilter);
return {
serviceName: convertToPascalCase(serviceName),
filters: {
paths: groupParsedFiltersByMatch(parsedFilters)
},
typeImports: {
http: /* @__PURE__ */ new Set()
},
referencedTypes: {
operations: /* @__PURE__ */ new Set(),
components: /* @__PURE__ */ new Set()
},
pendingActions: {
components: {
requests: { toMarkBodyAsOptional: /* @__PURE__ */ new Set() }
}
}
};
}
__name(createTypeTransformationContext, "createTypeTransformationContext");
// src/typegen/openapi/transform/imports.ts
var TYPEGEN_HTTP_IMPORT_MODULE = "@zimic/http";
function createImportDeclarations(context) {
const httpTypeImports = Array.from(context.typeImports.http).sort().map(createImportSpecifier);
const httpImportDeclaration = createImportDeclaration(httpTypeImports, TYPEGEN_HTTP_IMPORT_MODULE, {
typeOnly: true
});
return [httpImportDeclaration];
}
__name(createImportDeclarations, "createImportDeclarations");
// ../zimic-utils/dist/import/createCachedDynamicImport.mjs
function createCachedDynamicImport(importModuleDynamically) {
let cachedImportResult;
return /* @__PURE__ */ __name2(/* @__PURE__ */ __name(async function importModuleDynamicallyWithCache() {
cachedImportResult ??= await importModuleDynamically();
return cachedImportResult;
}, "importModuleDynamicallyWithCache"), "importModuleDynamicallyWithCache");
}
__name(createCachedDynamicImport, "createCachedDynamicImport");
__name2(createCachedDynamicImport, "createCachedDynamicImport");
var createCachedDynamicImport_default = createCachedDynamicImport;
var importOpenapiTypeScript = createCachedDynamic