Skip to content

perf(core): walk each schema and operation once in a node-outer generate loop - #3829

Merged
stijnvanhulle merged 3 commits into
mainfrom
claude/kubb-issue-3812-7ekj69
Jul 18, 2026
Merged

perf(core): walk each schema and operation once in a node-outer generate loop#3829
stijnvanhulle merged 3 commits into
mainfrom
claude/kubb-issue-3812-7ekj69

Conversation

@stijnvanhulle

Copy link
Copy Markdown
Collaborator

🎯 Changes

Closes #3812.

#runGenerators looped plugin-outer, so it re-traversed the shared schemas and operations arrays once per plugin and paid the macro and option resolution walk plugins × nodes times. This inverts the loop to node-outer: each schema is visited once and each operation once, and the node fans out to the matching generators of every plugin in dependency order.

Each node carries a NodeCache, a per-node object shared by every plugin that generates from that same node, reachable through ctx.cache. Work derived only from the node can be filled once and read by the rest instead of recomputed per plugin. The type is exported from @kubb/core and @kubb/kit, and the operations batch call receives a fresh scratch cache since it spans every node rather than one. This is the shared cache the name/path, import, and parameter items on the generation-repetition roadmap hang off.

Output is unchanged, which the constraints below preserve:

  • Schemas run before operations, in adapter order, with stable file paths.
  • Plugins fan out per node in dependency order.
  • Each plugin's macros and its include, exclude, and override filters still apply to the node before its generators run.
  • The operations batch still fires once per plugin after the single operation walk.
  • A failing plugin is dropped from the rest of the walk and reports one error diagnostic, without aborting the others.
  • kubb:plugin:end and the timing diagnostics still count up in dependency order for the CLI's Plugins N/M line.

Files

  • packages/core/src/nodeCache.ts — new NodeCache type and createNodeCache factory (get / set / getOrSet).
  • packages/core/src/KubbDriver.ts — node-outer #runGenerators, per-node cache wired into each generator context.
  • packages/core/src/defineGenerator.tscache field on GeneratorContext.
  • packages/core/src/{types.ts,mocks.ts} and packages/kit/src/index.ts — export the type and provide a cache in the mocked context.

✅ Checklist

  • I have followed the steps in the Contributing guide.
  • I have tested this code locally with pnpm run test.

Unit coverage: KubbDriver.test.ts now asserts the node-outer fan-out order and that one cache is shared per node across plugins while each node gets a fresh one; nodeCache.test.ts covers the cache primitive. pnpm lint and @kubb/core / @kubb/kit typecheck are clean. The one failing test in the suite (packages/mcp/src/tools/generate.test.ts) fails on the base branch too, from a missing built @kubb/adapter-oas dist in this environment, unrelated to this change.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.
  • This change is for the docs (no release).

🤖 Generated with Claude Code

https://claude.ai/code/session_01D1JYweapPQQNnjvkLV6c7n


Generated by Claude Code

…ate loop

`#runGenerators` looped plugin-outer, re-traversing the shared `schemas`
and `operations` arrays once per plugin so the walk cost was
`plugins × nodes`. Invert it to node-outer: each schema is visited once
and each operation once, and the node fans out to the matching generators
of every plugin in dependency order.

Each node carries a `NodeCache`, a per-node object shared by every plugin
that generates from it, reachable through `ctx.cache`, so work derived
only from the node is computed once and reused. The type is exported from
`@kubb/core` and `@kubb/kit`.

Output is unchanged: schemas still run before operations, plugins in
dependency order, macros and include/exclude/override filters still apply
before a plugin's generators run, and the `operations` batch still fires
once per plugin after the operation walk. `kubb:plugin:end` and the timing
diagnostics still count up in plugin order.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1JYweapPQQNnjvkLV6c7n
@changeset-bot

changeset-bot Bot commented Jul 18, 2026

Copy link
Copy Markdown

🦋 Changeset detected

Latest commit: 864bdf0

The changes in this PR will be included in the next version bump.

This PR includes changesets to release 12 packages
Name Type
@kubb/core Major
@kubb/kit Major
@kubb/adapter-oas Major
@kubb/cli Major
kubb Major
@kubb/mcp Major
@kubb/plugin-barrel Major
unplugin-kubb Major
@kubb/parser-md Major
@kubb/parser-ts Major
@kubb/renderer-jsx Major
@kubb/ast Major

Not sure what this means? Click here to learn what changesets are.

Click here if you're a maintainer who wants to add another changeset to this PR

@dosubot dosubot Bot added @kubb/core enhancement New feature or request labels Jul 18, 2026
@pkg-pr-new

pkg-pr-new Bot commented Jul 18, 2026

Copy link
Copy Markdown

Open in StackBlitz

@kubb/adapter-oas

npm i https://pkg.pr.new/@kubb/adapter-oas@3829

@kubb/ast

npm i https://pkg.pr.new/@kubb/ast@3829

@kubb/cli

npm i https://pkg.pr.new/@kubb/cli@3829

@kubb/core

npm i https://pkg.pr.new/@kubb/core@3829

@kubb/kit

npm i https://pkg.pr.new/@kubb/kit@3829

kubb

npm i https://pkg.pr.new/kubb@3829

@kubb/mcp

npm i https://pkg.pr.new/@kubb/mcp@3829

@kubb/parser-md

npm i https://pkg.pr.new/@kubb/parser-md@3829

@kubb/parser-ts

npm i https://pkg.pr.new/@kubb/parser-ts@3829

@kubb/plugin-barrel

npm i https://pkg.pr.new/@kubb/plugin-barrel@3829

@kubb/renderer-jsx

npm i https://pkg.pr.new/@kubb/renderer-jsx@3829

unplugin-kubb

npm i https://pkg.pr.new/unplugin-kubb@3829

commit: d94564d

Trim the per-plugin state comment that restated the object's fields, and
simplify the changeset so it reads plainly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01D1JYweapPQQNnjvkLV6c7n
@github-actions

github-actions Bot commented Jul 18, 2026

Copy link
Copy Markdown
Contributor

Size Change: 0 B

Total Size: 409 kB

ℹ️ View Unchanged
Filename Size Change
packages/adapter-oas/dist/index.cjs 24.4 kB 0 B
packages/adapter-oas/dist/index.js 24 kB 0 B
packages/adapter-oas/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/ast/dist/index.cjs 14.5 kB 0 B
packages/ast/dist/index.js 13.8 kB 0 B
packages/ast/dist/rolldown-runtime-CNktS9qV.js 291 B 0 B
packages/ast/dist/types.cjs 0 B 0 B 🆕
packages/ast/dist/types.js 31 B 0 B
packages/cli/dist/errors-CMvLO2NE.js 480 B 0 B
packages/cli/dist/errors-DNxBUo3k.cjs 537 B 0 B
packages/cli/dist/generate-DivmsV54.cjs 1.14 kB 0 B
packages/cli/dist/generate-DV_Srcbw.js 1.12 kB 0 B
packages/cli/dist/index.cjs 1.12 kB 0 B
packages/cli/dist/index.js 1.04 kB 0 B
packages/cli/dist/init-BMqpzODx.js 749 B 0 B
packages/cli/dist/init-C9-EwxER.cjs 777 B 0 B
packages/cli/dist/mcp-CYH5f0Cm.cjs 579 B 0 B
packages/cli/dist/mcp-vUOp-RlH.js 555 B 0 B
packages/cli/dist/package-BYGjY2e2.cjs 196 B 0 B
packages/cli/dist/package-C2WwUeML.js 137 B 0 B
packages/cli/dist/rolldown-runtime-Bx3C2hgW.cjs 576 B 0 B
packages/cli/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/cli/dist/run-B6GieDxN.cjs 12 kB 0 B
packages/cli/dist/run-BdtVrLKu.cjs 803 B 0 B
packages/cli/dist/run-BJhB7Qer.js 3.24 kB 0 B
packages/cli/dist/run-BuO4s2bO.js 12 kB 0 B
packages/cli/dist/run-CaOjZRiQ.js 758 B 0 B
packages/cli/dist/run-DAHp52w3.js 584 B 0 B
packages/cli/dist/run-DaVewTtW.cjs 3.33 kB 0 B
packages/cli/dist/run-iidDikJH.cjs 628 B 0 B
packages/cli/dist/Telemetry-7z2tIqPm.js 3.08 kB 0 B
packages/cli/dist/Telemetry-xcWb-UWT.cjs 3.2 kB 0 B
packages/cli/dist/tools-CzgGQa64.cjs 1.57 kB 0 B
packages/cli/dist/tools-DH1a7ZJH.js 1.49 kB 0 B
packages/cli/dist/validate-BWDhWrBx.cjs 581 B 0 B
packages/cli/dist/validate-dGW80XX9.js 559 B 0 B
packages/core/dist/index.cjs 27.7 kB 0 B
packages/core/dist/index.js 27.6 kB 0 B
packages/core/dist/mocks.cjs 1.81 kB 0 B
packages/core/dist/mocks.js 1.73 kB 0 B
packages/core/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/core/dist/usingCtx-BYOZEkiy.cjs 7.57 kB 0 B
packages/core/dist/usingCtx-C24YU3KM.js 7.05 kB 0 B
packages/kit/dist/index.cjs 5.87 kB 0 B
packages/kit/dist/index.js 5.69 kB 0 B
packages/kit/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/kit/dist/testing.cjs 221 B 0 B
packages/kit/dist/testing.js 61 B 0 B
packages/kubb/dist/astro.cjs 161 B 0 B
packages/kubb/dist/astro.js 81 B 0 B
packages/kubb/dist/config.cjs 153 B 0 B
packages/kubb/dist/config.js 82 B 0 B
packages/kubb/dist/defineConfig-BYCQRLaF.cjs 1.44 kB 0 B
packages/kubb/dist/defineConfig-CmqVIEF_.js 1.37 kB 0 B
packages/kubb/dist/esbuild.cjs 163 B 0 B
packages/kubb/dist/esbuild.js 83 B 0 B
packages/kubb/dist/farm.cjs 161 B 0 B
packages/kubb/dist/farm.js 80 B 0 B
packages/kubb/dist/index.cjs 233 B 0 B
packages/kubb/dist/index.js 111 B 0 B
packages/kubb/dist/jsx.cjs 250 B 0 B
packages/kubb/dist/jsx.js 71 B 0 B
packages/kubb/dist/jsx/jsx-dev-runtime.cjs 240 B 0 B
packages/kubb/dist/jsx/jsx-dev-runtime.js 79 B 0 B
packages/kubb/dist/jsx/jsx-runtime.cjs 234 B 0 B
packages/kubb/dist/jsx/jsx-runtime.js 75 B 0 B
packages/kubb/dist/kit.cjs 212 B 0 B
packages/kubb/dist/kit.js 54 B 0 B
packages/kubb/dist/kit/testing.cjs 219 B 0 B
packages/kubb/dist/kit/testing.js 62 B 0 B
packages/kubb/dist/nuxt.cjs 160 B 0 B
packages/kubb/dist/nuxt.js 80 B 0 B
packages/kubb/dist/rolldown-runtime-Bx3C2hgW.cjs 576 B 0 B
packages/kubb/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/kubb/dist/rolldown.cjs 160 B 0 B
packages/kubb/dist/rolldown.js 84 B 0 B
packages/kubb/dist/rollup.cjs 160 B 0 B
packages/kubb/dist/rollup.js 82 B 0 B
packages/kubb/dist/rspack.cjs 163 B 0 B
packages/kubb/dist/rspack.js 82 B 0 B
packages/kubb/dist/vite.cjs 160 B 0 B
packages/kubb/dist/vite.js 80 B 0 B
packages/kubb/dist/webpack.cjs 164 B 0 B
packages/kubb/dist/webpack.js 83 B 0 B
packages/mcp/dist/index.cjs 69.7 kB 0 B
packages/mcp/dist/index.js 69.1 kB 0 B
packages/mcp/dist/rolldown-runtime-G2anUtha.js 676 B 0 B
packages/parser-md/dist/index.cjs 1.29 kB 0 B
packages/parser-md/dist/index.js 1.25 kB 0 B
packages/parser-md/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/parser-ts/dist/index.cjs 6.22 kB 0 B
packages/parser-ts/dist/index.js 5.77 kB 0 B
packages/parser-ts/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/plugin-barrel/dist/index.cjs 5.49 kB 0 B
packages/plugin-barrel/dist/index.js 5.04 kB 0 B
packages/plugin-barrel/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/renderer-jsx/dist/index.cjs 5.5 kB 0 B
packages/renderer-jsx/dist/index.js 5.38 kB 0 B
packages/renderer-jsx/dist/jsx-dev-runtime.cjs 165 B 0 B
packages/renderer-jsx/dist/jsx-dev-runtime.js 79 B 0 B
packages/renderer-jsx/dist/jsx-runtime.cjs 567 B 0 B
packages/renderer-jsx/dist/jsx-runtime.js 508 B 0 B
packages/renderer-jsx/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/renderer-jsx/dist/rolldown-runtime-ClG-MNz_.cjs 202 B 0 B
packages/renderer-jsx/dist/types.cjs 0 B 0 B 🆕
packages/renderer-jsx/dist/types.js 31 B 0 B
packages/unplugin-kubb/dist/astro.cjs 300 B 0 B
packages/unplugin-kubb/dist/astro.js 296 B 0 B
packages/unplugin-kubb/dist/esbuild.cjs 191 B 0 B
packages/unplugin-kubb/dist/esbuild.js 187 B 0 B
packages/unplugin-kubb/dist/farm.cjs 191 B 0 B
packages/unplugin-kubb/dist/farm.js 184 B 0 B
packages/unplugin-kubb/dist/index.cjs 282 B 0 B
packages/unplugin-kubb/dist/index.js 199 B 0 B
packages/unplugin-kubb/dist/nuxt.cjs 331 B 0 B
packages/unplugin-kubb/dist/nuxt.js 329 B 0 B
packages/unplugin-kubb/dist/rolldown-runtime-C0LytTxp.js 168 B 0 B
packages/unplugin-kubb/dist/rolldown.cjs 193 B 0 B
packages/unplugin-kubb/dist/rolldown.js 188 B 0 B
packages/unplugin-kubb/dist/rollup.cjs 191 B 0 B
packages/unplugin-kubb/dist/rollup.js 186 B 0 B
packages/unplugin-kubb/dist/rspack.cjs 191 B 0 B
packages/unplugin-kubb/dist/rspack.js 186 B 0 B
packages/unplugin-kubb/dist/types.cjs 0 B 0 B 🆕
packages/unplugin-kubb/dist/types.js 31 B 0 B
packages/unplugin-kubb/dist/unpluginFactory-6ephcTBF.js 1.57 kB 0 B
packages/unplugin-kubb/dist/unpluginFactory-DKjcwMVB.cjs 1.71 kB 0 B
packages/unplugin-kubb/dist/unpluginFactory.cjs 157 B 0 B
packages/unplugin-kubb/dist/unpluginFactory.js 85 B 0 B
packages/unplugin-kubb/dist/vite.cjs 190 B 0 B
packages/unplugin-kubb/dist/vite.js 185 B 0 B
packages/unplugin-kubb/dist/webpack.cjs 192 B 0 B
packages/unplugin-kubb/dist/webpack.js 188 B 0 B

compressed-size-action

@stijnvanhulle
stijnvanhulle merged commit 4f03d56 into main Jul 18, 2026
6 checks passed
@stijnvanhulle
stijnvanhulle deleted the claude/kubb-issue-3812-7ekj69 branch July 18, 2026 13:25
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

enhancement New feature or request @kubb/core

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Generate loop re-walks every schema and operation once per plugin

2 participants