fork of hey-api/openapi-ts because I need some additional things
1import type { AnyPluginName, PluginContext, PluginNames } from '@hey-api/shared';
2import { dependencyFactory, valueToObject } from '@hey-api/shared';
3
4import { defaultPluginConfigs } from '../plugins/config';
5import type { Config, UserConfig } from './types';
6
7/**
8 * Default plugins used to generate artifacts if plugins aren't specified.
9 */
10export const defaultPlugins = ['@hey-api/python-sdk'] as const satisfies ReadonlyArray<PluginNames>;
11
12function getPluginsConfig({
13 dependencies,
14 userPlugins,
15 userPluginsConfig,
16}: {
17 dependencies: Record<string, string>;
18 userPlugins: ReadonlyArray<AnyPluginName>;
19 userPluginsConfig: Config['plugins'];
20}): Pick<Config, 'plugins' | 'pluginOrder'> {
21 const circularReferenceTracker = new Set<AnyPluginName>();
22 const pluginOrder = new Set<AnyPluginName>();
23 const plugins: Config['plugins'] = {};
24
25 const dfs = (name: AnyPluginName) => {
26 if (circularReferenceTracker.has(name)) {
27 throw new Error(`Circular reference detected at '${name}'`);
28 }
29
30 if (pluginOrder.has(name)) {
31 return;
32 }
33
34 circularReferenceTracker.add(name);
35
36 const defaultPlugin = defaultPluginConfigs[name as PluginNames];
37 const userPlugin = userPluginsConfig[name as PluginNames];
38
39 if (!defaultPlugin && !userPlugin) {
40 throw new Error(
41 `unknown plugin dependency "${name}" - do you need to register a custom plugin with this name?`,
42 );
43 }
44
45 const plugin = {
46 ...defaultPlugin,
47 ...userPlugin,
48 config: {
49 ...defaultPlugin?.config,
50 ...userPlugin?.config,
51 },
52 dependencies: new Set([
53 ...(defaultPlugin?.dependencies || []),
54 ...(userPlugin?.dependencies || []),
55 ]),
56 };
57
58 if (plugin.resolveConfig) {
59 const context: PluginContext = {
60 package: dependencyFactory(dependencies),
61 pluginByTag: (tag, props = {}) => {
62 const { defaultPlugin, errorMessage } = props;
63
64 for (const userPlugin of userPlugins) {
65 const defaultConfig =
66 defaultPluginConfigs[userPlugin as PluginNames] ||
67 userPluginsConfig[userPlugin as PluginNames];
68 if (defaultConfig && defaultConfig.tags?.includes(tag) && userPlugin !== name) {
69 return userPlugin as any;
70 }
71 }
72
73 if (defaultPlugin) {
74 const defaultConfig =
75 defaultPluginConfigs[defaultPlugin as PluginNames] ||
76 userPluginsConfig[defaultPlugin as PluginNames];
77 if (defaultConfig && defaultConfig.tags?.includes(tag) && defaultPlugin !== name) {
78 return defaultPlugin;
79 }
80 }
81
82 throw new Error(errorMessage || `missing plugin - no plugin with tag "${tag}" found`);
83 },
84 valueToObject,
85 };
86 // @ts-expect-error
87 plugin.resolveConfig(plugin, context);
88 }
89
90 for (const dependency of plugin.dependencies) {
91 dfs(dependency);
92 }
93
94 circularReferenceTracker.delete(name);
95 pluginOrder.add(name);
96
97 // @ts-expect-error
98 plugins[name] = plugin;
99 };
100
101 for (const name of userPlugins) {
102 dfs(name);
103 }
104
105 return {
106 pluginOrder: Array.from(pluginOrder) as ReadonlyArray<PluginNames>,
107 plugins,
108 };
109}
110
111function isPluginClient(plugin: Required<UserConfig>['plugins'][number]): boolean {
112 if (typeof plugin === 'string') {
113 return plugin.startsWith('@hey-api/client');
114 }
115
116 return (
117 plugin.name.startsWith('@hey-api/client') ||
118 // @ts-expect-error
119 (plugin.tags && plugin.tags.includes('client'))
120 );
121}
122
123export function getPlugins({
124 dependencies,
125 userConfig,
126}: {
127 dependencies: Record<string, string>;
128 userConfig: UserConfig;
129}): Pick<Config, 'plugins' | 'pluginOrder'> {
130 const userPluginsConfig: Config['plugins'] = {};
131
132 let definedPlugins: UserConfig['plugins'] = defaultPlugins;
133
134 if (userConfig.plugins) {
135 userConfig.plugins = userConfig.plugins.filter(
136 (plugin) =>
137 (typeof plugin === 'string' && plugin) || (typeof plugin !== 'string' && plugin.name),
138 );
139 if (userConfig.plugins.length === 1 && isPluginClient(userConfig.plugins[0]!)) {
140 definedPlugins = [...defaultPlugins, ...userConfig.plugins];
141 } else {
142 definedPlugins = userConfig.plugins;
143 }
144 }
145
146 const userPlugins = definedPlugins
147 .map((plugin) => {
148 if (typeof plugin === 'string') {
149 return plugin;
150 }
151
152 const pluginName = plugin.name;
153
154 if (pluginName) {
155 // @ts-expect-error
156 if (plugin.handler) {
157 // @ts-expect-error
158 userPluginsConfig[pluginName] = plugin;
159 } else {
160 // @ts-expect-error
161 userPluginsConfig[pluginName] = {
162 config: { ...plugin },
163 };
164 // @ts-expect-error
165 delete userPluginsConfig[pluginName]!.config.name;
166 }
167 }
168
169 return pluginName;
170 })
171 .filter(Boolean);
172
173 return getPluginsConfig({ dependencies, userPlugins, userPluginsConfig });
174}