Skip to content

feat(module): generate a module's files in the SDK - #26

Open
TomChv wants to merge 2 commits into
feat/module-config-writersfrom
feat/module-gen-dang
Open

feat(module): generate a module's files in the SDK#26
TomChv wants to merge 2 commits into
feat/module-config-writersfrom
feat/module-gen-dang

Conversation

@TomChv

@TomChv TomChv commented Aug 11, 2026

Copy link
Copy Markdown
Member

Assemble a module's generated tree here rather than routing through the engine's
built-in TypeScript runtime: bindings from the module-facing schema, the sdk/
directory the runtime mounts as @dagger.io/dagger, the dispatch entrypoint, and
the config files.

The schema is ModuleSource.introspectionSchemaJSON — the same builder call the
engine makes before handing the file to Codegen, so this is the same input, not
an approximation.

The scan runs with the compiler installed beside the introspector rather than in
the module tree: a bare import resolves from the importing file's directory, so
the module's own node_modules is not somewhere the scanner would look.

Exposed as generateModuleLocal and left unwired: Mod.generate still delegates to
the engine while the two are compared. ModConfig.runtime becomes public, since
codegen needs to know which config files a module wants and the detection
already lived there.

Comparing the two outputs turned up three places where our generator — ported
with the client codegen, from an older upstream commit than the engine we pin —
diverged from the engine's:

  • Enum members were named with strcase.ToCamel, which mangles consecutive
    capitals: EStarGZ became EstarGz where the engine emits EStarGz. Module code
    written against the engine's bindings would not compile against ours. Upstream
    had already fixed this by routing formatEnum through the same PascalCase rule
    as the rest of the generator; the corrected helper was sitting unused in our
    copy.
  • arguments was missing from the JS keyword list, so a field of that name came
    out unescaped instead of as arguments_.
  • The entrypoint emitted no source maps. The scan reports a location for every
    declaration and our typedef structs dropped all but the object's on the floor;
    the renderer had no sourceMapExpr at all.

With those fixed, every generated file matches the engine's byte-for-byte for
the same fixture, except core.js — ours is built from the vendored lockfile and
is 1.1MB smaller than the engine's, which builds without one. Verified for the
generate/app fixture by generating it both ways, and for the generate-deps
fixtures by calling a function on the result, which exercises the whole tree,
dependency bindings included, through the engine runtime.

Signed-off-by: Tom Chauveau tom@dagger.io


Stack created with GitHub Stacks CLIGive Feedback 💬

@TomChv
TomChv force-pushed the feat/module-gen-dang branch from 63b2b95 to c05d15b Compare August 19, 2026 14:53
@TomChv
TomChv force-pushed the feat/module-gen-dang branch from c05d15b to 9757654 Compare August 21, 2026 12:11
TomChv added 2 commits August 25, 2026 18:04
Generating a fixture both ways and diffing turned up three places where our
generator — ported with the client codegen, from an older upstream commit than
the engine we pin — produces different output from the engine's:

- Enum members were named with strcase.ToCamel, which mangles consecutive
  capitals: EStarGZ became EstarGz where the engine emits EStarGz. Module code
  written against the engine's bindings would not compile against ours.
  Upstream had already fixed this by routing formatEnum through the same
  PascalCase rule as the rest of the generator; the corrected helper was
  sitting unused in our copy.
- `arguments` was missing from the JS keyword list, so a field of that name
  came out unescaped instead of as `arguments_`.
- The entrypoint emitted no source maps. The scan reports a location for every
  declaration and our typedef structs dropped all but the object's on the
  floor; the renderer had no sourceMapExpr at all. Taken from the beta.9 tag
  along with the register template that calls it — our copies had no local
  changes to preserve, unlike the binding templates, which carry the client
  work developed here.

Regenerating the library bindings and rebuilding the bundle propagates the enum
fix into core.d.ts, which had inherited the old casing.

With this, every generated file matches the engine's byte-for-byte for the
same fixture, except core.js — ours is built from the vendored lockfile and is
1.1MB smaller than the engine's, which builds without one.

Signed-off-by: Tom Chauveau <tom@dagger.io>
Assemble a module's generated tree here rather than routing through the
engine's built-in TypeScript runtime: bindings from the module-facing schema,
the sdk/ directory the runtime mounts as @dagger.io/dagger, the dispatch
entrypoint, and the config files.

The schema is ModuleSource.introspectionSchemaJSON — the same builder call the
engine makes before handing the file to Codegen, so this is the same input, not
an approximation.

The scan runs with the compiler installed beside the introspector rather than
in the module tree: a bare import resolves from the importing file's directory,
so the module's own node_modules is not somewhere the scanner would look.

Exposed as generateModuleLocal and left unwired: Mod.generate still delegates
to the engine while the two are compared. Verified for the generate/app fixture
by generating it both ways — every file matches byte-for-byte except core.js
(§ the lockfile difference) — and by generating the generate-deps fixtures and
calling a function on the result, which exercises the whole tree, dependency
bindings included, through the engine runtime.

ModConfig.runtime becomes public: codegen needs to know which config files a
module wants, and the detection already lived there.

Signed-off-by: Tom Chauveau <tom@dagger.io>
@TomChv
TomChv force-pushed the feat/module-gen-dang branch from 9757654 to c4a2399 Compare August 25, 2026 16:06
@TomChv
TomChv marked this pull request as ready for review August 25, 2026 16:15
@TomChv TomChv changed the title feat/module gen dang feat(module): generate a module's files in the SDK Aug 25, 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.

1 participant