feat: in-memory generator context seam (fix OpenAPI/AsyncAPI in-memory drift)#420
Merged
Conversation
…Schema Downstream in-memory callers (the platform's generateInMemory/preview and the browser bundle) re-implemented document loading instead of reusing the CLI loaders, so they silently drifted from `codegen generate`. Two concrete drifts: - OpenAPI: in-memory paths dereferenced without calling reflectComponentSchemaNames, so array items lost their component name and collapsed to `ItemsItem[]` instead of e.g. `TransactionModel[]`. - AsyncAPI: in-memory callers used a bare Parser without the shared schema parsers (Avro/OpenAPI/RAML/Protobuf) and looser diagnostics handling. Expose a single in-memory seam so callers never re-implement parsing: - add loadOpenapiFromMemory, sharing the exact dereference + reflectComponentSchemaNames normalization with the local-file loader - add realizeInMemoryGeneratorContext, the in-memory counterpart of realizeGeneratorContext, dispatching to the load*FromMemory loaders - accept a raw spec string in loadJsonSchemaFromMemory for symmetry - export the seam and the three in-memory loaders from the public entry - fix the browser generate path to also call reflectComponentSchemaNames - ignore the local-only playground harness in eslint (mirrors .gitignore) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
The browser generate path hand-rolled its own OpenAPI parse (parse + dereference + reflectComponentSchemaNames) and JSON Schema string parsing, duplicating the Node in-memory loaders. Route both through the shared loadOpenapiFromMemory / loadJsonSchemaFromMemory so the browser playground and the Node in-memory seam use one implementation and cannot drift. AsyncAPI stays on loadAsyncapiFromMemoryBrowser: the Node loader pulls in @asyncapi/parser plus the Avro/OpenAPI/RAML/Protobuf schema parsers, which the browser bundle deliberately shims away. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
jonaslagoni
approved these changes
Jul 16, 2026
Contributor
|
🎉 This PR is included in version 0.77.0 🎉 The release is available on: Your semantic-release bot 📦🚀 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
In-memory code generation is already a first-class capability of this package — the browser bundle (
src/browser/generate.ts, the website playground) generates from an in-memory spec string, andloadAsyncapiFromMemory/loadJsonSchemaFromMemoryalready existed. The problem: every in-memory caller (the browser bundle, and any programmatic consumer) re-implemented document loading by hand instead of reusing one path, so they silently drifted fromcodegen generate. Two real drifts found:reflectComponentSchemaNames(the fix(openapi): preserve component schema names through dereferencing #416 fix), so an array of$refitems lost the component name and generateditems: ItemsItem[]instead ofitems: TransactionModel[].Parserwithout the shared schema parsers (Avro/OpenAPI/RAML/Protobuf) and with looser diagnostics thanloadAsyncapiDocument.What
Make in-memory generation a single, shared path rather than something each consumer re-derives:
loadOpenapiFromMemory(specString)— shares the exactdereference+reflectComponentSchemaNamesnormalization with the local-file branch ofloadOpenapiDocument.realizeInMemoryGeneratorContext({ configuration, specificationDocument })— the in-memory counterpart of the already-publicrealizeGeneratorContext; realizes config and dispatches toload{Openapi,Asyncapi,JsonSchema}FromMemoryoninputType, using the same root-level virtual paths as the browser path.loadJsonSchemaFromMemorynow also accepts a raw spec string (backward compatible with the object form).src/index.ts).src/browser/generate.tsnow routes OpenAPI and JSON Schema through the sharedloadOpenapiFromMemory/loadJsonSchemaFromMemoryinstead of its own hand-rolled parse — deleting the duplicated OpenAPI parse (which had the sameItemsItembug) and JSON Schema parse.playground/harness in eslint (mirrors.gitignore).Why this belongs in the CLI (not a downstream-only hook)
Anticipating the fair question "is this just for an external consumer?" — no:
CLAUDE.md: "CLI and library live in the same package undersrc/"). It already exportsrealizeConfiguration,runGenerators,realizeGeneratorContext, and the loaders.realizeInMemoryGeneratorContextsimply completes that surface as the in-memory twin of the existing publicrealizeGeneratorContext.ItemsItembug. This PR fixes that bug and removes the browser's duplicated parsing.src/browser/generate.ts) and the Node in-memory seam (realizeInMemoryGeneratorContext). This is a de-duplication of logic the CLI already had in three places, not scaffolding for one caller.inputType→loader dispatch and the missingreflectComponentSchemaNames). Centralizing it is the fix.Deliberate asymmetry (documented, not an oversight)
The browser's AsyncAPI path stays on
loadAsyncapiFromMemoryBrowserrather than the shared seam. The NodeloadAsyncapiFromMemorydepends on@asyncapi/parserplus the Avro/OpenAPI/RAML/Protobuf schema parsers, which the browser build intentionally shims away for bundle size/compat. OpenAPI and JSON Schema have no such constraint, so those are shared. The seam itself is Node-side (mirroring the Node-onlyrealizeGeneratorContext); the browser assembles its own context because it must inject a browser-shimmed AsyncAPI parser and drivesrenderGraphdirectly.Testing
npm run build,npm run build:browser, andnpm run lintall clean.npm test: 656 passed, 78 snapshots.items?: TransactionModel[](wasItemsItem[]).loadJsonSchemaFromMemorystill accepts the object form (existing browser/tests unchanged).🤖 Generated with Claude Code