Repository navigation
Commit 37a19d4
fix(cli): objectui check prints the refused key and path, and never calls an unvalidated file passed (objectui#11007) (#11053)
Fixes #11007
Clause-②: no
`domain:ui` seat 2, branch `claude/issue-11007-check-prints-key`,
session `https://claude.ai/code/session_011p7ikEivgXefNDaE5S5Uec`.
Placeholders are spelled in capitals (`FILE`) because GitHub strips
tag-shaped text from a body.
## What this changes
`objectui check` recognises a JSON file in one of two ways: a structural
root key (`children`, `className`, …) admits it without parsing it, or
the whole document validates. Measured on `origin/main` at `bf7ab35ce`
before this change, with the card's two documents:
- A root `object-map` whose `map` block carries `latitudeFieId` was
listed under "did not validate" as `map.json (type "object-map")`. The
validator's issue was already in hand from the recognising parse, and
was dropped.
- The same node under a page's `children` was admitted on `children` and
never parsed. The run ended `✓ All checks passed`. No exit call in
either run.
Per the triage ruling (both halves, narrowly):
- **(a)** Each "did not validate" entry now carries one indented line:
the first issue's path, spelled by the formatter behind `objectui
validate`'s `Path:` line, and its message, with the issue count when
there is more than one. For the card's root case it reads `Issue at map:
Unrecognized key: "latitudeFieId"`. It reuses the issues of the parse
the recogniser already ran. Skipped (foreign) files still get no
diagnosis.
- **(b)** The no-error close is a tally: `ObjectUI schema files: V
validated, S recognised but not validated, U did not validate. This
sweep is advisory; run objectui validate FILE for a verdict.` Nothing
reads as a pass. The parse-error close (`Found N errors`, exit 1) is
untouched.
- No nested walk in `check`. A structurally admitted file is still not
parsed, and a pin holds that boundary: a later walk turns it red.
- Exit codes do not move.
## Surface beyond the claim's file list, and why
- **`packages/cli/src/utils/issue-path.ts` (new, `formatIssuePath`), and
`validate.ts` switched to it.** The suggested route said to reuse
`validate`'s formatter rather than copy it. It was an inline ternary
with no export, so it moved into one helper that both commands call.
`validate`'s output is byte-identical: same expression, and its three
suites are green below.
- **A comment in `validate.ts` and the header of
`utils/union-arm-diagnostics.ts`** each said `validate` is "the
repository's only zod-issue printer". This change makes that false, so
both now say what `check` prints (one first-issue line, no arm
selection).
- **Three pending changesets get an appended dated note.** Their
existing text and declarations are unchanged. Each would otherwise
publish a sentence this change makes false, in the same release:
`7004-cli-union-arm-selection.md` (`check` "has no zod-issue printer"),
`7694-chart-series-chart-type-alias-refusal.md` ("without the issue")
and `6475-gantt-block-face-declared.md` ("without naming the missing
field"). The shape follows the 2026-09-25 dated notes (objectui#10524)
on the same files. `check-changeset-overwrite` reports the three as
modified, with declarations unchanged (report-only).
**Closing text pinned next to an exit code.** The order asked for this
to be reported, not acted on. Four existing tests asserted `All checks
passed` beside their exit-code assertion: `check-jsonc-parse` (two),
`check-schema-marker` and `check-validity-recogniser`.
`check-known-types` used the same line as its "not a failure" signal.
Each text assertion now reads the tally through `closingLine(...)`.
Every exit-code assertion is unchanged.
## Tests
`packages/cli/src/__tests__/check-first-issue-11007.test.ts`, 8 tests:
- The root typo prints the refused key and the path `map`.
- A two-segment first-issue path prints as `map → zoom`.
- The issue count appears when there is more than one issue.
- There is still one entry per file.
- The nested typo is not reported as passed: no printed line matches
`/pass/i`, the tally is 0 / 1 / 0, and there is no exit call.
- Each bucket is counted apart.
- The parse-error close is unchanged.
- There is no nested walk: a broken page and a clean page are counted
the same, while `safeValidateSchema` tells them apart.
Expected text comes from `describeFirstIssue` and `closingLine`, fed
with real `safeValidateSchema` issues. The assertions pin the subject
(key, path, counts), not the wording.
**Ablations.** Each was one-shot, run on the committed tree at
`762723318` through objectstack's `scripts/ablation-replace.mjs`. Each
restore was proven: the blob equals HEAD and `git diff HEAD` is empty.
No permanent test was added.
- **i. Drop the first-issue print:** 4 failed, 48 passed. The four
first-issue pins failed.
- **ii. Put the old pass line back at the call site:** 8 failed, 44
passed, across all five files. That is the five updated sibling
assertions plus the three new close pins. The first attempt was a no-op:
the tool refused before running because the replacement contained its
anchor. It was rerun with a different anchor.
- **iii. Parse structurally admitted files (a nested walk):** 1 failed,
51 passed. Only the no-walk pin failed.
## Gates, all at `762723318` (the final commit)
- `pnpm exec vitest run packages/cli/` → `Test Files 22 passed (22)`,
`Tests 302 passed (302)`. The base has 21 files.
- `pnpm --filter @object-ui/types build` → exit 0. That is the only
workspace package the CLI's source imports (`@object-ui/types/zod`); the
other `@object-ui/*` hits are template strings.
- `pnpm --filter @object-ui/cli type-check` (`tsc --noEmit`) → exit 0.
`--listFiles` includes the new test, `issue-path.ts` and `check.ts`.
- `pnpm --filter @object-ui/cli build`, then `pnpm check` (the repo-tree
run `lint.yml` makes) → exit 0. Output is below.
- eslint, run the way the package `lint` script runs it (`eslint src` in
`packages/cli`, inline config honoured): 48 files, 0 errors, 5 warnings.
All five are `no-explicit-any` in untouched files. `eslint.config.js`
enables no type-aware linting (no `parserOptions`, no type-checked
preset), so this diff cannot move any untouched file's verdict.
- Changeset and byte gates: `check-changeset-presence` ✅ (1 added),
`check-changeset-no-major` ✅, `check-control-bytes` ✅,
`check-new-line-citations` 0 new, `check-pending-changeset-literals` ✅.
- `check-changeset-claims` is report-only. It names two pending
changesets that mention touched files: 6320 (the ignore list in
`check.ts`) and 7658 (headings in `cli.mdx`). Both still hold.
- Other gates: `check-test-path-roots` ✅, `check-unreferenced-sources`
✅, `check-doc-fences` ✅, `check-doc-types` ✅, `check-spec-symbols` ✅,
`check-doc-example-ids` ✅, `check-doc-example-readers` ✅,
`check-doc-links` ✅.
- NOT MEASURED: `check:doc-examples` and `check:doc-snippets`. Their
prerequisite is not met: they need a scoped build of 34 packages. This
diff adds no TypeScript block to any document; its one new fence is
`text`. CI runs both.
`pnpm check` on this tree (`FILE` stands for the placeholder the command
prints):
```text
Object UI Schema Check
Analyzing 633 files...
1 parent 2a1779f commit 37a19d4
15 files changed
Lines changed: 547 additions & 35 deletions
File tree
- .changeset
- content/docs
- plugins
- utilities
- packages/cli/src
- __tests__
- commands
- utils
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
43 | 43 | | |
44 | 44 | | |
45 | 45 | | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
46 | 53 | | |
47 | 54 | | |
48 | 55 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
36 | 36 | | |
37 | 37 | | |
38 | 38 | | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
39 | 45 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
41 | 41 | | |
42 | 42 | | |
43 | 43 | | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
44 | 50 | | |
45 | 51 | | |
46 | 52 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
188 | 188 | | |
189 | 189 | | |
190 | 190 | | |
191 | | - | |
| 191 | + | |
192 | 192 | | |
193 | 193 | | |
194 | 194 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
199 | 199 | | |
200 | 200 | | |
201 | 201 | | |
| 202 | + | |
| 203 | + | |
| 204 | + | |
| 205 | + | |
| 206 | + | |
| 207 | + | |
202 | 208 | | |
203 | 209 | | |
204 | 210 | | |
205 | 211 | | |
206 | 212 | | |
207 | | - | |
208 | | - | |
| 213 | + | |
| 214 | + | |
| 215 | + | |
| 216 | + | |
209 | 217 | | |
210 | 218 | | |
211 | 219 | | |
212 | 220 | | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
213 | 232 | | |
214 | 233 | | |
215 | 234 | | |
| |||
0 commit comments