Skip to content

Commit 1c8eeb0

Browse files
committed
implement m6
1 parent 54b3152 commit 1c8eeb0

3 files changed

Lines changed: 152 additions & 32 deletions

File tree

Lines changed: 23 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,49 @@
11
import type { IR } from '@hey-api/shared';
22

3-
import type { $ } from '../../../ts-dsl';
4-
5-
type Expression = ReturnType<typeof $.expr>;
3+
import type { Expression } from './shared/types';
4+
import type { FakerJsFakerPlugin } from './types';
5+
import { toNodeRefV1, toNodeV1 } from './v1/api';
66

77
export type IApi = {
88
/**
9-
* Generate a Faker expression for a schema.
9+
* Generate an inline Faker expression for a schema.
1010
*
1111
* Returns an expression that produces a valid instance when executed.
12-
* Use when you need one-off generation without referencing shared artifacts.
12+
* The returned expression may reference faker symbols (`ensureFaker`,
13+
* `options`) — cross-plugin references resolve imports automatically.
1314
*
1415
* @example
1516
* ```ts
17+
* // For { type: 'object', properties: { name: string, email: string } }:
1618
* {
17-
* name: faker.person.fullName(),
18-
* email: faker.internet.email()
19+
* name: ensureFaker(options).person.fullName(),
20+
* email: ensureFaker(options).internet.email()
1921
* }
2022
* ```
2123
*/
22-
toNode(schema: IR.SchemaObject): Expression;
24+
toNode(args: { plugin: FakerJsFakerPlugin['Instance']; schema: IR.SchemaObject }): Expression;
2325
/**
24-
* Get a reference to a generated Faker expression for a schema.
26+
* Get a reference to an existing Faker factory for a schema.
2527
*
26-
* Returns a call expression referencing the shared artifact.
27-
* If the artifact doesn't exist, it will be created.
28+
* For `$ref` schemas, looks up the registered factory symbol via
29+
* `referenceSymbol` and returns a call expression (e.g. `fakeUser(options)`).
30+
* For non-`$ref` schemas, falls back to an inline expression via `toNode`.
2831
*
2932
* @example
30-
* // Returns: fakeUser()
33+
* ```ts
34+
* // For { $ref: '#/components/schemas/User' }:
35+
* fakeUser(options)
36+
* ```
3137
*/
32-
toNodeRef(schema: IR.SchemaObject): Expression;
38+
toNodeRef(args: { plugin: FakerJsFakerPlugin['Instance']; schema: IR.SchemaObject }): Expression;
3339
};
3440

3541
export class Api implements IApi {
36-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
37-
toNode(_schema: IR.SchemaObject): Expression {
38-
return undefined as any;
42+
toNode(args: { plugin: FakerJsFakerPlugin['Instance']; schema: IR.SchemaObject }): Expression {
43+
return toNodeV1(args);
3944
}
4045

41-
// eslint-disable-next-line @typescript-eslint/no-unused-vars
42-
toNodeRef(_schema: IR.SchemaObject): Expression {
43-
return undefined as any;
46+
toNodeRef(args: { plugin: FakerJsFakerPlugin['Instance']; schema: IR.SchemaObject }): Expression {
47+
return toNodeRefV1(args);
4448
}
4549
}

packages/openapi-ts/src/plugins/@faker-js/faker/shared/operation.ts

Lines changed: 87 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,8 @@ function exportOperationResponse({
112112
path: [...path, group, statusCode],
113113
resource: 'operation',
114114
resourceId: operation.id,
115-
role: group,
115+
role: 'response',
116+
statusCode,
116117
tags,
117118
tool: 'faker',
118119
},
@@ -125,12 +126,11 @@ function exportOperationResponse({
125126

126127
// Look up TypeScript type for indexed access return type
127128
// 2XX codes → responses (plural), 4XX/5XX → errors (plural)
128-
const typeRole = group; // 'responses' or 'errors'
129129
const typeSymbol = plugin.querySymbol({
130130
category: 'type',
131131
resource: 'operation',
132132
resourceId: operation.id,
133-
role: typeRole,
133+
role: group,
134134
tool: 'typescript',
135135
});
136136

@@ -148,6 +148,85 @@ function exportOperationResponse({
148148
plugin.node($.const(symbol).export().assign(arrowFn));
149149
}
150150

151+
/**
152+
* Export an unsuffixed operation response factory (single meaningful 2XX, no errors).
153+
* Uses manual export with consistent metadata (role: 'response', statusCode).
154+
*/
155+
function exportUnsuffixedResponse({
156+
naming,
157+
operation,
158+
path,
159+
plugin,
160+
processor,
161+
schema,
162+
statusCode,
163+
tags,
164+
}: {
165+
naming: NamingConfig;
166+
operation: IR.OperationObject;
167+
path: ReadonlyArray<string | number>;
168+
plugin: FakerJsFakerPlugin['Instance'];
169+
processor: ProcessorResult;
170+
schema: IR.SchemaObject;
171+
statusCode: string;
172+
tags?: ReadonlyArray<string>;
173+
}): void {
174+
const result = processor.process({
175+
export: false,
176+
meta: {
177+
resource: 'operation',
178+
resourceId: operation.id,
179+
role: 'response',
180+
},
181+
naming,
182+
namingAnchor: operation.id,
183+
path: [...path, 'responses'],
184+
plugin,
185+
schema,
186+
tags,
187+
}) as FakerResult | void;
188+
189+
if (!result) return;
190+
191+
const name = pathToName([...path, 'responses'], { anchor: operation.id });
192+
193+
const symbol = plugin.registerSymbol(
194+
buildSymbolIn({
195+
meta: {
196+
category: 'schema',
197+
path: [...path, 'responses'],
198+
resource: 'operation',
199+
resourceId: operation.id,
200+
role: 'response',
201+
statusCode,
202+
tags,
203+
tool: 'faker',
204+
},
205+
name,
206+
naming,
207+
plugin,
208+
schema,
209+
}),
210+
);
211+
212+
// Look up TypeScript type (singular 'response' role)
213+
const typeSymbol = plugin.querySymbol({
214+
category: 'type',
215+
resource: 'operation',
216+
resourceId: operation.id,
217+
role: 'response',
218+
tool: 'typescript',
219+
});
220+
221+
const arrowFn = $.func()
222+
.arrow()
223+
.$if(result.usesFaker, (f) => f.param('options', (p) => p.optional().type('Options')))
224+
.$if(typeSymbol, (f) => f.returns($.type(typeSymbol!)))
225+
.do($.return(result.expression));
226+
227+
plugin.node($.const(symbol).export().assign(arrowFn));
228+
}
229+
151230
export function irOperationToAst({
152231
operation,
153232
path,
@@ -172,23 +251,18 @@ export function irOperationToAst({
172251
const useSuffix = !(meaningful.length === 1 && meaningful[0]!.group === 'responses');
173252

174253
if (!useSuffix) {
175-
// Single 2XX: no suffix, use standard exportAst pipeline
176254
const entry = meaningful[0]!;
177-
processor.process({
178-
meta: {
179-
resource: 'operation',
180-
resourceId: operation.id,
181-
role: 'response',
182-
},
255+
exportUnsuffixedResponse({
183256
naming: plugin.config.responses,
184-
namingAnchor: operation.id,
185-
path: [...path, 'responses'],
257+
operation,
258+
path,
186259
plugin,
260+
processor,
187261
schema: entry.schema,
262+
statusCode: entry.statusCode,
188263
tags,
189264
});
190265
} else {
191-
// Suffixed: per-status-code factories
192266
for (const entry of meaningful) {
193267
exportOperationResponse({
194268
group: entry.group,
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { ref } from '@hey-api/codegen-core';
2+
import type { IR } from '@hey-api/shared';
3+
import { createSchemaWalker } from '@hey-api/shared';
4+
5+
import { $ } from '../../../../ts-dsl';
6+
import type { EmitTracking, Expression, FakerResult } from '../shared/types';
7+
import type { FakerJsFakerPlugin } from '../types';
8+
import { createVisitor } from './walker';
9+
10+
export function toNodeV1({
11+
plugin,
12+
schema,
13+
}: {
14+
plugin: FakerJsFakerPlugin['Instance'];
15+
schema: IR.SchemaObject;
16+
}): Expression {
17+
const tracking: EmitTracking = { needsResolveCondition: false };
18+
const visitor = createVisitor({ plugin, tracking });
19+
const walk = createSchemaWalker(visitor);
20+
const result = walk(schema, { path: ref([]), plugin });
21+
const final = visitor.applyModifiers(result, { path: ref([]), plugin }) as FakerResult;
22+
return final.expression;
23+
}
24+
25+
export function toNodeRefV1({
26+
plugin,
27+
schema,
28+
}: {
29+
plugin: FakerJsFakerPlugin['Instance'];
30+
schema: IR.SchemaObject;
31+
}): Expression {
32+
if (schema.$ref) {
33+
const symbol = plugin.referenceSymbol({
34+
category: 'schema',
35+
resource: 'definition',
36+
resourceId: schema.$ref,
37+
tool: 'faker',
38+
});
39+
return $(symbol).call($('options'));
40+
}
41+
return toNodeV1({ plugin, schema });
42+
}

0 commit comments

Comments
 (0)