Skip to content

fix(parser): emit no-root diagnostic when no root component resolves#632

Open
Shinyaigeek wants to merge 1 commit into
thesysdev:mainfrom
Shinyaigeek:fix/parser-no-root-diagnostic
Open

fix(parser): emit no-root diagnostic when no root component resolves#632
Shinyaigeek wants to merge 1 commit into
thesysdev:mainfrom
Shinyaigeek:fix/parser-no-root-diagnostic

Conversation

@Shinyaigeek

@Shinyaigeek Shinyaigeek commented Jun 11, 2026

Copy link
Copy Markdown
Contributor

Problem

This is a kind of proposal to provide more information in error message, so please feel free to close this if this is not acceptable 🙏

A program that parses successfully but contains no resolvable root component — e.g. only $state declarations, a top-level literal, or pure data statements — returned root: null with empty meta.errors, unresolved, and orphaned. There was no diagnostic at all indicating that a top-level component statement was missing.

This was reported by a coding agent integrating against the parser:

Without knowing the root = Stack(...) convention, I wrote code where meta.errors / unresolved / orphaned were all empty yet res.root was null. With no "root statement not found" diagnostic, I burned a full round identifying the cause. Emitting a no-root warning in meta would have saved it.

Reproduction (before)

input root errors unresolved orphaned
$data = ["a", "b"] null [] [] []
greeting = "hello" null [] [] []
$items = [1,2,3] / $count = 3 null [] [] []

Root cause

pickEntryId falls back to the first statement even when none is a component, and buildResult then silently set root = null when that entry materialized to a non-element — without pushing any error. It's the one null-root path that emitted no diagnostic (unknown-component, missing-required, etc. all push a ValidationError).

Fix

  • Add a no-root code to ValidationErrorCode (so it flows through to OpenUIErrorCode).
  • In buildResult, emit no-root when the entry resolves to a non-component value. Gated two ways to avoid noise:
    • !wasIncomplete — root is legitimately null mid-stream.
    • errors.length === 0 — don't double-report when something else (e.g. missing-required on root = Stack()) already explains the null root.
  • enrichErrors attaches an actionable hint pointing at the root = <Component>(...) convention, so the automated correction loop can recover on its own.

Tests

6 new cases under no-root diagnostic: $state-only / literal-entry / data-only programs emit no-root; a valid root does not; no double-report alongside missing-required; and no emit mid-stream while input is incomplete.

Full lang-core suite: 79/79 pass. tsc --noEmit: clean.

Note

Follow-up (not in this PR): the troubleshooting doc's error-code list doesn't yet mention no-root, and the spec frames a missing root as "nothing renders" (silent). Happy to update the docs in a separate change.

🤖 Generated with Claude Code

A program with statements but no resolvable root component (e.g. only
`$state`/literal/data declarations) returned `root: null` with empty
`errors`/`unresolved`/`orphaned` — no signal at all that a top-level
component statement was missing. `pickEntryId` falls back to the first
statement even when none is a component, and `buildResult` then set
`root` to null silently when it materialized to a non-element.

Add a `no-root` ValidationErrorCode and emit it from `buildResult` when
the entry resolves to a non-component value. Gated two ways to avoid
noise:
- `!wasIncomplete` — root is legitimately null mid-stream.
- `errors.length === 0` — don't double-report when something else
  (e.g. `missing-required` on `root = Stack()`) already explains it.

`enrichErrors` adds an actionable hint pointing at the `root = ...`
convention, so the automated correction loop can recover.

Tests cover: $state-only, literal-entry, and data-only programs emit
`no-root`; valid root does not; no double-report with missing-required;
no emit mid-stream.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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