Skip to content

Alloy infrastructure, mutation pipeline, and simple type components#90

Merged
swatkatz merged 13 commits into
feature/graphqlfrom
fionabronwen/graphql-foundation-skeleton
Jun 9, 2026
Merged

Alloy infrastructure, mutation pipeline, and simple type components#90
swatkatz merged 13 commits into
feature/graphqlfrom
fionabronwen/graphql-foundation-skeleton

Conversation

@FionaBronwen

Copy link
Copy Markdown

Merge PRs #77, #83, and #79 into the feature/graphql branch.

These branches were stacked and accidentally merged into each other instead of feature/graphql.

Swati Kumar and others added 13 commits June 8, 2026 20:24
- Build: @alloy-js/graphql (linked local), JSX transpilation via alloy
  build, rollup plugin for vitest
- Context: GraphQLSchemaContext provider with TypeGraph from mutation
  engine (single source of truth, no duplicate interface)
- Components: Field and OperationField — thin translators from mutated
  types to Alloy GraphQL SDL components. Use resolveGraphQLTypeName for
  type names and decorator-based nullable state. No type-expression
  render-prop indirection (mutation pipeline handles all transforms).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- Delete legacy emitter infrastructure (graphql-emitter.ts, registry.ts,
  schema-emitter.ts, type-maps.ts, types.d.ts)
- New $onEmit: type-usage → mutation engine → buildTypeGraph → render (stub)
- Add schema-mutator.ts: walks namespace, mutates all types via engine,
  produces TypeGraph. No pre-classified buckets — renderer classifies at
  render time using decorators and typeUsage.
- Add empty-schema diagnostic when no operations exist
- Emitter test updated to verify pipeline runs (rendering TBD)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Tests verify:
- Mutated models/enums/scalars/unions/operations appear in TypeGraph
- Unreachable types are excluded when omitUnreachableTypes is true
- All declared types included when omitUnreachableTypes is false
- T | null unions are not registered in the TypeGraph
- Union wrapper models (scalar variants) are included
- Array models are skipped (they're list types, not object types)

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
The mutation engine already handles T | null unions correctly (replaces
with inner type). The pre-check was a premature optimization that added
code without benefit — engine.mutate() is cached.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Without this, navigateTypesInNamespace on the global namespace visits
built-in TypeSpec scalars (string, int32, etc.) from the TypeSpec
sub-namespace, adding them to the TypeGraph unnecessarily.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
After creating synthetic wrapper models for scalar union variants, replace
the variant's type reference with the wrapper model. This makes the union
self-contained — all variant types are now Models, so the renderer can use
variant.type.name uniformly without reconstructing wrapper names.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Thin rendering components that consume mutated types from the TypeGraph and
delegate to @alloy-js/graphql. No render-time name logic — all names come
from type.name (set by the mutation engine).

Includes test infrastructure: renderToSDL helper and vitest config for
deduping @alloy-js/core and graphql across linked packages.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Models used as operation parameters now get a second mutation pass with
GraphQLTypeContext.Input, producing the Input-suffixed variant (e.g.,
BookInput) alongside the Output variant in the TypeGraph.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Only produce an Output mutation for models actually used as output (or
unreferenced models defaulting to output). Input-only models now only get
an Input mutation, preventing spurious output types in the TypeGraph.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When two different TypeSpec types produce the same GraphQL name (e.g.,
explicit model BookInput + model Book used as input both yielding
"BookInput"), report an error diagnostic instead of silently overwriting
in the TypeGraph.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
When creating a synthetic flattened union (after null-stripping or scalar
wrapping), clone the source union instead of creating from scratch. This
preserves decorators and the AST node, so getDoc/getDeprecationDetails
work on the flattened result.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
- GraphQLUnion narrows Union.name to string (mutation engine guarantee)
- $.model.is() typekit guard for variant types (established repo pattern)
- No runtime throws — type safety from interface contract + narrowing

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Add simple type components (Enum, Scalar, Union) and input model splitting
@FionaBronwen
FionaBronwen removed the request for review from steverice June 9, 2026 20:24
@swatkatz
swatkatz merged commit 2c388a2 into feature/graphql Jun 9, 2026
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.

2 participants