Skip to content

fix: don't stub every field when a mapper type is unresolvable#455

Open
GlebYavorski wants to merge 1 commit into
eddeee888:masterfrom
GlebYavorski:fix/smart-unresolvable-mapper-stub-injection
Open

fix: don't stub every field when a mapper type is unresolvable#455
GlebYavorski wants to merge 1 commit into
eddeee888:masterfrom
GlebYavorski:fix/smart-unresolvable-mapper-stub-injection

Conversation

@GlebYavorski

Copy link
Copy Markdown

Summary

Fixes #446.

When a mapper aliases a type whose import cannot be resolved (a TypeScript error type — e.g. a Prisma/generated client that hasn't been generated yet, or a module not installed on a fresh checkout), fixObjectTypeResolvers ('smart' and 'fast') treated the mapper as having zero fields and injected a resolver is required because … does not stub for every field of the schema type. This silently overwrites hand-maintained resolver files with stubs that return Promise<void> and break tsc.

Root cause

getNodePropertyMap derives the mapper's properties from node.getType().getProperties(), which returns [] for an error type. The generator couldn't tell "mapper genuinely has no fields" apart from "mapper type could not be resolved", so every field took the if (!mapperProperty) branch and got a stub.

Fix

  • Add isNodeTypeUnresolved, which detects the TypeScript error type (intrinsic type named error). This is distinct from a real any (intrinsicName === 'any') and from an empty object type (not an intrinsic type at all), so it does not misfire on those.
  • In both the smart and fast paths, when the mapper's declaration node is unresolved, skip stub generation for that mapper (leaving existing resolvers untouched) and emit a logger.warn naming the mapper, so the real problem — the unresolved import — surfaces.
  • Genuinely empty mappers (type FooMapper = {}) still generate stubs as before.

Tests

  • Unit tests for isNodeTypeUnresolved covering: unresolvable import → true; empty {}false; explicit anyfalse; resolved import → false; undefined node → false.
  • Integration tests for getGraphQLObjectTypeResolversToGenerate (both smart and fast): an unresolvable mapper produces no stubs and warns once; a genuinely empty mapper still stubs every field and does not warn.

nx test/lint/build typescript-resolver-files all pass. Existing e2e snapshots are unaffected (behavior only changes for unresolvable mappers, which no fixture has).

A changeset (patch) is included.

`fixObjectTypeResolvers` ('smart' and 'fast') built a mapper's property
set from `getProperties()`, which returns `[]` for a TypeScript *error
type* (an unresolvable import, e.g. a client that hasn't been generated
yet). An error type was therefore indistinguishable from an empty
mapper, so a resolver stub was injected for every field, silently
overwriting hand-maintained resolver files with broken `Promise<void>`
stubs.

Detect the error type via `isNodeTypeUnresolved` before deriving the
property map; when the mapper is unresolvable, skip stub generation
(leaving existing resolvers untouched) and emit a warning naming the
mapper so the real problem — the unresolved import — surfaces.
Genuinely empty mappers (`type FooMapper = {}`) still stub as before.

Fixes eddeee888#446

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@changeset-bot

changeset-bot Bot commented Jul 16, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 8301e93

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 1 package
Name Type
@eddeee888/gcg-typescript-resolver-files Patch

Not sure what this means? Click here to learn what changesets are.

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

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.

fixObjectTypeResolvers: 'smart' treats an unresolvable mapper type as an empty mapper and injects a stub for every field

1 participant