fork of hey-api/openapi-ts because I need some additional things
1import path from 'node:path';
2import { fileURLToPath } from 'node:url';
3
4import { Logger } from '@hey-api/codegen-core';
5import type { Context } from '@hey-api/shared';
6import {
7 checkNodeVersion,
8 ConfigValidationError,
9 getInputError,
10 getLogs,
11 JobError,
12 logCrashReport,
13 openGitHubIssueWithCrashReport,
14 printCliIntro,
15 printCrashReport,
16 shouldReportCrash,
17} from '@hey-api/shared';
18import type { LazyOrAsync, MaybeArray } from '@hey-api/types';
19
20import type { Configs } from './config/init';
21import { resolveJobs } from './config/init';
22import type { UserConfig } from './config/types';
23import { createClient as pCreateClient } from './createClient';
24
25const __filename = fileURLToPath(import.meta.url);
26const __dirname = path.dirname(__filename);
27
28/**
29 * Generate a client from the provided configuration.
30 *
31 * @param userConfig User provided {@link UserConfig} configuration(s).
32 */
33export async function createClient(
34 userConfig?: LazyOrAsync<MaybeArray<UserConfig>>,
35 logger = new Logger(),
36): Promise<ReadonlyArray<Context>> {
37 const resolvedConfig = typeof userConfig === 'function' ? await userConfig() : userConfig;
38 const userConfigs = resolvedConfig
39 ? resolvedConfig instanceof Array
40 ? resolvedConfig
41 : [resolvedConfig]
42 : [];
43
44 let rawLogs = userConfigs.find((config) => getLogs(config.logs).level !== 'silent')?.logs;
45 if (typeof rawLogs === 'string') {
46 rawLogs = getLogs(rawLogs);
47 }
48
49 let jobs: Configs['jobs'] = [];
50
51 try {
52 checkNodeVersion();
53
54 const eventCreateClient = logger.timeEvent('createClient');
55
56 const eventConfig = logger.timeEvent('config');
57 const resolved = await resolveJobs({ logger, userConfigs });
58 const dependencies = resolved.dependencies;
59 jobs = resolved.jobs;
60 const printIntro = jobs.some((job) => job.config.logs.level !== 'silent');
61 if (printIntro) printCliIntro(__dirname);
62 eventConfig.timeEnd();
63
64 const configErrors = jobs.flatMap((job) =>
65 job.errors.map((error) => ({ error, jobIndex: job.index })),
66 );
67 if (configErrors.length) {
68 throw new ConfigValidationError(configErrors);
69 }
70
71 const outputs = await Promise.all(
72 jobs.map(async (job) => {
73 try {
74 return await pCreateClient({
75 config: job.config,
76 dependencies,
77 jobIndex: job.index,
78 logger,
79 });
80 } catch (error) {
81 if (error instanceof Error) {
82 throw new JobError('', {
83 error,
84 jobIndex: job.index,
85 });
86 }
87 }
88 }),
89 );
90 const contexts = outputs.filter((ctx): ctx is Context => ctx !== undefined);
91
92 eventCreateClient.timeEnd();
93
94 logger.report(jobs.some((job) => job.config.logs.level === 'debug'));
95
96 return contexts;
97 } catch (error) {
98 const logs =
99 jobs.find((job) => job.config.logs.level !== 'silent')?.config.logs ??
100 jobs[0]?.config.logs ??
101 rawLogs;
102 const dryRun =
103 jobs.some((job) => job.config.dryRun) ?? userConfigs.some((config) => config.dryRun) ?? false;
104
105 const inputError = getInputError(error);
106 const normalizedError = inputError ?? error;
107
108 const logPath =
109 logs?.file && !dryRun ? logCrashReport(normalizedError, logs.path ?? '') : undefined;
110 if (!logs || logs.level !== 'silent') {
111 printCrashReport({ error, logPath });
112 const isInteractive =
113 jobs.some((job) => job.config.interactive) ??
114 userConfigs.some((config) => config.interactive) ??
115 false;
116 if (await shouldReportCrash({ error: normalizedError, isInteractive })) {
117 await openGitHubIssueWithCrashReport(error, __dirname);
118 }
119 }
120
121 if (inputError) return [];
122
123 throw error;
124 }
125}