Skip to content

Commit 0eb8683

Browse files
authored
Merge pull request #2215 from hey-api/refactor/plugin-walk
refactor(parser): replace plugin.subscribe with plugin.walk
2 parents 4128000 + 82e56e9 commit 0eb8683

File tree

23 files changed

+506
-665
lines changed

23 files changed

+506
-665
lines changed

.changeset/lucky-bees-exist.md

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
---
2+
'@hey-api/openapi-ts': minor
3+
---
4+
5+
feat(parser): replace `plugin.subscribe()` with `plugin.forEach()`
6+
7+
### Added `plugin.forEach()` method
8+
9+
This method replaces the `.subscribe()` method. Additionally, `.forEach()` is executed immediately, which means we don't need the `before` and `after` events – simply move your code before and after the `.forEach()` block.
10+
11+
```ts
12+
plugin.forEach('operation', 'schema', (event) => {
13+
// do something with event
14+
});
15+
```

docs/openapi-ts/migrating.md

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,22 @@ This config option is deprecated and will be removed in favor of [clients](./cli
2727

2828
This config option is deprecated and will be removed.
2929

30+
## v0.75.0
31+
32+
### Added `plugin.forEach()` method
33+
34+
This method replaces the `.subscribe()` method. Additionally, `.forEach()` is executed immediately, which means we don't need the `before` and `after` events – simply move your code before and after the `.forEach()` block.
35+
36+
```ts
37+
plugin.subscribe('operation', (event) => { // [!code --]
38+
// do something with event // [!code --]
39+
}); // [!code --]
40+
plugin.subscribe('schema', (event) => { // [!code --]
41+
plugin.forEach('operation', 'schema', (event) => { // [!code ++]
42+
// do something with event
43+
});
44+
```
45+
3046
## v0.74.0
3147
3248
### Single Zod schema per request

docs/openapi-ts/plugins/custom.md

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -118,20 +118,12 @@ export const handler: Plugin.Handler<Config> = ({ plugin }) => {
118118
path: plugin.output,
119119
});
120120

121-
plugin.subscribe('before', () => {
122-
// do something before parsing the input
123-
});
124-
125-
plugin.subscribe('operation', ({ operation }) => {
126-
// do something with the operation model
127-
});
128-
129-
plugin.subscribe('schema', ({ operation }) => {
130-
// do something with the schema model
131-
});
132-
133-
plugin.subscribe('after', () => {
134-
// do something after parsing the input
121+
plugin.forEach('operation', 'schema', (event) => {
122+
if (event.type === 'operation') {
123+
// do something with the operation model
124+
} else if (event.type === 'schema') {
125+
// do something with the schema model
126+
}
135127
});
136128

137129
// we're using the TypeScript Compiler API

packages/openapi-ts-tests/test/openapi-ts.config.ts

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -57,8 +57,8 @@ export default defineConfig(() => {
5757
// 'invalid',
5858
// 'servers-entry.yaml',
5959
// ),
60-
path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'),
61-
// path: path.resolve(__dirname, 'spec', 'v3-transforms.json'),
60+
// path: path.resolve(__dirname, 'spec', '3.1.x', 'validators.yaml'),
61+
path: path.resolve(__dirname, 'spec', 'v3-transforms.json'),
6262
// path: 'http://localhost:4000/',
6363
// path: 'https://get.heyapi.dev/',
6464
// path: 'https://get.heyapi.dev/hey-api/backend?branch=main&version=1.0.0',
@@ -93,9 +93,9 @@ export default defineConfig(() => {
9393
// ),
9494
},
9595
plugins: [
96-
customClientPlugin({
97-
baseUrl: false,
98-
}),
96+
// customClientPlugin({
97+
// baseUrl: false,
98+
// }),
9999
// myClientPlugin(),
100100
{
101101
// baseUrl: false,
@@ -123,13 +123,13 @@ export default defineConfig(() => {
123123
// responseStyle: 'data',
124124
// throwOnError: true,
125125
// transformer: '@hey-api/transformers',
126-
// transformer: true,
126+
transformer: true,
127127
validator: 'zod',
128128
},
129129
{
130130
// bigInt: true,
131-
dates: true,
132-
// name: '@hey-api/transformers',
131+
// dates: true,
132+
name: '@hey-api/transformers',
133133
},
134134
{
135135
enums: 'typescript+namespace',

packages/openapi-ts/src/generate/output.ts

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import path from 'node:path';
33
import ts from 'typescript';
44

55
import { compiler } from '../compiler';
6-
import { parseIR } from '../ir/parser';
76
import type { IR } from '../ir/types';
87
import { getClientPlugin } from '../plugins/@hey-api/client-core/utils';
98
import { generateClientBundle } from './client';
@@ -33,11 +32,9 @@ export const generateOutput = async ({ context }: { context: IR.Context }) => {
3332
}
3433

3534
for (const plugin of context.registerPlugins()) {
36-
plugin.run();
35+
await plugin.run();
3736
}
3837

39-
await parseIR({ context });
40-
4138
if (!context.config.dryRun) {
4239
const indexFile = context.createFile({
4340
id: '_index',

packages/openapi-ts/src/ir/context.ts

Lines changed: 9 additions & 106 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import path from 'node:path';
22

3-
import { HeyApiError } from '../error';
43
import { TypeScriptFile } from '../generate/files';
54
import { PluginInstance } from '../plugins/shared/utils/instance';
65
import type { Config, StringCase } from '../types/config';
@@ -42,47 +41,6 @@ export interface ContextFile {
4241
path: string;
4342
}
4443

45-
export interface Events {
46-
/**
47-
* Called after parsing.
48-
*/
49-
after: () => void;
50-
/**
51-
* Called before parsing.
52-
*/
53-
before: () => void;
54-
operation: (args: {
55-
method: keyof IR.PathItemObject;
56-
operation: IR.OperationObject;
57-
path: string;
58-
}) => void;
59-
parameter: (args: {
60-
$ref: string;
61-
name: string;
62-
parameter: IR.ParameterObject;
63-
}) => void;
64-
requestBody: (args: {
65-
$ref: string;
66-
name: string;
67-
requestBody: IR.RequestBodyObject;
68-
}) => void;
69-
schema: (args: {
70-
$ref: string;
71-
name: string;
72-
schema: IR.SchemaObject;
73-
}) => void;
74-
server: (args: { server: IR.ServerObject }) => void;
75-
}
76-
77-
type ListenerWithMeta<T extends keyof Events> = {
78-
callbackFn: Events[T];
79-
pluginName: string;
80-
};
81-
82-
type Listeners = {
83-
[T in keyof Events]?: Array<ListenerWithMeta<T>>;
84-
};
85-
8644
export class IRContext<Spec extends Record<string, any> = any> {
8745
/**
8846
* Configuration for parsing and generating the output. This
@@ -92,11 +50,11 @@ export class IRContext<Spec extends Record<string, any> = any> {
9250
/**
9351
* A map of files that will be generated from `spec`.
9452
*/
95-
public files: Files;
53+
public files: Files = {};
9654
/**
9755
* Intermediate representation model obtained from `spec`.
9856
*/
99-
public ir: IR.Model;
57+
public ir: IR.Model = {};
10058
/**
10159
* A map of registered plugin instances, keyed by plugin name. Plugins are
10260
* registered through the `registerPlugin` method and can be accessed by
@@ -108,50 +66,11 @@ export class IRContext<Spec extends Record<string, any> = any> {
10866
*/
10967
public spec: Spec;
11068

111-
/**
112-
* A map of event listeners.
113-
*/
114-
private listeners: Listeners;
115-
11669
constructor({ config, spec }: { config: Config; spec: Spec }) {
11770
this.config = config;
118-
this.files = {};
119-
this.ir = {};
120-
this.listeners = {};
12171
this.spec = spec;
12272
}
12373

124-
/**
125-
* Notify all event listeners about `event`.
126-
*/
127-
public async broadcast<T extends keyof Events>(
128-
event: T,
129-
...args: Parameters<Events[T]>
130-
): Promise<void> {
131-
const eventListeners = this.listeners[event];
132-
133-
if (eventListeners) {
134-
for (const listener of eventListeners) {
135-
try {
136-
await listener.callbackFn(
137-
// @ts-expect-error
138-
...args,
139-
);
140-
} catch (error) {
141-
const originalError =
142-
error instanceof Error ? error : new Error(String(error));
143-
throw new HeyApiError({
144-
args,
145-
error: originalError,
146-
event,
147-
name: 'BroadcastError',
148-
pluginName: listener.pluginName,
149-
});
150-
}
151-
}
152-
}
153-
}
154-
15574
/**
15675
* Create and return a new TypeScript file. Also set the current file context
15776
* to the newly created file.
@@ -216,13 +135,14 @@ export class IRContext<Spec extends Record<string, any> = any> {
216135
}
217136

218137
/**
219-
* Generator that iterates through plugin order and registers each plugin.
220-
* Yields the registered plugin instance for each plugin name.
138+
* Registers all plugins in the order specified by the configuration and returns
139+
* an array of the registered PluginInstance objects. Each plugin is instantiated
140+
* and added to the context's plugins map.
141+
*
142+
* @returns {ReadonlyArray<PluginInstance>} An array of registered plugin instances in order.
221143
*/
222-
public *registerPlugins(): Generator<PluginInstance> {
223-
for (const name of this.config.pluginOrder) {
224-
yield this.registerPlugin(name);
225-
}
144+
public registerPlugins(): ReadonlyArray<PluginInstance> {
145+
return this.config.pluginOrder.map((name) => this.registerPlugin(name));
226146
}
227147

228148
// TODO: parser - works the same as resolveRef, but for IR schemas.
@@ -245,21 +165,4 @@ export class IRContext<Spec extends Record<string, any> = any> {
245165
spec: this.spec,
246166
});
247167
}
248-
249-
/**
250-
* Register a new `event` listener.
251-
*/
252-
public subscribe<T extends keyof Events>(
253-
event: T,
254-
callbackFn: Events[T],
255-
pluginName: string,
256-
): void {
257-
if (!this.listeners[event]) {
258-
this.listeners[event] = [];
259-
}
260-
this.listeners[event].push({
261-
callbackFn,
262-
pluginName: pluginName ?? '',
263-
});
264-
}
265168
}

packages/openapi-ts/src/ir/parser.ts

Lines changed: 0 additions & 47 deletions
This file was deleted.

packages/openapi-ts/src/ir/types.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ import type {
33
SecuritySchemeObject,
44
ServerObject,
55
} from '../openApi/3.1.x/types/spec';
6-
import type { ContextFile as CtxFile, Events, IRContext } from './context';
6+
import type { ContextFile as CtxFile, IRContext } from './context';
77
import type { IRMediaType } from './mediaType';
88

99
interface IRBodyObject {
@@ -217,7 +217,6 @@ export namespace IR {
217217
export type BodyObject = IRBodyObject;
218218
export type ComponentsObject = IRComponentsObject;
219219
export type Context<Spec extends Record<string, any> = any> = IRContext<Spec>;
220-
export type ContextEvents = Events;
221220
export type ContextFile = CtxFile;
222221
export type Model = IRModel;
223222
export type OperationObject = IROperationObject;

0 commit comments

Comments
 (0)