otqs
Version:
A swagger client generator for typescript
1,450 lines (1,426 loc) • 48.7 kB
JavaScript
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __copyProps = (to, from, except, desc) => {
if (from && typeof from === "object" || typeof from === "function") {
for (let key of __getOwnPropNames(from))
if (!__hasOwnProp.call(to, key) && key !== except)
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
}
return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
// If the importer is in node compatibility mode or this is not an ESM
// file that has been converted to a CommonJS file using a Babel-
// compatible transform (i.e. "__esModule" has not been set), then set
// "default" to the CommonJS "module.exports" for node compatibility.
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
mod
));
// src/bin/otqs.ts
var import_core12 = require("@otqs/core");
var import_cac = require("cac");
var import_chalk7 = __toESM(require("chalk"));
// src/generate.ts
var import_core11 = require("@otqs/core");
var import_chalk6 = __toESM(require("chalk"));
// src/import-specs.ts
var import_swagger_parser = __toESM(require("@apidevtools/swagger-parser"));
var import_core4 = require("@otqs/core");
var import_chalk = __toESM(require("chalk"));
var import_js_yaml = __toESM(require("js-yaml"));
var import_fs_extra = __toESM(require("fs-extra"));
// src/import-open-api.ts
var import_core3 = require("@otqs/core");
var import_lodash = __toESM(require("lodash.omit"));
// src/api.ts
var import_core2 = require("@otqs/core");
var import_msw2 = require("@otqs/msw");
// src/client.ts
var import_axios = __toESM(require("@otqs/axios"));
var import_core = require("@otqs/core");
var import_msw = require("@otqs/msw");
var import_query = __toESM(require("@otqs/query"));
var DEFAULT_CLIENT = import_core.OutputClient.AXIOS;
var GENERATOR_CLIENT = {
axios: (0, import_axios.default)({ type: "axios" })(),
"axios-functions": (0, import_axios.default)({ type: "axios-functions" })(),
"solid-query": (0, import_query.default)({ type: "solid-query" })()
};
var getGeneratorClient = (outputClient) => {
const generator = (0, import_core.isFunction)(outputClient) ? outputClient(GENERATOR_CLIENT) : GENERATOR_CLIENT[outputClient];
if (!generator) {
throw `Oups... \u{1F37B}. Client not found: ${outputClient}`;
}
return generator;
};
var generateClientImports = ({
client = DEFAULT_CLIENT,
implementation,
imports,
specsName,
hasSchemaDir,
isAllowSyntheticDefaultImports,
hasGlobalMutator,
hasParamsSerializerOptions,
packageJson
}) => {
const { dependencies } = getGeneratorClient(client);
return (0, import_core.generateDependencyImports)(
implementation,
dependencies ? [
...dependencies(
hasGlobalMutator,
hasParamsSerializerOptions,
packageJson
),
...imports
] : imports,
specsName,
hasSchemaDir,
isAllowSyntheticDefaultImports
);
};
var generateClientHeader = ({
outputClient = DEFAULT_CLIENT,
isRequestOptions,
isGlobalMutator,
isMutator,
provideIn,
hasAwaitedType,
titles
}) => {
const { header } = getGeneratorClient(outputClient);
return {
implementation: header ? header({
title: titles.implementation,
isRequestOptions,
isGlobalMutator,
isMutator,
provideIn,
hasAwaitedType
}) : "",
implementationMSW: `export const ${titles.implementationMSW} = () => [
`
};
};
var generateClientFooter = ({
outputClient = DEFAULT_CLIENT,
operationNames,
hasMutator,
hasAwaitedType,
titles
}) => {
const { footer } = getGeneratorClient(outputClient);
if (!footer) {
return {
implementation: "",
implementationMSW: `]
`
};
}
let implementation;
try {
if ((0, import_core.isFunction)(outputClient)) {
implementation = footer(
operationNames
);
console.warn(
"[WARN] Passing an array of strings for operations names to the footer function is deprecated and will be removed in a future major release. Please pass them in an object instead: { operationNames: string[] }."
);
} else {
implementation = footer({
operationNames,
title: titles.implementation,
hasMutator,
hasAwaitedType
});
}
} catch (e) {
implementation = footer({
operationNames,
title: titles.implementation,
hasMutator,
hasAwaitedType
});
}
return {
implementation,
implementationMSW: `]
`
};
};
var generateClientTitle = ({
outputClient = DEFAULT_CLIENT,
title,
customTitleFunc
}) => {
const { title: generatorTitle } = getGeneratorClient(outputClient);
if (!generatorTitle) {
return {
implementation: "",
implementationMSW: `get${(0, import_core.pascal)(title)}MSW`
};
}
if (customTitleFunc) {
const customTitle = customTitleFunc(title);
return {
implementation: generatorTitle(customTitle),
implementationMSW: `get${(0, import_core.pascal)(customTitle)}MSW`
};
}
return {
implementation: generatorTitle(title),
implementationMSW: `get${(0, import_core.pascal)(title)}MSW`
};
};
var generateMock = (verbOption, options) => {
if (!options.mock) {
return {
implementation: {
function: "",
handler: ""
},
imports: []
};
}
if ((0, import_core.isFunction)(options.mock)) {
return options.mock(verbOption, options);
}
return (0, import_msw.generateMSW)(verbOption, options);
};
var generateOperations = (outputClient = DEFAULT_CLIENT, verbsOptions, options) => {
return (0, import_core.asyncReduce)(
verbsOptions,
async (acc, verbOption) => {
const { client: generatorClient } = getGeneratorClient(outputClient);
const client = await generatorClient(verbOption, options, outputClient);
const msw = generateMock(verbOption, options);
if (!client.implementation) {
return acc;
}
acc[verbOption.operationId] = {
implementation: verbOption.doc + client.implementation,
imports: client.imports,
implementationMSW: msw.implementation,
importsMSW: msw.imports,
tags: verbOption.tags,
mutator: verbOption.mutator,
clientMutators: client.mutators,
formData: verbOption.formData,
formUrlEncoded: verbOption.formUrlEncoded,
paramsSerializer: verbOption.paramsSerializer,
operationName: verbOption.operationName
};
return acc;
},
{}
);
};
// src/api.ts
var getApiBuilder = async ({
input,
output,
context
}) => {
var _a;
const api = await (0, import_core2.asyncReduce)(
Object.entries((_a = context.specs[context.specKey].paths) != null ? _a : {}),
async (acc, [pathRoute, verbs]) => {
const route = (0, import_core2.getRoute)(pathRoute);
let resolvedVerbs = verbs;
let resolvedContext = context;
if ((0, import_core2.isReference)(verbs)) {
const { schema, imports } = (0, import_core2.resolveRef)(verbs, context);
resolvedVerbs = schema;
resolvedContext = {
...context,
...imports.length ? {
specKey: imports[0].specKey
} : {}
};
}
let verbsOptions = await (0, import_core2.generateVerbsOptions)({
verbs: resolvedVerbs,
input,
output,
route,
context: resolvedContext
});
if (output.override.useDeprecatedOperations === false) {
verbsOptions = verbsOptions.filter((verb) => {
return !verb.deprecated;
});
}
const schemas = verbsOptions.reduce(
(acc2, { queryParams, headers, body, response, props }) => {
if (props) {
acc2.push(
...props.flatMap(
(param) => param.type === import_core2.GetterPropType.NAMED_PATH_PARAMS ? param.schema : []
)
);
}
if (queryParams) {
acc2.push(queryParams.schema, ...queryParams.deps);
}
if (headers) {
acc2.push(headers.schema, ...headers.deps);
}
acc2.push(...body.schemas);
acc2.push(...response.schemas);
return acc2;
},
[]
);
let fullRoute = route;
if (output.baseUrl) {
if (output.baseUrl.endsWith("/") && route.startsWith("/")) {
fullRoute = route.slice(1);
}
fullRoute = `${output.baseUrl}${fullRoute}`;
}
const pathOperations = await generateOperations(
output.client,
verbsOptions,
{
route: fullRoute,
pathRoute,
override: output.override,
context: resolvedContext,
mock: !!output.mock,
output: output.target
}
);
acc.schemas.push(...schemas);
acc.operations = { ...acc.operations, ...pathOperations };
return acc;
},
{
operations: {},
schemas: []
}
);
return {
operations: api.operations,
schemas: api.schemas,
title: generateClientTitle,
header: generateClientHeader,
footer: generateClientFooter,
imports: generateClientImports,
importsMock: import_msw2.generateMSWImports
};
};
// src/import-open-api.ts
var importOpenApi = async ({
data,
input,
output,
target,
workspace
}) => {
var _a;
const specs = await generateInputSpecs({ specs: data, input, workspace });
const schemas = getApiSchemas({ output, target, workspace, specs });
const api = await getApiBuilder({
input,
output,
context: {
specKey: target,
target,
workspace,
specs,
override: output.override,
tslint: output.tslint,
tsconfig: output.tsconfig,
packageJson: output.packageJson
}
});
return {
...api,
schemas: {
...schemas,
[target]: [...(_a = schemas[target]) != null ? _a : [], ...api.schemas]
},
target,
info: specs[target].info
};
};
var generateInputSpecs = async ({
specs,
input,
workspace
}) => {
var _a;
const transformerFn = ((_a = input.override) == null ? void 0 : _a.transformer) ? await (0, import_core3.dynamicImport)(input.override.transformer, workspace) : void 0;
return (0, import_core3.asyncReduce)(
Object.entries(specs),
async (acc, [specKey, value]) => {
const schema = await (0, import_core3.openApiConverter)(
value,
input.converterOptions,
specKey
);
const transfomedSchema = transformerFn ? transformerFn(schema) : schema;
if (input.validation) {
await (0, import_core3.ibmOpenapiValidator)(transfomedSchema);
}
acc[specKey] = transfomedSchema;
return acc;
},
{}
);
};
var getApiSchemas = ({
output,
target,
workspace,
specs
}) => {
return Object.entries(specs).reduce((acc, [specKey, spec]) => {
var _a, _b, _c, _d;
const context = {
specKey,
target,
workspace,
specs,
override: output.override,
tslint: output.tslint,
tsconfig: output.tsconfig,
packageJson: output.packageJson
};
const schemaDefinition = (0, import_core3.generateSchemasDefinition)(
!spec.openapi ? getAllSchemas(spec, specKey) : (_a = spec.components) == null ? void 0 : _a.schemas,
context,
output.override.components.schemas.suffix
);
const responseDefinition = (0, import_core3.generateComponentDefinition)(
(_b = spec.components) == null ? void 0 : _b.responses,
context,
output.override.components.responses.suffix
);
const bodyDefinition = (0, import_core3.generateComponentDefinition)(
(_c = spec.components) == null ? void 0 : _c.requestBodies,
context,
output.override.components.requestBodies.suffix
);
const parameters = (0, import_core3.generateParameterDefinition)(
(_d = spec.components) == null ? void 0 : _d.parameters,
context,
output.override.components.parameters.suffix
);
const schemas = [
...schemaDefinition,
...responseDefinition,
...bodyDefinition,
...parameters
];
if (!schemas.length) {
return acc;
}
acc[specKey] = schemas;
return acc;
}, {});
};
var getAllSchemas = (spec, specKey) => {
var _a;
const cleanedSpec = (0, import_lodash.default)(spec, [
"openapi",
"info",
"servers",
"paths",
"components",
"security",
"tags",
"externalDocs"
]);
if (specKey && (0, import_core3.isSchema)(cleanedSpec)) {
const name = import_core3.upath.getSchemaFileName(specKey);
return {
[name]: cleanedSpec,
...getAllSchemas(
(0, import_lodash.default)(cleanedSpec, [
"type",
"properties",
"allOf",
"oneOf",
"anyOf",
"items"
])
)
};
}
const schemas = Object.entries(cleanedSpec).reduce(
(acc, [key, value]) => {
if (!(0, import_core3.isObject)(value)) {
return acc;
}
if (!(0, import_core3.isSchema)(value) && !(0, import_core3.isReference)(value)) {
return { ...acc, ...getAllSchemas(value) };
}
acc[key] = value;
return acc;
},
{}
);
return {
...schemas,
...(_a = spec == null ? void 0 : spec.components) == null ? void 0 : _a.schemas
};
};
// src/import-specs.ts
var resolveSpecs = async (path, { validate, ...options }, isUrl3, isOnlySchema) => {
try {
if (validate) {
try {
await import_swagger_parser.default.validate(path, options);
} catch (e) {
if ((e == null ? void 0 : e.name) === "ParserError") {
throw e;
}
if (!isOnlySchema) {
(0, import_core4.log)(`\u26A0\uFE0F ${import_chalk.default.yellow(e)}`);
}
}
}
const data = (await import_swagger_parser.default.resolve(path, options)).values();
if (isUrl3) {
return data;
}
return Object.fromEntries(
Object.entries(data).map(([key, value]) => [import_core4.upath.resolve(key), value])
);
} catch {
const file = await import_fs_extra.default.readFile(path, "utf8");
return {
[path]: import_js_yaml.default.load(file)
};
}
};
var importSpecs = async (workspace, options) => {
const { input, output } = options;
if ((0, import_core4.isObject)(input.target)) {
return importOpenApi({
data: { [workspace]: input.target },
input,
output,
target: workspace,
workspace
});
}
const isPathUrl = (0, import_core4.isUrl)(input.target);
const data = await resolveSpecs(
input.target,
input.parserOptions,
isPathUrl,
!output.target
);
return importOpenApi({
data,
input,
output,
target: input.target,
workspace
});
};
// src/utils/options.ts
var import_core7 = require("@otqs/core");
var import_chalk2 = __toESM(require("chalk"));
// package.json
var package_default = {
name: "otqs",
description: "A swagger client generator for typescript",
version: "1.1.1",
license: "MIT",
files: [
"dist"
],
bin: "dist/bin/otqs.js",
type: "commonjs",
main: "dist/index.js",
keywords: [
"rest",
"client",
"swagger",
"open-api",
"fetch",
"data fetching",
"code-generation",
"msw",
"mock",
"axios",
"solidjs",
"solid",
"solid-query",
"tanstack"
],
author: {
name: "Andrej Nemec"
},
repository: {
type: "git",
url: "https://github.com/AndrejNemec/openapi-tanstack-query-solid"
},
scripts: {
build: "tsup ./src/bin/otqs.ts ./src/index.ts --target node12 --clean --dts",
dev: "tsup ./src/bin/otqs.ts ./src/index.ts --target node12 --clean --watch ./src --onSuccess 'yarn generate-api'",
lint: "eslint src/**/*.ts",
"generate-api": "node ./dist/bin/otqs.js --config ../../samples/solid-query/basic/otqs.config.ts"
},
devDependencies: {
"@types/inquirer": "^9.0.6",
"@types/js-yaml": "^4.0.8",
"@types/lodash.uniq": "^4.5.8"
},
dependencies: {
"@apidevtools/swagger-parser": "^10.1.0",
"@otqs/axios": "workspace:*",
"@otqs/core": "workspace:*",
"@otqs/msw": "workspace:*",
"@otqs/query": "workspace:*",
ajv: "^8.12.0",
cac: "^6.7.14",
chalk: "^4.1.2",
chokidar: "^3.5.3",
enquirer: "^2.4.1",
execa: "^5.1.1",
"find-up": "5.0.0",
"fs-extra": "^10.1.0",
"js-yaml": "^4.1.0",
"lodash.omit": "^4.5.0",
"lodash.uniq": "^4.5.0",
"openapi-types": "^12.1.3",
"openapi3-ts": "^3.2.0",
"string-argv": "^0.3.2",
tsconfck: "^2.0.1"
}
};
// src/utils/github.ts
var import_core5 = require("@otqs/core");
var import_enquirer = require("enquirer");
var import_fs_extra2 = __toESM(require("fs-extra"));
// src/utils/request.ts
var import_https = __toESM(require("https"));
var request = (urlOptions, data) => {
return new Promise((resolve, reject) => {
const req = import_https.default.request(urlOptions, (res) => {
let body = "";
res.on("data", (chunk) => body += chunk.toString());
res.on("error", reject);
res.on("end", () => {
const response = {
status: res.statusCode,
headers: res.headers,
body: JSON.parse(body)
};
if (res.statusCode && res.statusCode >= 200 && res.statusCode <= 299) {
resolve(response);
} else {
reject(response);
}
});
});
req.on("error", reject);
if (data) {
req.write(data, "binary");
}
req.end();
});
};
// src/utils/github.ts
var getGithubSpecReq = ({
accessToken,
repo,
owner,
branch,
path
}) => {
const payload = JSON.stringify({
query: `query {
repository(name: "${repo}", owner: "${owner}") {
object(expression: "${branch}:${path}") {
... on Blob {
text
}
}
}
}`
});
return [
{
method: "POST",
hostname: "api.github.com",
path: "/graphql",
headers: {
"content-type": "application/json",
"user-agent": "orval-importer",
authorization: `bearer ${accessToken}`,
"Content-Length": payload.length
}
},
payload
];
};
var githubToken = null;
var getGithubAcessToken = async (githubTokenPath) => {
if (githubToken) {
return githubToken;
}
if (await import_fs_extra2.default.pathExists(githubTokenPath)) {
return import_fs_extra2.default.readFile(githubTokenPath, "utf-8");
} else {
const answers = await (0, import_enquirer.prompt)([
{
type: "input",
name: "githubToken",
message: "Please provide a GitHub token with `repo` rules checked (https://help.github.com/articles/creating-a-personal-access-token-for-the-command-line/)"
},
{
type: "confirm",
name: "saveToken",
message: "Would you like to store your token for the next time? (stored in your node_modules)"
}
]);
githubToken = answers.githubToken;
if (answers.saveToken) {
await import_fs_extra2.default.outputFile(githubTokenPath, answers.githubToken);
}
return answers.githubToken;
}
};
var getGithubOpenApi = async (url) => {
var _a, _b, _c, _d;
const githubTokenPath = import_core5.upath.join(__dirname, ".githubToken");
const accessToken = await getGithubAcessToken(githubTokenPath);
const [info] = url.split("github.com/").slice(-1);
const [owner, repo, , branch, ...paths] = info.split("/");
const path = paths.join("/");
try {
const { body } = await request(...getGithubSpecReq({ accessToken, repo, owner, branch, path }));
if ((_a = body.errors) == null ? void 0 : _a.length) {
const isErrorRemoveLink = (_b = body.errors) == null ? void 0 : _b.some(
(error) => (error == null ? void 0 : error.type) === "NOT_FOUND"
);
if (isErrorRemoveLink) {
const answers = await (0, import_enquirer.prompt)([
{
type: "confirm",
name: "removeToken",
message: "Your token doesn't have the correct permissions, should we remove it?"
}
]);
if (answers.removeToken) {
await import_fs_extra2.default.unlink(githubTokenPath);
}
}
}
return (_d = (_c = body.data) == null ? void 0 : _c.repository) == null ? void 0 : _d.object.text;
} catch (e) {
if (!e.body) {
throw `Oups... \u{1F37B}. ${e}`;
}
if (e.body.message === "Bad credentials") {
const answers = await (0, import_enquirer.prompt)([
{
type: "confirm",
name: "removeToken",
message: "Your token doesn't have the correct permissions, should we remove it?"
}
]);
if (answers.removeToken) {
await import_fs_extra2.default.unlink(githubTokenPath);
}
}
throw e.body.message || `Oups... \u{1F37B}. ${e}`;
}
};
var githubResolver = {
order: 199,
canRead(file) {
return file.url.includes("github.com");
},
read(file) {
return getGithubOpenApi(file.url);
}
};
// src/utils/package-json.ts
var import_find_up = __toESM(require("find-up"));
var import_fs_extra3 = __toESM(require("fs-extra"));
var loadPackageJson = async (packageJson, workspace = process.cwd()) => {
if (!packageJson) {
const pkgPath = await (0, import_find_up.default)(["package.json"], {
cwd: workspace
});
if (pkgPath) {
const pkg = await Promise.resolve().then(() => __toESM(require(pkgPath)));
return pkg;
}
return;
}
const normalizedPath = normalizePath(packageJson, workspace);
if (import_fs_extra3.default.existsSync(normalizedPath)) {
const pkg = await Promise.resolve().then(() => __toESM(require(normalizedPath)));
return pkg;
}
return;
};
// src/utils/tsconfig.ts
var import_core6 = require("@otqs/core");
var import_find_up2 = __toESM(require("find-up"));
var import_fs_extra4 = __toESM(require("fs-extra"));
var import_tsconfck = require("tsconfck");
var loadTsconfig = async (tsconfig, workspace = process.cwd()) => {
var _a, _b;
if ((0, import_core6.isUndefined)(tsconfig)) {
const configPath = await (0, import_find_up2.default)(["tsconfig.json", "jsconfig.json"], {
cwd: workspace
});
if (configPath) {
const config = await (0, import_tsconfck.parse)(configPath);
return config.tsconfig;
}
return;
}
if ((0, import_core6.isString)(tsconfig)) {
const normalizedPath = normalizePath(tsconfig, workspace);
if (import_fs_extra4.default.existsSync(normalizedPath)) {
const config = await (0, import_tsconfck.parse)(normalizedPath);
const tsconfig2 = ((_b = (_a = config.referenced) == null ? void 0 : _a.find(
({ tsconfigFile }) => tsconfigFile === normalizedPath
)) == null ? void 0 : _b.tsconfig) || config.tsconfig;
return tsconfig2;
}
return;
}
if ((0, import_core6.isObject)(tsconfig)) {
return tsconfig;
}
return;
};
// src/utils/options.ts
var normalizeOptions = async (optionsExport, workspace = process.cwd(), globalOptions = {}) => {
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j, _k, _l, _m, _n, _o, _p, _q, _r, _s, _t, _u, _v, _w, _x, _y, _z, _A, _B, _C, _D, _E, _F, _G, _H, _I, _J, _K, _L, _M, _N, _O, _P, _Q, _R, _S, _T, _U, _V, _W, _X, _Y, _Z, __, _$, _aa, _ba, _ca, _da, _ea, _fa, _ga, _ha, _ia, _ja, _ka, _la;
const options = await ((0, import_core7.isFunction)(optionsExport) ? optionsExport() : optionsExport);
if (!options.input) {
(0, import_core7.createLogger)().error(import_chalk2.default.red(`Config require an input`));
process.exit(1);
}
if (!options.output) {
(0, import_core7.createLogger)().error(import_chalk2.default.red(`Config require an output`));
process.exit(1);
}
const inputOptions = (0, import_core7.isString)(options.input) ? { target: options.input } : options.input;
const outputOptions = (0, import_core7.isString)(options.output) ? { target: options.output } : options.output;
const outputWorkspace = normalizePath(
outputOptions.workspace || "",
workspace
);
const { clean, prettier, client, mode, mock, tslint } = globalOptions;
const tsconfig = await loadTsconfig(
outputOptions.tsconfig || globalOptions.tsconfig,
workspace
);
const packageJson = await loadPackageJson(
outputOptions.packageJson || globalOptions.packageJson,
workspace
);
const normalizedOptions = {
input: {
target: globalOptions.input ? normalizePathOrUrl(globalOptions.input, process.cwd()) : normalizePathOrUrl(inputOptions.target, workspace),
validation: inputOptions.validation || false,
override: {
transformer: normalizePath(
(_a = inputOptions.override) == null ? void 0 : _a.transformer,
workspace
)
},
converterOptions: (_b = inputOptions.converterOptions) != null ? _b : {},
parserOptions: (0, import_core7.mergeDeep)(
parserDefaultOptions,
(_c = inputOptions.parserOptions) != null ? _c : {}
),
filters: inputOptions.filters
},
output: {
target: globalOptions.output ? normalizePath(globalOptions.output, process.cwd()) : normalizePath(outputOptions.target, outputWorkspace),
schemas: normalizePath(outputOptions.schemas, outputWorkspace),
workspace: outputOptions.workspace ? outputWorkspace : void 0,
client: (_e = (_d = outputOptions.client) != null ? _d : client) != null ? _e : import_core7.OutputClient.AXIOS_FUNCTIONS,
mode: normalizeOutputMode((_f = outputOptions.mode) != null ? _f : mode),
mock: (_h = (_g = outputOptions.mock) != null ? _g : mock) != null ? _h : false,
clean: (_j = (_i = outputOptions.clean) != null ? _i : clean) != null ? _j : false,
prettier: (_l = (_k = outputOptions.prettier) != null ? _k : prettier) != null ? _l : false,
tslint: (_n = (_m = outputOptions.tslint) != null ? _m : tslint) != null ? _n : false,
tsconfig,
packageJson,
headers: (_o = outputOptions.headers) != null ? _o : false,
indexFiles: (_p = outputOptions.indexFiles) != null ? _p : true,
baseUrl: outputOptions.baseUrl,
override: {
...outputOptions.override,
mock: {
arrayMin: (_s = (_r = (_q = outputOptions.override) == null ? void 0 : _q.mock) == null ? void 0 : _r.arrayMin) != null ? _s : 1,
arrayMax: (_v = (_u = (_t = outputOptions.override) == null ? void 0 : _t.mock) == null ? void 0 : _u.arrayMax) != null ? _v : 10,
...(_x = (_w = outputOptions.override) == null ? void 0 : _w.mock) != null ? _x : {}
},
operations: normalizeOperationsAndTags(
(_z = (_y = outputOptions.override) == null ? void 0 : _y.operations) != null ? _z : {},
outputWorkspace
),
tags: normalizeOperationsAndTags(
(_B = (_A = outputOptions.override) == null ? void 0 : _A.tags) != null ? _B : {},
outputWorkspace
),
mutator: normalizeMutator(
outputWorkspace,
(_C = outputOptions.override) == null ? void 0 : _C.mutator
),
formData: (_G = !(0, import_core7.isBoolean)((_D = outputOptions.override) == null ? void 0 : _D.formData) ? normalizeMutator(
outputWorkspace,
(_E = outputOptions.override) == null ? void 0 : _E.formData
) : (_F = outputOptions.override) == null ? void 0 : _F.formData) != null ? _G : true,
formUrlEncoded: (_K = !(0, import_core7.isBoolean)((_H = outputOptions.override) == null ? void 0 : _H.formUrlEncoded) ? normalizeMutator(
outputWorkspace,
(_I = outputOptions.override) == null ? void 0 : _I.formUrlEncoded
) : (_J = outputOptions.override) == null ? void 0 : _J.formUrlEncoded) != null ? _K : true,
paramsSerializer: normalizeMutator(
outputWorkspace,
(_L = outputOptions.override) == null ? void 0 : _L.paramsSerializer
),
header: ((_M = outputOptions.override) == null ? void 0 : _M.header) === false ? false : (0, import_core7.isFunction)((_N = outputOptions.override) == null ? void 0 : _N.header) ? (_O = outputOptions.override) == null ? void 0 : _O.header : getDefaultFilesHeader,
requestOptions: (_Q = (_P = outputOptions.override) == null ? void 0 : _P.requestOptions) != null ? _Q : true,
components: {
schemas: {
suffix: import_core7.RefComponentSuffix.schemas,
...(_T = (_S = (_R = outputOptions.override) == null ? void 0 : _R.components) == null ? void 0 : _S.schemas) != null ? _T : {}
},
responses: {
suffix: import_core7.RefComponentSuffix.responses,
...(_W = (_V = (_U = outputOptions.override) == null ? void 0 : _U.components) == null ? void 0 : _V.responses) != null ? _W : {}
},
parameters: {
suffix: import_core7.RefComponentSuffix.parameters,
...(_Z = (_Y = (_X = outputOptions.override) == null ? void 0 : _X.components) == null ? void 0 : _Y.parameters) != null ? _Z : {}
},
requestBodies: {
suffix: import_core7.RefComponentSuffix.requestBodies,
...(_aa = (_$ = (__ = outputOptions.override) == null ? void 0 : __.components) == null ? void 0 : _$.requestBodies) != null ? _aa : {}
}
},
query: {
useQuery: true,
useMutation: true,
signal: true,
...normalizeQueryOptions((_ba = outputOptions.override) == null ? void 0 : _ba.query, workspace)
},
swr: {
...(_da = (_ca = outputOptions.override) == null ? void 0 : _ca.swr) != null ? _da : {}
},
angular: {
provideIn: (_ga = (_fa = (_ea = outputOptions.override) == null ? void 0 : _ea.angular) == null ? void 0 : _fa.provideIn) != null ? _ga : "root"
},
useDates: ((_ha = outputOptions.override) == null ? void 0 : _ha.useDates) || false,
useDeprecatedOperations: (_ja = (_ia = outputOptions.override) == null ? void 0 : _ia.useDeprecatedOperations) != null ? _ja : true,
useNativeEnums: (_la = (_ka = outputOptions.override) == null ? void 0 : _ka.useNativeEnums) != null ? _la : false
}
},
hooks: options.hooks ? normalizeHooks(options.hooks) : {}
};
if (!normalizedOptions.input.target) {
(0, import_core7.createLogger)().error(import_chalk2.default.red(`Config require an input target`));
process.exit(1);
}
if (!normalizedOptions.output.target && !normalizedOptions.output.schemas) {
(0, import_core7.createLogger)().error(
import_chalk2.default.red(`Config require an output target or schemas`)
);
process.exit(1);
}
return normalizedOptions;
};
var parserDefaultOptions = {
validate: true,
resolve: { github: githubResolver }
};
var normalizeMutator = (workspace, mutator) => {
var _a;
if ((0, import_core7.isObject)(mutator)) {
if (!mutator.path) {
(0, import_core7.createLogger)().error(import_chalk2.default.red(`Mutator need a path`));
process.exit(1);
}
return {
...mutator,
path: import_core7.upath.resolve(workspace, mutator.path),
default: (_a = mutator.default || !mutator.name) != null ? _a : false
};
}
if ((0, import_core7.isString)(mutator)) {
return {
path: import_core7.upath.resolve(workspace, mutator),
default: true
};
}
return mutator;
};
var normalizePathOrUrl = (path, workspace) => {
if ((0, import_core7.isString)(path) && !(0, import_core7.isUrl)(path)) {
return normalizePath(path, workspace);
}
return path;
};
var normalizePath = (path, workspace) => {
if (!(0, import_core7.isString)(path)) {
return path;
}
return import_core7.upath.resolve(workspace, path);
};
var normalizeOperationsAndTags = (operationsOrTags, workspace) => {
return Object.fromEntries(
Object.entries(operationsOrTags).map(
([
key,
{
transformer,
mutator,
formData,
formUrlEncoded,
paramsSerializer,
query: query2,
...rest
}
]) => {
return [
key,
{
...rest,
...query2 ? {
query: normalizeQueryOptions(query2, workspace)
} : {},
...transformer ? { transformer: normalizePath(transformer, workspace) } : {},
...mutator ? { mutator: normalizeMutator(workspace, mutator) } : {},
...formData ? {
formData: !(0, import_core7.isBoolean)(formData) ? normalizeMutator(workspace, formData) : formData
} : {},
...formUrlEncoded ? {
formUrlEncoded: !(0, import_core7.isBoolean)(formUrlEncoded) ? normalizeMutator(workspace, formUrlEncoded) : formUrlEncoded
} : {},
...paramsSerializer ? {
paramsSerializer: normalizeMutator(
workspace,
paramsSerializer
)
} : {}
}
];
}
)
);
};
var normalizeOutputMode = (mode) => {
if (!mode) {
return import_core7.OutputMode.SINGLE;
}
if (!Object.values(import_core7.OutputMode).includes(mode)) {
(0, import_core7.createLogger)().warn(import_chalk2.default.yellow(`Unknown the provided mode => ${mode}`));
return import_core7.OutputMode.SINGLE;
}
return mode;
};
var normalizeHooks = (hooks) => {
const keys = Object.keys(hooks);
return keys.reduce((acc, key) => {
if ((0, import_core7.isString)(hooks[key])) {
return {
...acc,
[key]: [hooks[key]]
};
} else if (Array.isArray(hooks[key])) {
return {
...acc,
[key]: hooks[key]
};
} else if ((0, import_core7.isFunction)(hooks[key])) {
return {
...acc,
[key]: [hooks[key]]
};
}
return acc;
}, {});
};
var normalizeQueryOptions = (queryOptions = {}, outputWorkspace) => {
if (queryOptions.options) {
console.warn(
"[WARN] Using query options is deprecated and will be removed in a future major release. Please use queryOptions or mutationOptions instead."
);
}
return {
...!(0, import_core7.isUndefined)(queryOptions.usePrefetch) ? { usePrefetch: queryOptions.usePrefetch } : {},
...!(0, import_core7.isUndefined)(queryOptions.useQuery) ? { useQuery: queryOptions.useQuery } : {},
...!(0, import_core7.isUndefined)(queryOptions.useSuspenseQuery) ? { useSuspenseQuery: queryOptions.useSuspenseQuery } : {},
...!(0, import_core7.isUndefined)(queryOptions.useMutation) ? { useMutation: queryOptions.useMutation } : {},
...!(0, import_core7.isUndefined)(queryOptions.useInfinite) ? { useInfinite: queryOptions.useInfinite } : {},
...!(0, import_core7.isUndefined)(queryOptions.useSuspenseInfiniteQuery) ? { useSuspenseInfiniteQuery: queryOptions.useSuspenseInfiniteQuery } : {},
...queryOptions.useInfiniteQueryParam ? { useInfiniteQueryParam: queryOptions.useInfiniteQueryParam } : {},
...queryOptions.options ? { options: queryOptions.options } : {},
...(queryOptions == null ? void 0 : queryOptions.queryKey) ? {
queryKey: normalizeMutator(outputWorkspace, queryOptions == null ? void 0 : queryOptions.queryKey)
} : {},
...(queryOptions == null ? void 0 : queryOptions.queryOptions) ? {
queryOptions: normalizeMutator(
outputWorkspace,
queryOptions == null ? void 0 : queryOptions.queryOptions
)
} : {},
...(queryOptions == null ? void 0 : queryOptions.mutationOptions) ? {
mutationOptions: normalizeMutator(
outputWorkspace,
queryOptions == null ? void 0 : queryOptions.mutationOptions
)
} : {},
...!(0, import_core7.isUndefined)(queryOptions.signal) ? { signal: queryOptions.signal } : {},
...!(0, import_core7.isUndefined)(queryOptions.version) ? { version: queryOptions.version } : {}
};
};
var getDefaultFilesHeader = ({
title,
description,
version
}) => [
`Generated by ${package_default.name} v${package_default.version} \u{1F37A}`,
`Do not edit manually.`,
...title ? [title] : [],
...description ? [description] : [],
...version ? [`OpenAPI spec version: ${version}`] : []
];
// src/utils/watcher.ts
var import_core8 = require("@otqs/core");
var import_chalk3 = __toESM(require("chalk"));
var startWatcher = async (watchOptions, watchFn, defaultTarget = ".") => {
if (!watchOptions)
return;
const { watch } = await Promise.resolve().then(() => __toESM(require("chokidar")));
const ignored = ["**/{.git,node_modules}/**"];
const watchPaths = typeof watchOptions === "boolean" ? defaultTarget : Array.isArray(watchOptions) ? watchOptions.filter((path) => typeof path === "string") : watchOptions;
(0, import_core8.log)(
`Watching for changes in ${Array.isArray(watchPaths) ? watchPaths.map((v) => '"' + v + '"').join(" | ") : '"' + watchPaths + '"'}`
);
const watcher = watch(watchPaths, {
ignorePermissionErrors: true,
ignored
});
watcher.on("all", async (type, file) => {
(0, import_core8.log)(`Change detected: ${type} ${file}`);
try {
await watchFn();
} catch (e) {
(0, import_core8.log)(import_chalk3.default.red(e));
}
});
};
// src/write-specs.ts
var import_core10 = require("@otqs/core");
var import_chalk5 = __toESM(require("chalk"));
var import_execa2 = __toESM(require("execa"));
var import_fs_extra5 = __toESM(require("fs-extra"));
var import_lodash2 = __toESM(require("lodash.uniq"));
// src/utils/executeHook.ts
var import_core9 = require("@otqs/core");
var import_chalk4 = __toESM(require("chalk"));
var import_execa = __toESM(require("execa"));
var import_string_argv = require("string-argv");
var executeHook = async (name, commands = [], args = []) => {
(0, import_core9.log)(import_chalk4.default.white(`Running ${name} hook...`));
for (const command of commands) {
if ((0, import_core9.isString)(command)) {
const [cmd, ..._args] = [...(0, import_string_argv.parseArgsStringToArgv)(command), ...args];
try {
await (0, import_execa.default)(cmd, _args);
} catch (e) {
(0, import_core9.log)(import_chalk4.default.red(`\u{1F6D1} Failed to run ${name} hook: ${e}`));
}
} else if ((0, import_core9.isFunction)(command)) {
await command(args);
}
}
};
// src/write-specs.ts
var getHeader = (option, info) => {
if (!option) {
return "";
}
const header = option(info);
return Array.isArray(header) ? (0, import_core10.jsDoc)({ description: header }) : header;
};
var writeSpecs = async (builder, workspace, options, projectName) => {
const { info = { title: "", version: 0 }, schemas, target } = builder;
const { output } = options;
const projectTitle = projectName || info.title;
const specsName = Object.keys(schemas).reduce((acc, specKey) => {
const basePath = import_core10.upath.getSpecName(specKey, target);
const name = basePath.slice(1).split("/").join("-");
acc[specKey] = name;
return acc;
}, {});
const header = getHeader(output.override.header, info);
if (output.schemas) {
const rootSchemaPath = output.schemas;
await Promise.all(
Object.entries(schemas).map(([specKey, schemas2]) => {
const schemaPath = !(0, import_core10.isRootKey)(specKey, target) ? import_core10.upath.join(rootSchemaPath, specsName[specKey]) : rootSchemaPath;
return (0, import_core10.writeSchemas)({
schemaPath,
schemas: schemas2,
target,
specsName,
specKey,
isRootKey: (0, import_core10.isRootKey)(specKey, target),
header,
indexFiles: output.indexFiles
});
})
);
}
let implementationPaths = [];
if (output.target) {
const writeMode = getWriteMode(output.mode);
implementationPaths = await writeMode({
builder,
workspace,
output,
specsName,
header,
needSchema: !output.schemas && output.client !== "zod"
});
}
if (output.workspace) {
const workspacePath = output.workspace;
let imports = implementationPaths.filter((path) => !path.endsWith(".msw.ts")).map(
(path) => import_core10.upath.relativeSafe(
workspacePath,
(0, import_core10.getFileInfo)(path).pathWithoutExtension
)
);
if (output.schemas) {
imports.push(
import_core10.upath.relativeSafe(workspacePath, (0, import_core10.getFileInfo)(output.schemas).dirname)
);
}
if (output.indexFiles) {
const indexFile = import_core10.upath.join(workspacePath, "/index.ts");
if (await import_fs_extra5.default.pathExists(indexFile)) {
const data = await import_fs_extra5.default.readFile(indexFile, "utf8");
const importsNotDeclared = imports.filter((imp) => !data.includes(imp));
await import_fs_extra5.default.appendFile(
indexFile,
(0, import_lodash2.default)(importsNotDeclared).map((imp) => `export * from '${imp}';`).join("\n") + "\n"
);
} else {
await import_fs_extra5.default.outputFile(
indexFile,
(0, import_lodash2.default)(imports).map((imp) => `export * from '${imp}';`).join("\n") + "\n"
);
}
implementationPaths = [indexFile, ...implementationPaths];
}
}
const paths = [
...output.schemas ? [(0, import_core10.getFileInfo)(output.schemas).dirname] : [],
...implementationPaths
];
if (options.hooks.afterAllFilesWrite) {
await executeHook(
"afterAllFilesWrite",
options.hooks.afterAllFilesWrite,
paths
);
}
if (output.prettier) {
try {
await (0, import_execa2.default)("prettier", ["--write", ...paths]);
} catch (e) {
(0, import_core10.log)(
import_chalk5.default.yellow(
`\u26A0\uFE0F ${projectTitle ? `${projectTitle} - ` : ""}Prettier not found`
)
);
}
}
(0, import_core10.createSuccessMessage)(projectTitle);
};
var getWriteMode = (mode) => {
switch (mode) {
case import_core10.OutputMode.SPLIT:
return import_core10.writeSplitMode;
case import_core10.OutputMode.TAGS:
return import_core10.writeTagsMode;
case import_core10.OutputMode.TAGS_SPLIT:
return import_core10.writeSplitTagsMode;
case import_core10.OutputMode.SINGLE:
default:
return import_core10.writeSingleMode;
}
};
// src/generate.ts
var generateSpec = async (workspace, options, projectName) => {
if (options.output.clean) {
const extraPatterns = Array.isArray(options.output.clean) ? options.output.clean : [];
if (options.output.target) {
await (0, import_core11.removeFiles)(
["**/*", "!**/*.d.ts", ...extraPatterns],
(0, import_core11.getFileInfo)(options.output.target).dirname
);
}
if (options.output.schemas) {
await (0, import_core11.removeFiles)(
["**/*", "!**/*.d.ts", ...extraPatterns],
(0, import_core11.getFileInfo)(options.output.schemas).dirname
);
}
(0, import_core11.log)(`${projectName ? `${projectName}: ` : ""}Cleaning output folder`);
}
const writeSpecBuilder = await importSpecs(workspace, options);
await writeSpecs(writeSpecBuilder, workspace, options, projectName);
};
var generateSpecs = async (config, workspace, projectName) => {
if (projectName) {
const options = config[projectName];
if (options) {
try {
await generateSpec(workspace, options, projectName);
} catch (e) {
(0, import_core11.log)(import_chalk6.default.red(`\u{1F6D1} ${projectName ? `${projectName} - ` : ""}${e}`));
process.exit(1);
}
} else {
(0, import_core11.errorMessage)("Project not found");
process.exit(1);
}
return;
}
let hasErrors;
const accumulate = (0, import_core11.asyncReduce)(
Object.entries(config),
async (acc, [projectName2, options]) => {
try {
acc.push(await generateSpec(workspace, options, projectName2));
} catch (e) {
hasErrors = true;
(0, import_core11.log)(import_chalk6.default.red(`\u{1F6D1} ${projectName2 ? `${projectName2} - ` : ""}${e}`));
}
return acc;
},
[]
);
if (hasErrors)
process.exit(1);
return accumulate;
};
var generateConfig = async (configFile, options) => {
const {
path,
file: configExternal,
error
} = await (0, import_core11.loadFile)(configFile, {
defaultFileName: "otqs.config"
});
if (!configExternal) {
throw `failed to load from ${path} => ${error}`;
}
const workspace = import_core11.upath.dirname(path);
const config = await ((0, import_core11.isFunction)(configExternal) ? configExternal() : configExternal);
const normalizedConfig = await (0, import_core11.asyncReduce)(
Object.entries(config),
async (acc, [key, value]) => {
acc[key] = await normalizeOptions(value, workspace, options);
return acc;
},
{}
);
const fileToWatch = Object.entries(normalizedConfig).filter(
([project]) => (options == null ? void 0 : options.projectName) === void 0 || project === (options == null ? void 0 : options.projectName)
).map(([, { input }]) => input.target).filter((target) => (0, import_core11.isString)(target));
if ((options == null ? void 0 : options.watch) && fileToWatch.length) {
startWatcher(
options == null ? void 0 : options.watch,
() => generateSpecs(normalizedConfig, workspace, options == null ? void 0 : options.projectName),
fileToWatch
);
} else {
await generateSpecs(normalizedConfig, workspace, options == null ? void 0 : options.projectName);
}
};
// src/bin/otqs.ts
var cli = (0, import_cac.cac)("otqs");
(0, import_core12.startMessage)({
name: package_default.name,
version: package_default.version,
description: package_default.description
});
cli.version(package_default.version);
cli.command(
"[config]",
"generate client with appropriate type-signatures from OpenAPI specs",
{
ignoreOptionDefaultValue: true
}
).option("-o, --output <path>", "output file destination").option("-i, --input <path>", "input file (yaml or json openapi specs)").option("-c, --config <path>", "override flags by a config file").option("-p, --project <name>", "focus a project of the config").option("-m, --mode <name>", "default mode that will be used").option("-c, --client <name>", "default client that will be used").option("--mock", "activate the mock").option(
"-w, --watch [path]",
"Watch mode, if path is not specified, it watches the input target"
).option("--clean [path]", "Clean output directory").option("--prettier [path]", "Prettier generated files").option("--tslint [path]", "tslint generated files").option("--tsconfig [path]", "path to your tsconfig file").action(async (paths, cmd) => {
if (!cmd.config && (0, import_core12.isString)(cmd.input) && (0, import_core12.isString)(cmd.output)) {
const normalizedOptions = await normalizeOptions({
input: cmd.input,
output: {
target: cmd.output,
clean: cmd.clean,
prettier: cmd.prettier,
tslint: cmd.tslint,
mock: cmd.mock,
client: cmd.client,
mode: cmd.mode,
tsconfig: cmd.tsconfig
}
});
if (cmd.watch) {
startWatcher(
cmd.watch,
async () => {
try {
await generateSpec(process.cwd(), normalizedOptions);
} catch (e) {
(0, import_core12.log)(import_chalk7.default.red(`\u{1F6D1} ${e}`));
}
},
normalizedOptions.input.target
);
} else {
try {
await generateSpec(process.cwd(), normalizedOptions);
} catch (e) {
(0, import_core12.log)(import_chalk7.default.red(`\u{1F6D1} ${e}`));
}
}
} else {
await generateConfig(cmd.config, {
projectName: cmd.project,
watch: cmd.watch,
clean: cmd.clean,
prettier: cmd.prettier,
tslint: cmd.tslint,
mock: cmd.mock,
client: cmd.client,
mode: cmd.mode,
tsconfig: cmd.tsconfig,
input: cmd.input,
output: cmd.output
});
}
});
cli.help();
cli.parse(process.argv);