fork of hey-api/openapi-ts because I need some additional things
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

Merge pull request #1462 from hey-api/fix/plugins-custom-type

fix: update types for custom plugins so defineConfig does not throw

authored by

Lubos and committed by
GitHub
cccc1605 f1dfeb40

+34 -21
+5
.changeset/moody-knives-accept.md
··· 1 + --- 2 + '@hey-api/openapi-ts': patch 3 + --- 4 + 5 + fix: update types for custom plugins so defineConfig does not throw
+11 -9
packages/openapi-ts/src/index.ts
··· 12 12 import type { ClientPlugins, UserPlugins } from './plugins'; 13 13 import { defaultPluginConfigs } from './plugins'; 14 14 import type { 15 + AnyPluginName, 15 16 DefaultPluginConfigs, 16 17 PluginContext, 17 18 PluginNames, ··· 190 191 userPluginsConfig, 191 192 }: { 192 193 pluginConfigs: DefaultPluginConfigs<ClientPlugins>; 193 - userPlugins: ReadonlyArray<PluginNames>; 194 + userPlugins: ReadonlyArray<AnyPluginName>; 194 195 userPluginsConfig: Config['plugins']; 195 196 }): Pick<Config, 'plugins' | 'pluginOrder'> => { 196 - const circularReferenceTracker = new Set<PluginNames>(); 197 - const pluginOrder = new Set<PluginNames>(); 197 + const circularReferenceTracker = new Set<AnyPluginName>(); 198 + const pluginOrder = new Set<AnyPluginName>(); 198 199 const plugins: Config['plugins'] = {}; 199 200 200 - const dfs = (name: PluginNames) => { 201 + const dfs = (name: AnyPluginName) => { 201 202 if (circularReferenceTracker.has(name)) { 202 203 throw new Error(`Circular reference detected at '${name}'`); 203 204 } ··· 205 206 if (!pluginOrder.has(name)) { 206 207 circularReferenceTracker.add(name); 207 208 208 - const pluginConfig = pluginConfigs[name]; 209 + const pluginConfig = pluginConfigs[name as PluginNames]; 209 210 if (!pluginConfig) { 210 211 throw new Error( 211 212 `🚫 unknown plugin dependency "${name}" - do you need to register a custom plugin with this name?`, 212 213 ); 213 214 } 214 215 215 - const defaultOptions = defaultPluginConfigs[name]; 216 - const userOptions = userPluginsConfig[name]; 216 + const defaultOptions = defaultPluginConfigs[name as PluginNames]; 217 + const userOptions = userPluginsConfig[name as PluginNames]; 217 218 if (userOptions && defaultOptions) { 218 219 const nativePluginOption = Object.keys(userOptions).find((key) => 219 220 key.startsWith('_'), ··· 243 244 }, 244 245 pluginByTag: (tag) => { 245 246 for (const userPlugin of userPlugins) { 246 - const defaultConfig = defaultPluginConfigs[userPlugin]; 247 + const defaultConfig = 248 + defaultPluginConfigs[userPlugin as PluginNames]; 247 249 if ( 248 250 defaultConfig && 249 251 defaultConfig._tags?.includes(tag) && ··· 274 276 } 275 277 276 278 return { 277 - pluginOrder: Array.from(pluginOrder), 279 + pluginOrder: Array.from(pluginOrder) as ReadonlyArray<PluginNames>, 278 280 plugins, 279 281 }; 280 282 };
+15 -5
packages/openapi-ts/src/plugins/types.d.ts
··· 20 20 | 'fastify' 21 21 | 'zod'; 22 22 23 + // eslint-disable-next-line @typescript-eslint/ban-types 24 + export type AnyPluginName = PluginNames | (string & {}); 25 + 23 26 type PluginTag = 'transformer' | 'validator'; 24 27 25 28 export interface PluginContext { 26 29 ensureDependency: (name: PluginNames | true) => void; 27 - pluginByTag: (tag: PluginTag) => PluginNames | undefined; 30 + pluginByTag: (tag: PluginTag) => AnyPluginName | undefined; 28 31 } 29 32 30 33 interface BaseConfig { ··· 35 38 * barrel file? 36 39 */ 37 40 exportFromIndex?: boolean; 38 - // eslint-disable-next-line @typescript-eslint/ban-types 39 - name: PluginNames | (string & {}); 41 + name: AnyPluginName; 40 42 output?: string; 41 43 } 42 44 ··· 45 47 * Dependency plugins will be always processed, regardless of whether user 46 48 * explicitly defines them in their `plugins` config. 47 49 */ 48 - _dependencies?: ReadonlyArray<PluginNames>; 50 + _dependencies?: ReadonlyArray<AnyPluginName>; 49 51 /** 50 52 * Allows overriding config before it's sent to the parser. An example is 51 53 * defining `validator` as `true` and the plugin figures out which plugin ··· 83 85 84 86 export type DefineConfig<Config extends BaseConfig> = ( 85 87 config?: Plugin.UserConfig<Config>, 86 - ) => Plugin.Config<Config>; 88 + ) => Omit<Plugin.Config<Config>, 'name'> & { 89 + /** 90 + * Cast name to `any` so it doesn't throw type error in `plugins` array. 91 + * We could allow any `string` as plugin `name` in the object syntax, but 92 + * that TypeScript trick would cause all string methods to appear as 93 + * suggested auto completions, which is undesirable. 94 + */ 95 + name: any; 96 + }; 87 97 88 98 /** 89 99 * Plugin implementation for experimental parser.
+3 -7
packages/openapi-ts/test/plugins.test.ts
··· 244 244 it('handles a custom plugin', async () => { 245 245 const myPlugin: Plugin.Config<{ 246 246 customOption: boolean; 247 - name: string; 247 + name: any; 248 248 output: string; 249 249 }> = { 250 250 _dependencies: ['@hey-api/typescript'], ··· 260 260 experimentalParser: true, 261 261 input: path.join(__dirname, 'spec', '3.1.x', 'full.json'), 262 262 output: path.join(outputDir, myPlugin.name, 'default'), 263 - // @ts-expect-error 264 263 plugins: [myPlugin], 265 264 }); 266 265 ··· 270 269 271 270 it('throws on invalid dependency', async () => { 272 271 const myPlugin: Plugin.Config<{ 273 - name: string; 272 + name: any; 274 273 output: string; 275 274 }> = { 276 - // @ts-expect-error 277 275 _dependencies: ['@hey-api/oops'], 278 276 _handler: vi.fn(), 279 277 _handlerLegacy: vi.fn(), ··· 290 288 level: 'silent', 291 289 }, 292 290 output: path.join(outputDir, myPlugin.name, 'default'), 293 - // @ts-expect-error 294 291 plugins: [myPlugin], 295 292 }), 296 293 ).rejects.toThrowError(/unknown plugin/g); ··· 301 298 302 299 it('throws on native plugin override', async () => { 303 300 const myPlugin: Plugin.Config<{ 304 - name: string; 301 + name: any; 305 302 output: string; 306 303 }> = { 307 304 _handler: vi.fn(), ··· 319 316 level: 'silent', 320 317 }, 321 318 output: path.join(outputDir, myPlugin.name, 'default'), 322 - // @ts-expect-error 323 319 plugins: [myPlugin], 324 320 }), 325 321 ).rejects.toThrowError(/cannot register plugin/g);