UNPKG

otqs

Version:
1,440 lines (1,416 loc) 47.9 kB
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 __export = (target, all) => { for (var name in all) __defProp(target, name, { get: all[name], enumerable: true }); }; 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 )); var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod); // src/index.ts var src_exports = {}; __export(src_exports, { Options: () => import_core12.Options, default: () => src_default, defineConfig: () => defineConfig, generate: () => generate }); module.exports = __toCommonJS(src_exports); var import_core12 = require("@otqs/core"); 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 function defineConfig(options) { return options; } 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/index.ts var generate = async (optionsExport, workspace = process.cwd(), options) => { if (!optionsExport || (0, import_core12.isString)(optionsExport)) { return generateConfig(optionsExport, options); } const normalizedOptions = await normalizeOptions( optionsExport, workspace, options ); if (options == null ? void 0 : options.watch) { startWatcher( options == null ? void 0 : options.watch, async () => { try { await generateSpec(workspace, normalizedOptions); } catch (e) { (0, import_core12.log)( import_chalk7.default.red( `\u{1F6D1} ${(options == null ? void 0 : options.projectName) ? `${options == null ? void 0 : options.projectName} - ` : ""}${e}` ) ); } }, normalizedOptions.input.target ); } else { try { return await generateSpec(workspace, normalizedOptions); } catch (e) { (0, import_core12.log)( import_chalk7.default.red( `\u{1F6D1} ${(options == null ? void 0 : options.projectName) ? `${options == null ? void 0 : options.projectName} - ` : ""}${e}` ) ); } } }; var src_default = generate; // Annotate the CommonJS export names for ESM import in node: 0 && (module.exports = { Options, defineConfig, generate });