Skip to content

feat(codegen): TypeScript-only generated bindings (Candid codegen V0)#183

Open
b3hr4d wants to merge 6 commits into
plan/ic-reactor-start-v0from
feat/codegen-typescript-only-v0
Open

feat(codegen): TypeScript-only generated bindings (Candid codegen V0)#183
b3hr4d wants to merge 6 commits into
plan/ic-reactor-start-v0from
feat/codegen-typescript-only-v0

Conversation

@b3hr4d

@b3hr4d b3hr4d commented Jun 20, 2026

Copy link
Copy Markdown
Collaborator

Summary

First concrete step (V0) of the Candid compiler/codegen evolution: @ic-reactor/codegen now emits TypeScript-only generated artifacts. .did remains the source contract and is no longer copied into the frontend folder; parallel .js/.d.ts declaration files are dropped.

New per-canister output

```text
/
generated.ts # typed service types + real idlFactory/init + (optional) reactor & hooks
index.ts # user-owned stable wrapper: export * from "./generated"
```

Config semantics are unchanged:

  • global `outDir` = canisters root → `outDir: "src/canisters" + name: "backend"` → `src/canisters/backend/generated.ts`
  • per-canister `outDir` = exact canister directory → `src/lib/backend/generated.ts`

Changes

  • `generators/declarations.ts` (rewritten):
    • `buildTypedBindings()` — merges `didToTs` type block with the real `didToJs` `idlFactory`/`init` (drops the redundant `declare const` lines and re-annotates the runtime consts inline).
    • `generateGeneratedFile()` — full single-file output (bindings-only, or with inlined reactor/hooks).
    • `generateEntryFile()` — user-owned wrapper re-exporting `./generated`.
  • `generators/reactor.ts`: added `generateReactorBlock()` with an `inlineDeclarations` option (embeds reactor+hooks in `generated.ts` or emits them standalone). `generateReactorFile()`/`generateReactorEntryFile()` kept for backward compatibility; entry wrapper repointed to `./generated`.
  • `pipeline.ts`: writes a single `generated.ts` + manages the user-owned `index.ts`. Preserves the "don't overwrite customized wrapper" and legacy-migration behavior; legacy detection broadened to also migrate old `export * from "./index.generated"` wrappers.
  • `generators/index.ts`: exports updated.
  • Tests/snapshots rewritten for the new layout.

Constraints honored

  • Parser `didToJs`/`didToTs` unchanged (parser tests unaffected).
  • No React imports added to the codegen package itself (only into generated output, as before).
  • CLI / vite-plugin insulated — they consume `runCanisterPipeline` by contract and mock it in tests, so no changes required there.

Verification

  • `pnpm --filter @ic-reactor/codegen test` → 23/23 passing (2 new snapshots).
  • `tsc --noEmit` on `@ic-reactor/codegen` → clean.

Out of scope / follow-up

Checked-in example `index.generated.ts` artifacts, the CLI `--bindgen-only` help text, and codegen/CLI/vite READMEs are intentionally left untouched per the "do not edit generated example artifacts unless tests require it" constraint. They are now stale relative to the new output and should be regenerated/updated in a follow-up.

Relates to the evolution plan in `docs/plans/candid-compiler-codegen-evolution.md`.

b3hr4d added 2 commits June 20, 2026 19:47
…eactorBlock and renaming generated files to generated.ts.

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b23375122e

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

// The TS compiler output ends with `declare const` signatures for the two
// runtime exports. Strip those — the JS implementation provides the values
// and we re-annotate them inline below.
const typeBlock = tsContent

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Strip unused imports from generated .ts files

When a Candid service does not reference principals, didToTs still emits import type { Principal } ...; preserving that declaration block was harmless in .d.ts, but this commit now writes it into generated.ts. Projects with noUnusedLocals enabled, including this repo's base tsconfig, will fail type-checking on simple services like the updated snapshot with TS6196 for the unused Principal import, so the merge step needs to drop unused parser imports or render only imports required by the generated source.

Useful? React with 👍 / 👎.

Comment thread packages/codegen/src/pipeline.ts Outdated
content.includes("createActorHooks(")
(content.includes("Auto-generated by @ic-reactor/codegen") &&
content.includes("createActorHooks(")) ||
content.includes('export * from "./index.generated"')

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P1 Badge Preserve customized legacy wrappers

This broad substring check treats any existing index.ts that still re-exports ./index.generated as disposable and runCanisterPipeline overwrites the whole file with the new default wrapper. The old wrapper explicitly said it was safe to customize, so users who added query factories or app-specific hooks while keeping the re-export will lose that code on their first v4 regeneration; migrate only the exact managed wrapper or rewrite just the export line.

Useful? React with 👍 / 👎.

* Skill install: npx skills add B3Pay/ic-reactor-skills --full-depth --skill ic-reactor-hooks
*/
export * from "./index.generated"
export * from "./generated"

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

P2 Badge Keep legacy reactor wrapper pointing at index.generated

generateReactorFile() is still exported and documented as the backward-compatible standalone index.generated.ts generator, but the companion generateReactorEntryFile() now returns an index.ts that re-exports ./generated. Any advanced caller that pairs these two public helpers as before will write index.generated.ts and then an entrypoint that imports a missing generated.ts, breaking the generated canister module.

Useful? React with 👍 / 👎.

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