feat(angular): add @json-render/angular renderer - #310
Conversation
Add a new first-party Angular renderer package at feature parity with the
React, Vue, and Solid baselines. The public API mirrors the baseline export
surface exactly.
Package (packages/angular):
- Built with ng-packagr (Angular Package Format), matching the Svelte
package's use of svelte-package rather than tsup. Zero added consumer
runtime dependencies.
- Public API parity: schema/AngularSchema/AngularSpec, JsonRenderComponent,
ComponentRegistry, defineRegistry, provideJsonRender, createRenderer,
JsonRendererComponent, JSON_RENDER_* tokens, SpecStateService,
VisibilityService, ActionDispatcherService, ValidationService,
RepeatScopeService, ChildrenOutletDirective, confirm-dialog directive +
styled ConfirmDialog component, boundProp/injectBoundProp, streaming
parts helpers, injectUIStream/injectChatUI/injectJsonRenderMessage, and
core re-exports.
- Angular 21 (ng-packagr 21) to stay within the workspace TypeScript ~5.9
pin; consumer peerDependencies kept broad (^20 || ^21 || ^22).
- Idiomatic modern Angular: standalone components, signals, inject().
- Colocated *.test.ts suites run via an isolated Vitest pipeline
(@analogjs/vite-plugin-angular) using pnpm test:angular.
Parity gap fixes: validateForm writes {valid,errors} without throwing (B2),
repeat $item filtering via core splitRepeatVisibility (B3), external
StateStore support (M4), onStateChange delta emission (M5), and the missing
default rules (M6).
Root/shared changes:
- package.json: add test:angular script.
- vitest.config.mts: exclude packages/angular (Angular needs its own
compiler pipeline; incompatible with the shared React/Svelte/Solid
transforms).
- pnpm-workspace.yaml: mark native-build transitive deps
(@parcel/watcher, lmdb, msgpackr-extract) as non-building.
- README.md: packages table row, install line, and Angular section.
- pnpm-lock.yaml: Angular devDependencies.
Also adds skills/angular/SKILL.md.
Follow-ups (deferred): wire pnpm test:angular into CI, apps/web docs-site
integration, and optional commit signing.
|
@tomzohar is attempting to deploy a commit to the Vercel Labs Team on Vercel. A member of the Team first needs to authorize it. |
|
Review the following changes in direct dependencies. Learn more about Socket for GitHub.
|
- Add pnpm test:angular step to CI test job so Angular tests run in CI - Remove tslib from dependencies (importHelpers: false) - Align @angular/build devDep to 21.2.18 (match other Angular packages)
…ch errors - Refactor onStateChange from input() to output() (stateChange event) - Add .catch(onEventDispatchError) to fire-and-forget dispatcher calls
- Remove 20+ core re-exports from public API (consumers import from @json-render/core) - Add cross-renderer naming map to README - Update onStateChange docs to (stateChange) output syntax - Update defineCatalog import to @json-render/core in README and SKILL.md
Exercises every package feature: spec rendering, state binding, repeat/filtered lists, visibility, actions, validation, confirmation dialogs, watchers, streaming helpers, external state store, and (stateChange) output.
|
For anyone finding this closed PR while looking for Angular support: a standalone Angular renderer is now available — Same renderer contract as the official React/Vue/Solid/Svelte packages on top of @tomzohar — if you're still interested in json-render + Angular, feedback and contributions are very welcome. |
Summary
Adds a new first-party Angular renderer, @json-render/angular , at feature
parity with the existing React, Vue, and Solid renderers. The package
mirrors
the baseline public API surface exactly (React = Vue = Solid share one
contract;
this package holds it too) and ships as an idiomatic modern Angular library
(standalone components, signals, inject() ).
No new runtime dependencies are added for consumers.
Motivation
json-render supports React, Vue, Solid, and Svelte. Angular is the
remaining
major framework without a first-party renderer. This PR closes that gap so
Angular apps can render the same JSON UI specs with the same capabilities
(state, visibility, actions, validation, repeat, streaming) as every other
supported framework.
What's included
New package: packages/angular ( @json-render/angular , v0.19.0)
• Build: ng-packagr https://github.com/ng-packagr/ng-packagr (Angular
Package Format), consistent with the Svelte package's use of svelte-package
rather than tsup . Two entry points ( . and ./schema ), full AOT.
• Angular version: built against Angular 21 / ng-packagr 21 to stay within
the workspace TypeScript ~5.9 pin (Angular 22's compiler requires TS >= 6.0 ,
which would be a much more invasive workspace-wide bump). Consumer
peerDependencies are kept broad: @angular/* "^20 || ^21 || ^22" .
• Public API parity with the baseline:
• schema , AngularSchema , AngularSpec (+ Spec , StateStore ,
createStateStore re-exports)
• JsonRenderComponent , ComponentRegistry , defineRegistry
• provideJsonRender , createRenderer , JsonRendererComponent
• JSON_RENDER_* DI tokens
• SpecStateService , VisibilityService , ActionDispatcherService ,
ValidationService , RepeatScopeService , ChildrenOutletDirective
• JsonRenderConfirmDialogDirective (headless) plus an out-of-the-box
styled
ConfirmDialog component
• boundProp / injectBoundProp
• streaming: flatToTree / buildSpecFromParts / getTextFromParts ,
injectUIStream / injectChatUI / injectJsonRenderMessage
• core re-exports ( defineCatalog , getByPath , setByPath , check ,
createDirectiveRegistry , defineDirective , resolvePropValue , + types)
• Tests: colocated *.test.ts suites (8 files, including TestBed component
tests) run through an isolated Vitest pipeline powered by
@analogjs/vite-plugin-angular , invoked via pnpm test:angular .
Parity gap fixes (behavior verified against the baseline)
• validateForm writes { valid, errors } to params.statePath ??
'/formValidation'
and does not throw; added to schema.builtInActions .
• repeat $item filter uses core splitRepeatVisibility to separate the
container visibility gate from the per-item filter, preserving item indices.
• external StateStore support via [store] input and
SpecStateService.connectStore/disconnectStore .
• onStateChange emits Array<{ path, value }> deltas.
• default rules now include the two previously missing rules
( required-children , filtered lists).
Root / shared changes
• package.json : adds a test:angular script (no Angular devDeps at root;
they
live in the package).
• vitest.config.mts : excludes packages/angular/** . Angular requires its
own
compiler pipeline ( @analogjs/vite-plugin-angular ), which is incompatible
with
the shared React/Svelte/Solid transforms; putting it in the root config
breaks
those suites.
• pnpm-workspace.yaml : marks transitive native-build deps
( @parcel/watcher , lmdb , msgpackr-extract ) as non-building. These come
in
via the Angular test tooling; they are only needed for watch/dev, not
build/test.
• README.md : packages-table row, install line, and an Angular renderer
section.
• pnpm-lock.yaml : updated for the new Angular devDependencies.
• skills/angular/SKILL.md : agent skill for the Angular renderer.
Validation
Run on Node 24 / pnpm:
• pnpm turbo run build --filter='./packages/*' — all library packages
build,
including @json-render/angular via ng-packagr (both entry points, full
AOT).
• pnpm test — green (930 tests). The root config now excludes
packages/angular .
• pnpm test:angular — green (all 8 Angular test files, including TestBed
component tests and the B2/B3/M5 behavior tests).
• pnpm --filter @json-render/angular typecheck — clean.
│ Note: the CI test job builds packages/* and then runs pnpm test . To
run
│ the
│ Angular suite in CI, pnpm test:angular must be added to the workflow
(see
│ Follow-ups).
Follow-ups (deferred, intentionally out of scope for this PR)
suite runs in CI (today only pnpm test runs, which excludes this package).
the
Angular renderer.
signing is set up.
Notes for reviewers
• ng-packagr owns the published package.json (generates dist/package.json
);
the source package.json intentionally does not hand-write
exports / module / typings .
• This is a pnpm workspace ( npm install fails on workspace:* ); Node >=24 ,
pnpm >=11 .