Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions .changeset/4795-check-bindable-text-keys.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
'@object-ui/cli': minor
---

feat(cli): `objectui check` refuses a `${…}` on a text key its node never evaluates

`SchemaRenderer` evaluates an expression on the closed text keys `title`,
`label`, `value` and `description` only where `@objectstack/spec`'s
`expressionBindableTextKeysFor(type)` lists that key for the node's type.
Anywhere else the expression is never resolved, so the user sees
`${data.total}` as literal text, or nothing at all — and no step before the
browser said so.

`objectui check` now refuses such an expression in every file it recognises as
an ObjectUI schema, and the run exits non-zero. The refusal names the key, the
path to it (spelled as `objectui validate` spells paths), the keys that type
does evaluate, and the channels `SchemaRenderer` evaluates. Types with no row in
the carriage map are refused too: `text.value` and `action:button.label` are
never evaluated.

- **Component nodes only**: the file's root node and every node its `children`
hold. Objects under other keys, such as a form's `fields` entries, are
definitions rather than nodes and are not judged. A root of type `page` keeps
its own `title`, which is a page key; its `children` are still judged.
- **The type is matched as written**, as the runtime matches it: `ui:card` has
no row, and is not read as `card`.
- **A type no registered component answers to** gets a warning instead of a
refusal, because a custom renderer may evaluate its own keys.
- **There is no escape spelling**: a `${…}` meant as literal text on one of
these keys, such as a code sample in a `code-editor`'s `value`, is refused
too. Write it without `${`.

The key vocabulary and the per-type carriage map are read from
`@objectstack/spec`, now a declared dependency of `@object-ui/cli`, so a row
added upstream moves this check and the runtime together.
40 changes: 34 additions & 6 deletions content/docs/utilities/cli.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -224,13 +224,41 @@ distinction matters:
Issue at map: Unrecognized key: "latitudeFieId"
```

A run with no parse errors ends on a tally rather than a pass: how many
recognised files validated, how many were recognised by a structural key and not
validated, and how many did not validate, followed by a pointer to
`objectui validate` for the verdict.
#### Expressions on text keys that are never evaluated

`SchemaRenderer` evaluates a `${…}` expression on the closed text keys `title`,
`label`, `value` and `description` only where `@objectstack/spec`'s
`expressionBindableTextKeysFor(type)` lists that key for the node's type. On any
other type, the expression is never resolved: the user sees its literal text, or
nothing. `objectui check` refuses it in every recognised file:

- **Component nodes only.** The file's root node and every node its `children`
hold, at any depth. Objects under other keys (a form's `fields`, a grid's
`columns`) are definitions, not nodes, and are not judged. A root whose `type`
is `page` keeps its own `title`: that is a page key, while its `children` are
still judged.
- **The type is matched as written.** `ui:card` is not `card`, exactly as at
render time.
- **A type no registered component answers to** is warned about, not refused: a
custom renderer may evaluate its own keys.
- **There is no escape spelling.** A `${…}` meant as literal text on one of
these keys — a code sample in a `code-editor`'s `value`, a shell `${VAR}` — is
refused too. Write the text without `${`, for example with string
concatenation in a code sample.

Only unreadable JSON makes `objectui check` exit non-zero; everything above is a
report. Use `objectui validate` when you want a failing exit code.
```text
x Unevaluated expression in dashboard.json at children → 0 → title: "statistic" never evaluates `title` (it evaluates only `label`, `value`, `description`), so the expression is never resolved: the user sees its literal text, or nothing.
Channels SchemaRenderer evaluates: `label`, `value`, `description`, `content`, `properties.title` (evaluated, then hoisted onto the node); or resolve the value in the host before the schema reaches SchemaRenderer.
```

A run with no parse errors and no refused expression ends on a tally rather than
a pass: how many recognised files validated, how many were recognised by a
structural key and not validated, and how many did not validate, followed by a
pointer to `objectui validate` for the verdict.

Unreadable JSON and a refused expression make `objectui check` exit non-zero;
everything else above is a report. Use `objectui validate` when you want a
failing exit code on a document that does not validate.

### `objectui doctor`

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"type": "code-editor",
"value": "function greet(name) {\n console.log(`Hello, ${name}!`);\n return `Welcome, ${name}`;\n}\n\ngreet('Developer');",
"value": "function greet(name) {\n console.log('Hello, ' + name + '!');\n return 'Welcome, ' + name;\n}\n\ngreet('Developer');",
"language": "javascript",
"theme": "vs-dark",
"height": "300px"
Expand Down
1 change: 1 addition & 0 deletions packages/cli/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@object-ui/components": "workspace:*",
"@object-ui/react": "workspace:*",
"@object-ui/types": "workspace:*",
"@objectstack/spec": "^17.1.0",
"@tailwindcss/postcss": "^4.3.3",
"@types/glob": "^9.0.0",
"@vitejs/plugin-react": "^6.0.5",
Expand Down
Loading
Loading