Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 25 additions & 1 deletion packages/openapi-ts/src/plugins/@hey-api/transformers/plugin.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,15 +27,18 @@ const isNodeReturnStatement = ({

const schemaResponseTransformerNodes = ({
plugin,
processingSchemas,
schema,
}: {
plugin: HeyApiTransformersPlugin['Instance'];
processingSchemas: Set<string>;
schema: IR.SchemaObject;
}): Array<ts.Expression | ts.Statement> => {
const identifierData = tsc.identifier({ text: dataVariableName });
const nodes = processSchemaType({
dataExpression: identifierData,
plugin,
processingSchemas,
schema,
});
// append return statement if one does not already exist
Expand All @@ -51,19 +54,25 @@ const schemaResponseTransformerNodes = ({
const processSchemaType = ({
dataExpression,
plugin,
processingSchemas,
schema,
}: {
dataExpression?: ts.Expression | string;
plugin: HeyApiTransformersPlugin['Instance'];
processingSchemas: Set<string>;
schema: IR.SchemaObject;
}): Array<ts.Expression | ts.Statement> => {
if (schema.$ref) {
const selector = plugin.api.selector('response-ref', schema.$ref);
const selectorKey = JSON.stringify(selector);

if (!plugin.getSymbol(selector)) {
// TODO: remove
// create each schema response transformer only once

// Mark as processing to handle recursion
processingSchemas.add(selectorKey);

// Register symbol early to prevent infinite recursion with self-referential schemas
const symbol = plugin.registerSymbol({
name: buildName({
Expand All @@ -81,8 +90,13 @@ const processSchemaType = ({
);
const nodes = schemaResponseTransformerNodes({
plugin,
processingSchemas,
schema: refSchema,
});

// Done processing
processingSchemas.delete(selectorKey);

if (nodes.length) {
const node = tsc.constVariable({
expression: tsc.arrowFunction({
Expand All @@ -103,7 +117,9 @@ const processSchemaType = ({
}
}

if (plugin.isSymbolRegistered(selector)) {
// Only reference the symbol if it has a value (transformer function was generated)
// OR is currently being processed (recursive case)
if (plugin.hasSymbolValue(selector) || processingSchemas.has(selectorKey)) {
const ref = plugin.referenceSymbol(selector);
const callExpression = tsc.callExpression({
functionName: ref.placeholder,
Expand Down Expand Up @@ -145,6 +161,7 @@ const processSchemaType = ({
: processSchemaType({
dataExpression: 'item',
plugin,
processingSchemas,
schema: schema.items?.[0]
? schema.items[0]
: {
Expand Down Expand Up @@ -209,6 +226,7 @@ const processSchemaType = ({
const propertyNodes = processSchemaType({
dataExpression: propertyAccessExpression,
plugin,
processingSchemas,
schema: property,
});
if (!propertyNodes.length) {
Expand Down Expand Up @@ -245,6 +263,7 @@ const processSchemaType = ({
return processSchemaType({
dataExpression: 'item',
plugin,
processingSchemas,
schema: schema.items[0]!,
});
}
Expand All @@ -262,6 +281,7 @@ const processSchemaType = ({
const nodes = processSchemaType({
dataExpression: dataExpression || 'item',
plugin,
processingSchemas,
schema: item,
});
if (nodes.length) {
Expand Down Expand Up @@ -319,6 +339,9 @@ const processSchemaType = ({

// handles only response transformers for now
export const handler: HeyApiTransformersPlugin['Handler'] = ({ plugin }) => {
// Track schemas currently being processed to handle recursion
const processingSchemas = new Set<string>();

plugin.forEach(
'operation',
({ operation }) => {
Expand All @@ -343,6 +366,7 @@ export const handler: HeyApiTransformersPlugin['Handler'] = ({ plugin }) => {
// TODO: parser - consider handling simple string response which is also a date
const nodes = schemaResponseTransformerNodes({
plugin,
processingSchemas,
schema: response,
});
if (!nodes.length) return;
Expand Down
5 changes: 5 additions & 0 deletions packages/openapi-ts/src/plugins/shared/utils/instance.ts
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,11 @@ export class PluginInstance<T extends Plugin.Types = Plugin.Types> {
return this.gen.symbols.isRegistered(symbolIdOrSelector);
}

hasSymbolValue(symbolIdOrSelector: number | Selector): boolean {
const symbol = this.getSymbol(symbolIdOrSelector);
return symbol ? this.gen.symbols.hasValue(symbol.id) : false;
}

referenceSymbol(symbolIdOrSelector: number | Selector): Symbol {
return this.gen.symbols.reference(symbolIdOrSelector);
}
Expand Down