Skip to content

[typespec-ts] wip split emitter into adapter / codemodel / codegen#3981

Draft
maorleger wants to merge 24 commits into
Azure:mainfrom
maorleger:squad-rewrite
Draft

[typespec-ts] wip split emitter into adapter / codemodel / codegen#3981
maorleger wants to merge 24 commits into
Azure:mainfrom
maorleger:squad-rewrite

Conversation

@maorleger
Copy link
Copy Markdown
Member

@maorleger maorleger commented May 18, 2026

This is the refactor I have wanted for the TypeSpec TS emitter for a while: make it boring

Before this branch, the modular emitter was reading TCGC types, shaping emitter state, and rendering with ts-morph all over src/modular/. That works until it doesn't :) and it has made it harder than I want to reason about boundaries, test the adaptation layer directly, or move code around without accidentally dragging TCGC assumptions everywhere.

The things I want from this migration:

  • Mirror the three-layer pipeline that already seems to work well in Rust/Go: TCGC -> adapter -> code model -> codegen
  • Keep the swap in-place so we can keep validating against the existing emitter behavior instead of incubating a parallel implementation forever
  • Make it much more obvious where a bug belongs: TCGC adaptation, pure IR shaping, or ts-morph rendering
  • Make the eventual cleanup / deletion story less painful once the dust settles

This PR builds off of #3970, which was the seed POC for the separation. I also used my local ~/workspace/emitter-chain/go-rust.md notes pretty heavily while moving this over.

What is actually wired now is the in-place swap for stages 0-6 of that migration. src/tcgcadapter/adapter.ts is now the only place in the new path that imports TCGC directly and adapts it into the new IR in src/codemodel/index.ts. From there src/codegen/ owns the ts-morph rendering for clients, operations, classical clients/operations, models, enums, unions, response types, API options, LRO helpers, and index files. In other words, I am trying pretty hard to keep "what the SDK is" separate from "how we print it".

I could have hidden this behind a feature flag or kept the new path additive for longer; however, I would rather do the swap in place and keep one source of truth if possible. The migration is still very much WIP though, and I don't want to oversell it.

Still not done in this PR:

  • ContextManager is still an ambient singleton instead of explicit data flow
  • the adapter still leans on a few helpers from src/modular/helpers/
  • there is still no dedicated src/tcgcadapter/naming.ts module yet

Validation on this branch is green:

  • pnpm build
  • 662 unit tests passing
  • modular + azure-modular integration passing
  • smoke passing

Scope-wise this is 25 files under packages/typespec-ts/ plus a tiny .gitignore housekeeping change for local team-state files. The last commit is just that housekeeping and not part of the architectural story.

Co-authored-by: Copilot 223556219+Copilot@users.noreply.github.com

maorleger and others added 14 commits May 18, 2026 17:25
Tasks executed:
1. ✅ Decisions archive: No archival needed (decisions.md < 20KB threshold)
2. ✅ Decision inbox: Merged ripley-staged-refactor-plan.md + copilot-directive into decisions.md
   - Summary of 9-stage pipeline refactor (stages 1–9, stage 10 dropped)
   - Key decisions: swap-in-place, adapter testing focus, readability-first organization
   - Directives: skip lint guard, focus adapter tests, skip package separation
3. ✅ Orchestration log: Created 2026-05-15T2238Z-ripley.md (not git-tracked per .gitignore)
4. ✅ Session log: Created 2026-05-15T2238Z-refactor-plan.md (not git-tracked per .gitignore)
5. ✅ Cross-agent history: Appended Ripley plan summary to dallas/history.md and parker/history.md
6. ✅ History summarization: All history.md < 15KB (no summarization needed)
7. ✅ Git commit: Staged 3 files (decisions.md, dallas/history.md, parker/history.md)
8. ✅ Health report: decisions.md 0→1710 bytes, inbox count 2→0 (after merge)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ne (Stage 1)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ns (Stage 2)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
- Fix Stage 3 adapter: add missing isRLCMultiEndpoint import
- Fix child TSClient construction: add allowOptionalSubscriptionId and usesNamespacedContextType properties
- Rewrite adaptFunctionDeclaration for safe handling of OptionalKind types from ts-morph
- Update adapter test expectations for new IR properties (TSClient 16→18, TSMethod 9→17)
- Validate: build ✅, unit tests ✅ (662/662 passing), format ✅
- Document session: .squad/log/2026-05-16T0107Z-stage3-scribe-fixes.md
- Update decisions.md: Stage 2/3 completion notes

Stage 3 now unblocked. Parker ready to implement model/enum/union adapters.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…Stage 4)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…line (Stage 5)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…e (Stage 6a)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ts, serializer placeholders

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…ular codegen

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@maorleger maorleger changed the title Squad rewrite WIP: simplify emitter architecture May 18, 2026
@maorleger maorleger changed the title WIP: simplify emitter architecture [typespec-ts] wip split emitter into adapter / codemodel / codegen May 18, 2026
maorleger and others added 8 commits May 18, 2026 22:40
High-level architecture map for the typespec-ts emitter:  entry,
RLC vs Modular split, the three-layer TCGC adapter -> code model -> codegen
pipeline, framework/reference system, two end-to-end flows, and current
known follow-ups.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
…sion

package.json continued to advertise ./api/<resource> subpath exports, but the rewritten root index only re-exported ./api/index.js. That left the source graph unable to reach those barrels, so the dist subpath files and root OptionalParams re-exports were never produced during build.

Restore the missing top-level api/** recursion in root index emission so the producer once again reaches every generated api subbarrel instead of trying to clean things up downstream.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
The rewritten client-context renderer was treating every api-version parameter as required based on isApiVersion alone, even when the adapter had already recorded a client default and left the parameter optional. That changed generated *Context interfaces from apiVersion?: string to apiVersion: string for defaulted clients.

Make requiredness follow the adapted TSClientParameter metadata instead of the api-version marker, and lock it in with a modular unit test that renders the new pipeline's client context for a versioned client with a defaulted api-version.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… models renderer

The new pipeline's models renderer was still walking the legacy global emit queue, so it bypassed the adapter's filtered TSCodeModel.models/enums/unions set and reintroduced paging result types like *ListResult onto the public surface.

Switch file selection to the filtered IR and look raw sdk types up only for the legacy declaration/serializer helpers that are still shared with src/modular/emitModels.ts. The production path remains src/codegen/models.ts; the legacy file stays as a rendering helper while this removes the direct TCGC dependency from the codegen layer.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Apply formatter output for the client-context and model-renderer regression fixes after re-running build and unit validation.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
… placeholders

The new filtered-IR renderer in src/codegen/models.ts only walked
codeModel.models/enums/unions and skipped array/dict helper types from the
emitQueue. The serializer builders (buildSerializerFunction.ts,
buildDeserializerFunction.ts) still emit refkey(type, 'serializer') /
refkey(type, 'deserializer') references for those helpers. With no matching
declaration registered, the binder left __PLACEHOLDER_*__ tokens unresolved —
causing 26 TS2304 errors in the SCVMM and NetworkAnalytics repros.

Strategy A: walk emitQueue entries of kind 'array'/'dict' and call emitType()
for each, mirroring what the legacy emitTypes() in emitModels.ts did. This
registers the serializer/deserializer refkeys so the binder can substitute them.

A TODO comment and .squad/decisions/inbox/dallas-models-helpers.md document
the follow-up to migrate these helper types into TSCodeModel IR, removing the
emitQueue side-channel dependency from the codegen layer.

Validated:
- pnpm build: clean
- npm run unit-test (typespec-ts): 664/664 passed
- NetworkAnalytics.Management regen: zero __PLACEHOLDER_ matches, zero TS2304

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
maorleger and others added 2 commits May 20, 2026 21:18
Implement Strategy B for modular model helpers by adapting array, dict, and named nullable wrapper types into TSCodeModel.helperTypes and consuming that IR from codegen/models.ts instead of the legacy emitQueue patch.

This keeps helper registration in the adapter, removes the dead Strategy A loop from the renderer, and leaves the extensible-enum follow-up (U1) explicitly scoped to adaptEnums.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Co-authored-by: Copilot <223556219+Copilot@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