feat(core,cli): variable schema validation + lint rules (PR 3/4)#602
Merged
jrusso1020 merged 2 commits intomainfrom May 4, 2026
Merged
feat(core,cli): variable schema validation + lint rules (PR 3/4)#602jrusso1020 merged 2 commits intomainfrom
jrusso1020 merged 2 commits intomainfrom
Conversation
This was referenced May 3, 2026
Collaborator
Author
This was referenced May 3, 2026
miguel-heygen
approved these changes
May 3, 2026
vanceingalls
approved these changes
May 4, 2026
75f892b to
1da6f45
Compare
a10b3f6 to
239c3c8
Compare
Two lint rules + render-time validation built on top of the existing
data-composition-variables schema.
Lint rules (packages/core/src/lint/rules/composition.ts):
- invalid_variable_values_json — host's data-variable-values must parse as
a JSON object. Today the runtime swallows parse failures silently and
falls back to declared defaults, masking typos.
- invalid_composition_variables_declaration — root <html>'s
data-composition-variables must parse as an array of objects with
`id` (string), `type` (one of string/number/color/boolean/enum), `label`
(string), and `default`. Per-entry findings report which fields are
missing or invalid.
Both rules read attributes via a new `readJsonAttr` helper in lint/utils.ts.
The existing `readAttr` regex `["']([^"']+)["']` truncates JSON-in-attribute
values at the first internal quote (e.g. `data-variable-values='{"x":"y"}'`
captures only `{`); `readJsonAttr` alternates double-vs-single-quoted
branches with quote-specific char classes so JSON values round-trip cleanly.
A second helper `findHtmlTag` returns the actual <html> open tag (where
data-composition-variables lives) — distinct from `findRootTag` which
returns the first in-body composition element.
Render-time validation (packages/core/src/runtime/validateVariables.ts):
- validateVariables(values, declarations) returns a structured array of
issues: undeclared keys, type mismatches, enum-out-of-range values.
Pure / sync; works in any environment.
- formatVariableValidationIssue(issue) renders a one-line user-facing
string for CLI output.
- Both exported from @hyperframes/core for studio/tooling reuse.
CLI integration (packages/cli/src/commands/render.ts):
- New --strict-variables flag. Default behavior: print warnings and
continue. With --strict-variables: print warnings then exit 1.
- New `validateVariablesAgainstProject(indexPath, values)` helper:
reads the project's index.html, runs extractCompositionMetadata to
pull the declared schema, validates the CLI's --variables payload
against it. ensureDOMParser polyfill for Node-side parsing (same
pattern as compositions.ts).
Tests:
- 11 new validateVariables unit tests covering happy path, undeclared
keys, type mismatches (string/number/boolean/color/enum), enum range,
multiple-issue aggregation, and formatter output.
- 11 new composition.test.ts cases for both lint rules: parse errors,
shape errors, per-entry validation, unknown types, missing fields,
positive cases.
- 5 new render.test.ts cases for validateVariablesAgainstProject:
no-declarations, happy path, undeclared, type-mismatch, missing-file.
- All 646 core tests + 213 cli tests still green.
Docs:
- docs/packages/cli.mdx — added --strict-variables flag row.
This is PR 3 of a 4-PR stack. PR 4 ships skill/scaffold distribution.
Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
239c3c8 to
366a64c
Compare
- core.types.ts: export COMPOSITION_VARIABLE_TYPES, a runtime tuple of every CompositionVariableType variant guarded by `as const satisfies readonly CompositionVariableType[]`. Adding a new variant to the union without also adding it to the tuple becomes a compile error rather than silent drift in callers that maintain their own list. - composition.ts (lint rule): the local `new Set(["string","number","color","boolean","enum"])` now derives from COMPOSITION_VARIABLE_TYPES instead of duplicating the list. - index.ts: export COMPOSITION_VARIABLE_TYPES alongside the rest of the variable type guards. Reuse + efficiency reviews otherwise clean. The other reuse finding (loadProjectHtml helper to dedupe readFileSync + ensureDOMParser across 3 callers) is real but reaches files outside this PR's scope; it's a better fit as a follow-up cleanup once the variable-feature stack lands. All 48 composition lint tests + 49 core suite tests still green. Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
366a64c to
09da5db
Compare
Collaborator
Author
Merge activity
|
jrusso1020
added a commit
that referenced
this pull request
May 4, 2026
…603) ## What Distribution PR for the variables feature stack. Tells agents how to declare, read, and override variables across the four authoring surfaces — the two skill files agents load (`hyperframes`, `hyperframes-cli`), the public docs (`docs/packages/core.mdx`), and the in-CLI docs (`npx hyperframes docs compositions`). This is **PR 4 of 4**, the final PR in the stack. Stacked on `feat/get-variables-validation` (PR #602). ## Why PRs 1–3 added the runtime helper, sub-comp scoping, and schema validation, but the only places that mention them are the docs in those PRs. Agents loading `/hyperframes` or `/hyperframes-cli` skills won't know the new attributes/flags exist. This PR closes the loop. ## How - **`skills/hyperframes/SKILL.md`** — new "Variables (Parametrized Compositions)" section right after "Composition Structure" with: declare/read/override pattern, full worked example (with enum), sub-comp per-instance pattern (two hosts sharing a source), rules of thumb (defaults always, read-once, `--strict-variables` in CI, type validation behavior). Also added `data-variable-values` + `data-composition-variables` rows to the existing data-attributes tables. - **`skills/hyperframes-cli/SKILL.md`** — added `--variables`, `--variables-file`, `--strict-variables` to the render flag table; short paragraph forwarding to the hyperframes skill for the full pattern. - **`docs/packages/core.mdx`** — added a code snippet showing `getVariables<T>()` and `validateVariables` / `formatVariableValidationIssue` for tooling that validates CLI / host overrides. - **`packages/cli/src/docs/compositions.md`** — replaced the obsolete `JSON.parse(host.dataset.variableValues)` example with the modern `getVariables()` pattern. The `openai/plugins` mirror is intentionally out of scope. Skills in this repo are the source of truth; the downstream mirror is updated after each release as a separate workflow. ## Test plan - [x] Doc-only PR — no source code, no tests. - [x] Format check passes via `bunx oxfmt --check` on the touched markdown files. - [x] Manual review confirms each example compiles in head against the runtime/CLI surface that PRs 1–3 ship. ## Backwards compatibility Doc-only — no behavior change. 🤖 Generated with [Claude Code](https://claude.com/claude-code)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.

What
Adds two lint rules + render-time validation for the variable system shipped in PR #600 + PR #601. Authors get fast feedback when JSON is malformed, declarations are missing required fields, or
--variablesvalues don't match the declared schema.This is PR 3 of a 4-PR stack — based on
feat/get-variables-subcomp(PR #601). Will retarget tomainafter PRs 1 + 2 merge.Why
The runtime today silently masks several classes of mistake:
data-variable-valuesJSON makes the parser return{}and the script reads stale declared defaults, with no visible signal.data-composition-variablesdeclaration (missingid, wrongtype) gets silently filtered out.--variables '{"titel":"x"}'instead of"title"renders fine and produces the wrong output.These are exactly the cases lint + schema validation are good at catching.
How
Lint rules (
packages/core/src/lint/rules/composition.ts):invalid_variable_values_json— host'sdata-variable-valuesmust parse as a JSON object.invalid_composition_variables_declaration— root<html>'sdata-composition-variablesmust parse as an array of objects withid,type(one of string/number/color/boolean/enum),label, anddefault. Per-entry findings report which fields are missing or invalid.Both rules read via a new
readJsonAttrhelper inlint/utils.ts. The existingreadAttr's regex["']([^"']+)["']truncates JSON-in-attribute values at the first internal quote —data-variable-values='{"x":"y"}'would capture only{. The new helper alternates double-vs-single-quoted branches with quote-specific char classes. A second helperfindHtmlTagreturns the<html>open tag (wheredata-composition-variableslives), distinct fromfindRootTagwhich returns the first in-body composition element.Render-time validation (
packages/core/src/runtime/validateVariables.ts):validateVariables(values, declarations)returns a structured array ofVariableValidationIssues —undeclared,type-mismatch, orenum-out-of-range. Pure / sync; works in any environment.formatVariableValidationIssuerenders one-line user-facing strings for CLI output.@hyperframes/core.CLI integration (
packages/cli/src/commands/render.ts):--strict-variablesflag. Default: print warnings, continue. Strict: print warnings, exit 1.validateVariablesAgainstProject(indexPath, values)helper reads the project'sindex.html, pulls the declared schema viaextractCompositionMetadata, validates the CLI payload. Uses the existingensureDOMParserpolyfill (same pattern ascompositions.ts).Test plan
validateVariablesunit tests — happy path, undeclared keys, type mismatches (every type), enum range, multi-issue aggregation, formatter output.composition.test.tscases — both lint rules: parse errors, shape errors, per-entry validation, unknown types, positive cases for valid declarations.render.test.tscases —validateVariablesAgainstProject: no-declarations, happy path, undeclared, type-mismatch, missing-file.--variables '{"title":"x"}'against an index that declarestitleas string → no warnings.--variables '{"count":"three"}'againstcount: number→ warning printed, render continues.--strict-variables→ exit 1 before render starts.docs/packages/cli.mdx— added--strict-variablesflag row.Backwards compatibility
Fully additive. Existing compositions emit zero new lint findings (the rules only fire on malformed JSON or invalid declarations, which the runtime would have silently dropped anyway). Existing
hyperframes renderinvocations behave identically without the new flag.🤖 Generated with Claude Code