Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Oct 21, 2025

Problem

When using the SDK plugin with asClass: true, the code generator would fail with "Maximum call stack size exceeded" error for certain OpenAPI specifications. This issue occurred when operationIds contained path segments that, after PascalCase transformation, created duplicate class names or circular class hierarchies.

Root Cause

The issue had two related causes:

  1. Duplicate class names in path: When an operationId like api/v1/test/getData was combined with a tag like Test, the generated class path would be:

    • Before transformation: ["Test", "api", "v1", "test"]
    • After PascalCase: ["Test", "Api", "V1", "Test"]

    This created a self-referencing class structure where Test appeared twice in the hierarchy.

  2. Circular class hierarchies: Multiple operations with overlapping class segments could create cycles. For example:

    • Operation A creates: AccountingCompanies → Api → VVersionApiVersion → Odata
    • Operation B creates: Odata → ... → AccountingCompanies

    This resulted in infinite recursion during class generation.

Solution

This PR implements two fixes:

1. Deduplicate class names in operation paths (operation.ts)

After transforming path segments to PascalCase, the code now removes duplicate class names while preserving order:

const uniquePath: Array<string> = [];
const seen = new Set<string>();
for (const name of transformedPath) {
  if (!seen.has(name)) {
    seen.add(name);
    uniquePath.push(name);
  }
}

2. Add cycle detection to parent-child relationships (plugin.ts)

Before adding a child class to a parent, the code now checks if it would create a cycle:

const wouldCreateCycle = (childId: number, ancestorId: number): boolean => {
  const child = sdkClasses.get(childId);
  if (!child) return false;
  if (child.id === ancestorId) return true;
  for (const grandchildId of child.classes) {
    if (wouldCreateCycle(grandchildId, ancestorId)) {
      return true;
    }
  }
  return false;
};

if (!wouldCreateCycle(symbolCurrentClass.id, symbolParentClass.id)) {
  parentClass.classes.add(symbolCurrentClass.id);
}

Testing

  • ✅ Created test cases with operationIds that reproduce the issue
  • ✅ Verified the fix works with the original 37k-line OpenAPI spec from the issue
  • ✅ All 910 existing tests pass
  • ✅ Manually verified generated code has correct class hierarchies with no circular references

Fixes #2627

Original prompt

This section details on the original issue you should resolve

<issue_title>Maximum call stack size exceeded when using asClass: true</issue_title>
<issue_description>### Description

Maximum call stack size exceeded when using asClass: true

Reproducible example or configuration

import { defineConfig } from '@hey-api/openapi-ts';

export default defineConfig({
  input: 'http://localhost:5038/swagger/1.0/swagger.json',
  output: 'src/_generated',
  plugins: [{ name: '@hey-api/typescript' }, { name: '@hey-api/sdk', asClass: true }],
});

OpenAPI specification (optional)

https://gist.github.com/hekystyle/86c87cb8255fe85dab9c4844283477d3

System information (optional)

OS: Windows 11
bun: 1.2.22
NodeJS: 24.10.0</issue_description>

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

Fixes #2815


✨ 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 21, 2025

⚠️ No Changeset found

Latest commit: 17bb4be

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 21, 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 21, 2025 4:03pm

💡 Enable Vercel Agent with $100 free credit for automated AI reviews

- Remove duplicate class names from operation path to prevent self-references
- Add cycle detection to prevent circular class hierarchies
- Fixes issue where operationIds with path segments that transform to same PascalCase name as tags created circular references

Co-authored-by: mrlubos <12529395+mrlubos@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix maximum call stack size exceeded with asClass option Fix maximum call stack size exceeded when using asClass: true Oct 21, 2025
Copilot AI requested a review from mrlubos October 21, 2025 16:08
Copilot finished work on behalf of mrlubos October 21, 2025 16:08
@codecov
Copy link

codecov bot commented Oct 21, 2025

Codecov Report

❌ Patch coverage is 0% with 35 lines in your changes missing coverage. Please review.
✅ Project coverage is 29.13%. Comparing base (efa2e87) to head (17bb4be).

Files with missing lines Patch % Lines
...ages/openapi-ts/src/plugins/@hey-api/sdk/plugin.ts 0.00% 20 Missing ⚠️
...s/openapi-ts/src/plugins/@hey-api/sdk/operation.ts 0.00% 15 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##             main    #2816      +/-   ##
==========================================
- Coverage   29.15%   29.13%   -0.03%     
==========================================
  Files         391      391              
  Lines       38104    38131      +27     
  Branches     2272     2272              
==========================================
  Hits        11109    11109              
- Misses      26965    26992      +27     
  Partials       30       30              
Flag Coverage Δ
unittests 29.13% <0.00%> (-0.03%) ⬇️

Flags with carried forward coverage won't be shown. Click here to find out more.

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.
  • 📦 JS Bundle Analysis: Save yourself from yourself by tracking and limiting bundle sizes in JS merges.

@pkg-pr-new
Copy link

pkg-pr-new bot commented Oct 21, 2025

Open in StackBlitz

npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/codegen-core@2816
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/nuxt@2816
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/openapi-ts@2816
npm i https://pkg.pr.new/hey-api/openapi-ts/@hey-api/vite-plugin@2816

commit: 17bb4be

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.

Maximum call stack size exceeded when using asClass: true

2 participants