Skip to content

feat(mdl): SHOW / DESCRIBE BUILDING BLOCKS (read-only discovery) - #16

Merged
ako merged 2 commits into
mainfrom
feature/show-describe-building-blocks
Jul 24, 2026
Merged

feat(mdl): SHOW / DESCRIBE BUILDING BLOCKS (read-only discovery)#16
ako merged 2 commits into
mainfrom
feature/show-describe-building-blocks

Conversation

@ako

@ako ako commented Jul 24, 2026

Copy link
Copy Markdown
Owner

Adds read-only discovery for Mendix Building Blocks (Pages$BuildingBlock) — the native "reusable widget composition" library. This is the READ prerequisite for the Atlas design-system recipe work (see PROPOSAL_atlas_design_system.md); INSTANTIATE (USE BUILDING BLOCK) and AUTHOR (CREATE BUILDING BLOCK) remain separate follow-ups.

Mirrors the existing SHOW/DESCRIBE SNIPPET path layer-for-layer.

Commands

  • SHOW BUILDING BLOCKS [in <module>] — lists Qualified Name, Module, Name, Display Name, Platform, Category.
  • DESCRIBE BUILDING BLOCK Module.Name — informational output: doc block (if any) + metadata comment lines + the widget tree. Read-only — deliberately not a re-executable create (Building Blocks can't be authored via MDL), analogous to DESCRIBE LAYOUT.
  • select … from CATALOG.building_blocks — SQL querying over blocks; also listed by SHOW CATALOG TABLES.

Notable: a latent reader bug fixed

The storage $Type is Pages$BuildingBlock (per the generated metamodel), but ListBuildingBlocks previously queried only Forms$BuildingBlock — so it returned empty on real projects. It now does a dual-type lookup (Pages$ first, Forms$ fallback), mirroring how ListSnippets falls back. The widget tree is read from the raw unit (GetRawUnit) as a top-level Widgets[] array — the same shape and reader logic as a Studio-Pro snippet — not from the typed parser.

Wiring (all layers)

  • Data: sdk/pages/pages.go (struct fields), sdk/mpr/parser_misc.go (scalar parse + correct $Type), sdk/mpr/reader_types.go (dual-type lookup).
  • Grammar: new BUILDING/BLOCK/BLOCKS lexer tokens + showStatement/describeStatement alternatives. Added to the keyword rule so they remain usable as identifiers (verified: create entity Sales.Block (Building: string) still parses). The catalog SELECT needs no grammar change (catalogTableName already accepts IDENTIFIER).
  • AST / visitor / executor dispatch, new mdl/executor/cmd_building_blocks.go (list + read-only describe + raw widget reader), CLI describe registration for both $Type strings.
  • Catalog: new building_blocks_data table + view (mdl/catalog/tables.go), buildBuildingBlocks() builder (builder_pages.go), registered in Catalog.Tables(), and ListBuildingBlocks added to the CatalogReader interface (*mpr.Reader already implements it). Deliberately not wired into widgets_data/the refs projection — a Building Block is a read-only copy-template (deep-copied, no live link), so it has no meaningful cross-reference edges, only a WidgetCount.
  • Backend PageBackend interface/impls unchanged (ListBuildingBlocks + GetRawUnit already existed everywhere).

Tests & docs

  • Executor mock tests: list, module filter, describe-not-found — all passing.
  • Catalog tests: building_blocks added to the core-tables query test + CATALOG.BUILDING_BLOCKS to the Tables()-coverage test; mdl/catalog suite green.
  • Check-parseable doctype example mdl-examples/doctype-tests/36-building-block-examples.mdl.
  • MDL_QUICK_REFERENCE.md + a syntax feature entry.
  • make grammar + go build ./... + go vet + gofmt clean; mdl/... and sdk/... suites green (incl. the grammar keyword-coverage test, which caught the missing keyword-rule entries — now fixed).

Validation note

Resolved the $Type and widget-shape questions from the authoritative in-repo metamodel rather than a live dump (a blank mxcli new app has no building blocks anyway). Real-project / Studio-Pro confirmation of the dual-type lookup and widget walk is the natural next validation step.

🤖 Generated with Claude Code

https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4

claude added 2 commits July 24, 2026 13:27
Add read-only discovery for Mendix Building Blocks (Pages$BuildingBlock),
mirroring the SHOW/DESCRIBE SNIPPET path. Building Blocks are the native
"reusable widget composition" library; this surfaces them so a project's
existing blocks can be discovered and inspected (the READ prerequisite for the
Atlas design-system recipe work — INSTANTIATE/AUTHOR remain separate).

- SHOW BUILDING BLOCKS [in module] — lists Qualified Name, Module, Name,
  Display Name, Platform, Category.
- DESCRIBE BUILDING BLOCK Module.Name — informational output (doc block +
  metadata comments + widget tree). Read-only: not a re-executable CREATE,
  since Building Blocks can't be authored via MDL.

Data layer: the storage $Type is Pages$BuildingBlock (per the generated
metamodel), not Forms$BuildingBlock as the reader previously assumed — so
ListBuildingBlocks now does a dual-type lookup (Pages$ first, Forms$ fallback),
fixing a latent empty-result bug. parseBuildingBlock reads DisplayName /
Platform / TemplateCategory scalars. The widget tree is read from the raw unit
(GetRawUnit) as a top-level Widgets[] array — the same shape and reader logic
as a Studio-Pro snippet — not from the typed parser.

Grammar: new BUILDING / BLOCK / BLOCKS lexer tokens (added to the keyword rule
so they remain usable as identifiers), plus showStatement / describeStatement
alternatives. Wired through AST, visitor, executor dispatch, and the CLI
describe registration (both $Type strings). Backend interface/impls unchanged
(ListBuildingBlocks + GetRawUnit already existed everywhere).

Tests: executor mock tests (list, module filter, describe-not-found) + a
check-parseable doctype example. Docs: MDL_QUICK_REFERENCE + a syntax feature.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
Surface Building Blocks in the SQLite catalog so they are queryable via
`select ... from CATALOG.building_blocks` and listed by SHOW CATALOG TABLES.

- New building_blocks_data table + full-snapshot view (tables.go), registered
  in Catalog.Tables() as CATALOG.BUILDING_BLOCKS.
- buildBuildingBlocks() populates it (Id, Name, QualifiedName, Module, Folder,
  Description, DisplayName, Platform, Category, WidgetCount). WidgetCount is read
  from the raw unit's top-level Widgets array (full mode only).
- ListBuildingBlocks added to the CatalogReader interface (*mpr.Reader already
  implements it).

Deliberately NOT wired into widgets_data / the refs projection: a Building Block
is a read-only copy-template (deep-copied onto pages with no live link), so it
has no meaningful cross-reference edges — only a widget count. The SELECT path
needs no grammar change (catalogTableName already accepts IDENTIFIER).

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
@ako
ako merged commit 8634203 into main Jul 24, 2026
1 of 3 checks passed
ako pushed a commit that referenced this pull request Jul 28, 2026
Ledger finding #16: year() and month() were in the built-in function
whitelist, so `mxcli check --references` passed, but Mendix has no such
functions and the build then failed with CE0117. Remove both so the
error is caught at check time; the correct approach is date
formatting/parsing (parseInteger(formatDateTime($d,'yyyy'))).

Flagged the sibling extraction names (dayOfYear/hour/minute/…) as
unverified-and-likely-invalid in a comment rather than removing them
blind — they need a Studio Pro build to confirm, and rejecting a valid
function is worse than the current state. Test: TestFuncReturnKind_NoYearMonth.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
ako pushed a commit that referenced this pull request Jul 30, 2026
…ibute-keyword hint (TraceOps #11/#12/#16)

Three MDL ergonomics improvements, each verified against mxbuild 11.12.1
(`mx check` → 0 errors):

#11 — a single-quoted string literal may now span multiple lines. STRING_LITERAL
excluded `\r\n`, so a newline terminated the token ("missing END at …"). Dropped
the newline exclusion; mxbuild accepts a multi-line String value. (A missing
close-quote now spans lines — the standard multi-line-string trade-off.)

#12 — a bare MDL keyword (`body`, `content`, `search`, `as`, …) may be used
unquoted as a WIDGET name, matching attribute and placeholder names. The
widgetV3 rule accepted only IDENTIFIER | QUOTED_IDENTIFIER; it now also accepts
`keyword`, and the visitor reads `wCtx.Keyword()` so the name is preserved
(previously the parse failed, or an accepted keyword name came out empty →
CE7247 "name cannot be empty").

#16 — `alter entity … add <name>: <type>` without the `attribute` keyword gave
an opaque "no viable alternative at input 'add<Name>'". enhanceErrorMessage now
appends an actionable hint with the correct `add attribute <name>: <type>` form
when the offending line is `add <word>:` and `<word>` isn't a real clause
keyword (attribute/column/index/event/value/…); gated to the primary error.

`make grammar` regenerates the parser (generated files are not committed). Tests
TestMultiLineStringLiteral, TestKeywordWidgetName,
TestAlterEntityMissingAttributeKeywordHint; repro
mdl-examples/bug-tests/traceops-11-12-16-strings-names.mdl.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01JXnEgoc2NQP1Y2TWMCMXC4
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.

2 participants