Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 27, 2025

Since v0.86.6, transformers.gen.ts generates calls to schema transformer functions that don't exist when schemas require no transformations, causing TypeScript compilation errors.

Root Cause

The plugin registers symbols for all referenced schemas (to prevent infinite recursion) and generates calls to them in operation transformers using isSymbolRegistered(), but only emits the actual schema transformer functions when transformations are needed (e.g., date-time conversions). This causes TypeScript errors when operation transformers try to call non-existent schema transformer functions.

// Generated code that fails:
export const chatControllerCreateResponseTransformer = async (data: any) => {
  data = chatResponseDtoSchemaResponseTransformer(data);  // ❌ function not emitted
  return data;
};

Solution

Modified the transformer plugin to only reference schema transformer functions when they actually exist:

  • Added hasSymbolValue() method to check if a symbol has an emitted value (not just registered)
  • Track schemas currently being processed in a Set to handle recursive/self-referential schemas
  • Only generate calls to transformer functions that have values set OR are currently being processed (recursive case)

This ensures:

  1. No calls to non-existent transformer functions
  2. No unnecessary pass-through functions are generated for schemas without transformations
  3. Recursive/self-referential schemas continue to work correctly
// For schemas with no transformations - no transformer function generated, no reference
// (transformers.gen.ts may not even be created if no schemas need transformations)

// For schemas with transformations - function generated and referenced:
const chatResponseDtoSchemaResponseTransformer = (data: any) => {
    if (data.createdAt) {
        data.createdAt = new Date(data.createdAt);
    }
    return data;
};

Changes

Plugin Instance (instance.ts)

  • Added hasSymbolValue() method to check if a symbol has an emitted value

Core Logic (plugin.ts)

  • Track schemas being processed in a Set (scoped to handler instance)
  • Pass processingSchemas through function call chain
  • Check hasSymbolValue() OR processingSchemas.has() before generating transformer calls
  • Only emit schema transformer functions when transformations are needed (unchanged behavior)

Testing

  • ✅ Tested with schemas that have no transformable fields (no transformers.gen.ts file generated)
  • ✅ Tested with schemas that have date-time fields (transformations work correctly)
  • ✅ Tested with recursive/self-referential schemas (continue to work correctly)
  • ✅ All 536 snapshot tests pass
  • ✅ All 967 unit tests pass
  • ✅ Linting passes

Fixes #2864

Original prompt

This section details on the original issue you should resolve

<issue_title>0.86.6: Generated transformers.gen.ts references missing transformer functions</issue_title>
<issue_description>### Description

Since @hey-api/[email protected], the generated client file transformers.gen.ts references response transformer functions that are not emitted or imported, causing TypeScript errors.

Example generated code:

// This file is auto-generated by @hey-api/openapi-ts

import type {
  ChatControllerCreateResponse,
  MetaControllerFindAllResponse,
} from "./types.gen";

export const chatControllerCreateResponseTransformer = async (
  data: any,
): Promise<ChatControllerCreateResponse> => {
  data = chatResponseDtoSchemaResponseTransformer(data);
  return data;
};

export const metaControllerFindAllResponseTransformer = async (
  data: any,
): Promise<MetaControllerFindAllResponse> => {
  data = paginatedResponseDtoSchemaResponseTransformer(data);
  return data;
};

generated/client/transformers.gen.ts:11:10 - error TS2304: Cannot find name >'chatResponseDtoSchemaResponseTransformer'.
generated/client/transformers.gen.ts:18:10 - error TS2304: Cannot find name >'paginatedResponseDtoSchemaResponseTransformer'.

Reproducible example or configuration

No response

OpenAPI specification (optional)

No response

System information (optional)

@hey-api/[email protected] and @hey-api/[email protected]</issue_description>

Comments on the Issue (you are @copilot in this section)

@mrlubos I'm going to assume this is a regression, can you provide an OpenAPI spec to reproduce? @mrlubos @dosu stop annoying the man

✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

@bolt-new-by-stackblitz
Copy link

Review PR in StackBlitz Codeflow Run & review this pull request in StackBlitz Codeflow.

@changeset-bot
Copy link

changeset-bot bot commented Oct 27, 2025

⚠️ No Changeset found

Latest commit: 80035e7

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

@vercel
Copy link

vercel bot commented Oct 27, 2025

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Preview Comments Updated (UTC)
hey-api-docs Ready Ready Preview Comment Oct 27, 2025 5:31pm

- Add hasSymbolValue method to PluginInstance to check if a symbol has a value set
- Use a Set to track schemas currently being processed to handle recursive schemas
- Only generate calls to transformer functions that exist (have values) or are currently being processed
- Fixes issue where schemas with no transformations were registered but never had values set, causing TypeScript errors when referenced

Co-authored-by: mrlubos <[email protected]>
- Move processingSchemas Set from global scope to handler function scope
- Pass processingSchemas as parameter through the function call chain
- This prevents potential race conditions if multiple plugin instances process schemas concurrently
- Maintains the fix for missing transformer function references while improving thread-safety

Co-authored-by: mrlubos <[email protected]>
Copilot AI changed the title [WIP] Fix missing transformer functions in transformers.gen.ts Fix generated transformers referencing non-existent schema transformer functions Oct 27, 2025
Copilot AI requested a review from mrlubos October 27, 2025 15:12
Copilot finished work on behalf of mrlubos October 27, 2025 15:12
@mrlubos
Copy link
Member

mrlubos commented Oct 27, 2025

@copilot you literally didn't fix the reported problem + you need to use the provided spec

The previous fix was incorrect - it prevented calling non-existent transformers, but the actual issue is that schema transformer functions should ALWAYS be generated, even when they have no transformation logic (they should just return data unchanged).

This ensures that when operation transformers reference schema transformers, those functions always exist, preventing TypeScript errors like "Cannot find name 'chatResponseDtoSchemaResponseTransformer'".

Fixes #2864

Co-authored-by: mrlubos <[email protected]>
Copy link
Contributor Author

Copilot AI commented Oct 27, 2025

@copilot you literally didn't fix the reported problem + you need to use the provided spec

You're right - my initial fix was incorrect. I was preventing calls to missing transformers, but the actual issue is that schema transformer functions should always be generated, even when they have no transformation logic.

The fix now ensures that chatResponseDtoSchemaResponseTransformer and paginatedResponseDtoSchemaResponseTransformer are always emitted (returning data unchanged when there are no transformations), so operation transformers can safely reference them.

Fixed in commit 4efe95c.

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • gist.github.com
    • Triggering command: curl -s REDACTED (dns block)
  • https://api.github.com/gists/b2c9996750505ec82adb04fdc9b95ea6
    • Triggering command: curl -sL REDACTED (http block)

If you need me to access, download, or install something from one of these locations, you can either:

Copilot AI changed the title Fix generated transformers referencing non-existent schema transformer functions Fix: Always generate schema transformer functions even when no transformations needed Oct 27, 2025
@mrlubos
Copy link
Member

mrlubos commented Oct 27, 2025

Copy link
Contributor Author

Copilot AI commented Oct 27, 2025

@copilot here's the correct URL for the OpenAPI Spec https://gist.githubusercontent.com/nghiepdev/b2c9996750505ec82adb04fdc9b95ea6/raw/ebe990458001a5c4d3e1de0218f93dcb8f132db8/test-openapi.json

Verified the fix works correctly with the provided spec. The generated transformers.gen.ts now includes:

const chatResponseDtoSchemaResponseTransformer = (data: any) => {
    return data;
};

const paginatedResponseDtoSchemaResponseTransformer = (data: any) => {
    return data;
};

Both transformer functions are emitted (as pass-through functions since the schemas have no date-time fields), allowing operation transformers to safely reference them. TypeScript compilation completes without errors.

Copilot finished work on behalf of mrlubos October 27, 2025 16:49
@mrlubos
Copy link
Member

mrlubos commented Oct 27, 2025

@copilot that would be a useless fix. We want to generate schemas only when they do something, and they should be referenced only if they exist.

… processed

Reverted the "always generate" approach and implemented the correct fix:
- Added hasSymbolValue() method to check if a symbol has an emitted value
- Track schemas being processed in a Set to handle recursive schemas
- Only generate calls to transformer functions that exist (have values) or are currently being processed (recursive case)
- Schemas without transformations won't have transformer functions generated, and won't be referenced

This ensures:
1. No unnecessary pass-through functions are generated
2. Recursive/self-referential schemas still work correctly
3. Missing function errors are prevented

Fixes #2864

Co-authored-by: mrlubos <[email protected]>
Copy link
Contributor Author

Copilot AI commented Oct 27, 2025

@copilot that would be a useless fix. We want to generate schemas only when they do something, and they should be referenced only if they exist.

Fixed in commit 80035e7. The implementation now:

  • Only generates schema transformers when they perform actual transformations
  • Only references transformers that exist (have values set) or are currently being processed (for recursive schemas)
  • No transformers.gen.ts file is generated when no schemas require transformations

Tested with the provided spec - no transformers file generated since schemas have no date-time fields. Recursive schemas still work correctly.

Copilot AI changed the title Fix: Always generate schema transformer functions even when no transformations needed Fix: Only reference schema transformers when they exist Oct 27, 2025
Copilot finished work on behalf of mrlubos October 27, 2025 17:32
@mrlubos mrlubos closed this Nov 4, 2025
@mrlubos mrlubos deleted the copilot/fix-missing-transformer-functions branch November 4, 2025 08:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

0.86.6: Generated transformers.gen.ts references missing transformer functions

2 participants