feat(cli): introduce @a2ui/cli and basic catalog python builders - #2425
feat(cli): introduce @a2ui/cli and basic catalog python builders#2425jacobsimionato wants to merge 24 commits into
Conversation
- Add static Catalog.fromJson factory to ingest raw A2UI JSON catalog schemas into typed Catalog instances. - Reconstruct ComponentDefinition, SlotDefinition, and parameter bindings dynamically with canonical Zod common types. - Export JsonSchemaCatalogLoader and add comprehensive unit test suite.
- Add @a2ui/cli TypeScript package registered in Yarn monorepo workspaces. - Provide codegen command powered by CatalogAnalyzer and PythonEmitter. - Emit single-file consolidated Python modules with types, dataclasses, and functions. - Add builder base runtime foundation (base.py) and pre-generated Basic Catalog builders (basic.py).
There was a problem hiding this comment.
Code Review
This pull request introduces the @a2ui/cli package, a developer tool and typesafe component generator that analyzes catalog schemas and generates typesafe Python builder classes. It also includes the generated Python builders and base runtime classes. The review feedback highlights critical issues in recursive traversal and serialization: both assign_ids and serialize_node in base.py fail to traverse Mapping values, which prevents nested components (like those in Tabs) from being correctly processed. Similarly, the generated _serialize_prop helper in python-emitter.ts needs to recursively serialize dictionaries to avoid runtime TypeErrors. Finally, catalog-analyzer.ts should match refMatch against the accumulated description variable rather than current.description to correctly resolve REF: pointers on optional or default fields.
- Make json_schema_loader internal by removing its re-export from index.ts. - Default protocol version to v0.9 per specification when omitted instead of requiring explicit options. - Support data.id and data.protocolVersion in extractCatalogMetadata. - Fix allOf and properties merging by evaluating both instead of using else-if. - Resolve required fields across schemas using a two-pass collection. - Stricten integer schema type parsing to z.number().int(). - Add convertEnumToZod helper to safely parse string, literal, and mixed enums without throwing in z.enum. - Add defensive checks for non-object propSchema. - Format modified files with Prettier. - Add comprehensive unit tests covering all edge cases.
- Remove CatalogJsonLoaderOptions interface. - Simplify Catalog.fromJson to accept only catalogJson and rely on catalog metadata and spec defaults.
…mJson without options
- Support nested component traversal inside mappings in assign_ids and serialize_node - Support dict recursion in python emitter _serialize_prop - Match refMatch against unwrapped description in CatalogAnalyzer - Restore third_party to IGNORE_PATTERNS in fix_licenses.py - Format python builder files with pyink
…olVersion/rawSchema
…t to a2ui.builder.base
…without hardcoded weight
…er builder/catalogs/basic
…s to a2ui.builder
| # ============================================================================= | ||
|
|
||
| TextVariant = Literal["h1", "h2", "h3", "h4", "h5", "caption", "body"] | ||
| ImageFit = Literal["contain", "cover", "fill", "none", "scaleDown"] |
There was a problem hiding this comment.
this needs to handle future and previous versions of the basic catalog
if we like the setup here https://docs.google.com/document/d/1ACOeNwMxSOZ2UFQdZfi80eAd8EET9CXiH5de2Apfr5w/edit?resourcekey=0-BunpI_b9qriYqpjbl1hY0w&tab=t.y0y8446q3tdb#bookmark=id.s0pb0dnj7k8m maybe just ask the LLM to support it?
here I think we need open enums
IconSize = Literal["small", "medium", "large"] | str
| d["label"] = _serialize_prop(self.label) | ||
| if self.id is not None: | ||
| d["id"] = self.id | ||
| return d |
There was a problem hiding this comment.
can we try to get these builders working as the deserialization engine too?
there are some extra properties we want like unknown field preservation, eg
Component = Annotated[
Union[MaterialIcon, UnknownComponent],
Field(discriminator="type"),
]
There was a problem hiding this comment.
|
|
||
|
|
||
| @dataclass(kw_only=True) | ||
| class DateTimeInput(ComponentBuilderNode): |
There was a problem hiding this comment.
why not use pydantic? it has some options we want like preserve extra fields, eg
class MaterialIcon(BaseModel):
model_config = ConfigDict(
extra="allow", # Preserves unknown fields for round-tripping
populate_by_name=True,
)
… json_schema_loader to schema_loader
Summary
Introduces the
@a2ui/clideveloper tooling package in TypeScript and pre-generated Basic Catalog Python builders.Part 2 of the Programmatic Macros & Typesafe Builders stack.
Key Changes
@a2ui/cliPackage: Built with Commander, registered in the root Yarn Berry monorepo workspace under"javascript/*".a2ui codegenCommand: Ingests any catalog schema (via@a2ui/web_core'sCatalog.fromJson) and emits a clean, type-annotated single-file Python module containing:@dataclasscomponent builder classes with automatic ID allocation and serialization.__all__exports.builder/base.py): DefinesComponentBuilderNode,Surface,bind,Action, and tree flattening logic.builder/basic.py): Generated directly by@a2ui/clifor protocol versionv0.9.1.Stack Overview
feat(web_core): introduce Catalog.fromJson schema ingestion engine(feat(web_core): introduce Catalog.fromJson schema ingestion engine #2424)feat(cli): introduce @a2ui/cli and basic catalog python buildersfeat(a2ui_agent): add programmatic macro runtime and test suitefeat(samples): add community macros demo server and react clientdocs(proposals): add programmatic macros and typesafe builders proposalVerification
yarn --cwd javascript/a2ui_cli run buildyarn --cwd javascript/a2ui_cli run test(5 tests passed)yarn --cwd javascript/a2ui_cli run lint && yarn --cwd javascript/a2ui_cli run format:check