Skip to content

fix(cli): register intersection types in discoveredTypes and improve cycle detection#219

Merged
izumin5210 merged 7 commits into
mainfrom
fix/cycle-detection-symbol-leak
Mar 12, 2026
Merged

fix(cli): register intersection types in discoveredTypes and improve cycle detection#219
izumin5210 merged 7 commits into
mainfrom
fix/cycle-detection-symbol-leak

Conversation

@izumin5210
Copy link
Copy Markdown
Owner

@izumin5210 izumin5210 commented Mar 12, 2026

Why

Non-exported intersection type aliases (e.g., type Foo = A & B) were not registered in discoveredTypes, causing two issues:

  1. Recursive intersection types triggered cycle detection in tryExtractAsInlineObject, silently falling back to an "Unknown" reference type — potentially leaking internal TypeScript symbols into the schema
  2. Non-exported intersection types were expanded as inline objects with auto-generated names (e.g., ContainerMixed) instead of using their original alias names (NotBranded)

Summary

  • Register non-exported intersection type aliases in discoveredTypes using the same logic as the alias expansion path, so recursive references resolve correctly and original alias names are preserved
  • Add CYCLE_DETECTED diagnostic code and FieldTypeResolverDiagnostic infrastructure as a safety net — when a cycle is detected with no valid reference target (not in knownTypeNames or discoveredTypes), emit a warning and skip the field instead of silently falling back
  • Improve cycle detection to check type.aliasSymbol as fallback (intersection types may lack type.symbol)
  • Add intersection-type-discovery golden test case verifying recursive intersection type resolution
  • Update branded-type-not-branded golden snapshots to reflect improved naming

Test plan

  • intersection-type-discovery golden test: non-exported recursive intersection type resolves correctly with original alias name
  • branded-type-not-branded golden test: updated to reflect alias name usage
  • All 464 golden tests pass
  • Type check passes

🤖 Generated with Claude Code

The cycle detection in `tryExtractAsInlineObject` used
`type.symbol.getName()` directly, which could return internal
TypeScript symbols like `__type` or `__object`. Now filters
through `isInternalTypeSymbol` to prevent them from leaking
into the generated schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@chatgpt-codex-connector
Copy link
Copy Markdown

You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard.

Instead of silently falling back to "Unknown" reference type when a
cycle is detected with an internal symbol name, emit a CYCLE_DETECTED
warning diagnostic and return never type to skip the field.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

Add test case that verifies CYCLE_DETECTED warning is emitted when a
non-exported recursive intersection type creates a cycle. The cyclic
field is skipped and a warning diagnostic is reported.

Also improve cycle detection to check aliasSymbol as fallback and only
return a reference type when the target exists in the schema.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@github-actions

This comment has been minimized.

…ve resolution

Instead of emitting a CYCLE_DETECTED warning and skipping fields,
register non-exported intersection type aliases in discoveredTypes so
recursive references resolve correctly. This also causes non-exported
intersection types to use their original alias names instead of
auto-generated names.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@izumin5210 izumin5210 changed the title fix(cli): guard cycle detection fallback against internal symbol names feat(cli): register intersection types in discoveredTypes and improve cycle detection Mar 12, 2026
izumin5210 and others added 2 commits March 12, 2026 17:19
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-actions

This comment has been minimized.

@github-actions
Copy link
Copy Markdown
Contributor

Code Metrics Report

main (9ed4962) #219 (e1986f5) +/-
Coverage 88.4% 88.4% -0.1%
Test Execution Time 10m34s 10m48s +14s
Details
  |                     | main (9ed4962) | #219 (e1986f5) |  +/-  |
  |---------------------|----------------|----------------|-------|
- | Coverage            |          88.4% |          88.4% | -0.1% |
  |   Files             |             78 |             78 |     0 |
  |   Lines             |           5322 |           5344 |   +22 |
+ |   Covered           |           4708 |           4726 |   +18 |
- | Test Execution Time |         10m34s |         10m48s |  +14s |

Code coverage of files in pull request scope (87.8% → 87.6%)

Files Coverage +/- Status
packages/cli/src/resolver-extractor/extractor/define-api-extractor.ts 88.8% 0.0% modified
packages/cli/src/type-extractor/extractor/field-type-resolver.ts 91.6% -0.7% modified
packages/cli/src/type-extractor/extractor/type-extractor.ts 85.1% -0.2% modified

Reported by octocov

@izumin5210 izumin5210 changed the title feat(cli): register intersection types in discoveredTypes and improve cycle detection fix(cli): register intersection types in discoveredTypes and improve cycle detection Mar 12, 2026
@izumin5210 izumin5210 merged commit 1281654 into main Mar 12, 2026
8 checks passed
@izumin5210 izumin5210 deleted the fix/cycle-detection-symbol-leak branch March 12, 2026 08:38
@github-actions github-actions Bot mentioned this pull request Mar 12, 2026
izumin5210 pushed a commit that referenced this pull request Mar 16, 2026
This PR was opened by the [Changesets
release](https://github.com/changesets/action) GitHub action. When
you're ready to do a release, you can merge this and the packages will
be published to npm automatically. If you're not ready to do a release
yet, that's fine, whenever you add more changesets to main, this PR will
be updated.


# Releases
## @gqlkit-ts/cli@0.7.0

### Minor Changes

- [#207](#207)
[`b6fb6c1`](b6fb6c1)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: support
custom discriminator fields for union type resolution

- [#209](#209)
[`42a5fff`](42a5fff)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: flatten
intersection-expanded union members for discriminator fields

- [#218](#218)
[`9ed4962`](9ed4962)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: map
`unknown` to `JSON` and index signatures to `JSONObject` scalar

### Patch Changes

- [#213](#213)
[`21fa614`](21fa614)
Thanks [@izumin5210](https://github.com/izumin5210)! - docs: add Vercel
AI SDK integration guide

- [#204](#204)
[`d462e79`](d462e79)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: preserve
original type names for external .d.ts types used as union members

- [#192](#192)
[`eed52d2`](eed52d2)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: discover
and register non-exported union member types with original names

- [#194](#194)
[`ee06751`](ee06751)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: add type
annotation to auto-generated resolveType parameter

- [#223](#223)
[`61af8ef`](61af8ef)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: detect
custom scalars inside inline object properties

- [#212](#212)
[`0d102f2`](0d102f2)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: apply
discriminator-aware flattening to inline unions

- [#219](#219)
[`1281654`](1281654)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: register
intersection type aliases in discoveredTypes for recursive resolution

- [#189](#189)
[`28b6214`](28b6214)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: skip fields
with `never` type during schema generation

- [#216](#216)
[`248a06e`](248a06e)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: filter
`__object` internal symbol from generated schema

- [#193](#193)
[`d53a940`](d53a940)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: resolve
`defineResolveType` with auto-generated inline union names

- [#220](#220)
[`55e096a`](55e096a)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: prevent
false-positive cycle detection for shared inline types

- [#225](#225)
[`4c8a3cc`](4c8a3cc)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: preserve
enum prefix stripping for singularized arrays

- [#190](#190)
[`01c09ee`](01c09ee)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: map
string/number literal fields to GraphQL scalar types

- [#191](#191)
[`507ce4b`](507ce4b)
Thanks [@izumin5210](https://github.com/izumin5210)! - feat: map
template literal types to String! in GraphQL schema

- [#203](#203)
[`958d4b0`](958d4b0)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: discover
type aliases transitively in union members

- [#195](#195)
[`2b11608`](2b11608)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: suppress
warnings for typename discrimination fields

- [#205](#205)
[`38f3875`](38f3875)
Thanks [@izumin5210](https://github.com/izumin5210)! - fix: replace
`member${i}` index-based naming fallback with `UNNAMEABLE_UNION_MEMBER`
diagnostic error

Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
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.

1 participant