fix(core): an added sub-composition keeps its declared variable defaults when bundled - #4539
Conversation
…lts when bundled parseHTMLContent only treated input as a full document when it started with a doctype or <html>. Files installed by `hyperframes add` start with a marker comment, so they were wrapped as a fragment in a new <html> and lost their own <html data-composition-variables>. Leading comments are now skipped first.
…iables isFullHtmlDocument moves to core beside parseHTMLContent and both callers use it, so the standalone preview of a file that `hyperframes add` installed (a marker comment above the doctype) is treated as the full document it is. The leading-comment skip also handles an empty `<!-->` comment, and `<html-card>` style elements no longer count as a document.
terencecho
left a comment
There was a problem hiding this comment.
Reviewed 41b7f8196805bebde4a74ca1e7fca7e1d3c4c24e. Approved on code merit. The CLI's add marker precedes the sub-composition document; the shared isFullHtmlDocument now skips leading comments/whitespace before checking for the doctype or <html>. The bundler parses that file as a document, reads its declared defaults, merges the variables into the bundled composition table, and Studio uses the same document predicate.
In an isolated worktree, 113 focused parser, bundler and Studio-preview tests passed. Bundling the actual marker-prefixed carousel-orbit-1 yielded all 24 image defaults with their assets/carousel-images/ paths (26 defaults total); the previous fragment wrapper lost its <html data-composition-variables> carrier. I inspected the supplied before/after captures and saw white cards become populated image cards. I did not independently run a browser/network trace to verify the asserted 48→0 request count. Parser probes covered whitespace/comments, case variants, and fragment-like <html-card> starts. A malformed <!DOCTYPEhtml><div…> prefix can be misclassified as a full document in Studio; that invalid-input edge is worth tightening but is not a blocker for the valid marked-document fix. At review time completed required checks were green, with some test/Windows shards still running; approval is not a claim that CI had fully settled.
— Review by tai (pr-review)
What changes
A sub-composition installed with
hyperframes addkeeps its declared variable defaults in two places: when the project is bundled withbundleToSingleHtml, and in Studio's standalone preview of that file. Inside the sub-composition,getVariables()returns those defaults again. The carousel blocks, for example, load their images fromassets/carousel-images/instead of 404ing on bare file names and drawing white cards.Why it happened
parseHTMLContentdecided whether its input was a full document or a fragment by checking whether it started with<!doctypeor<html.hyperframes addwrites a<!-- hyperframes-registry-item: ... -->marker comment above the doctype of every file it installs. Those files were therefore parsed as fragments and wrapped in a fresh<html>, which dropped their own<html data-composition-variables>.The sub-composition inliner then read no declared defaults and emitted no
__hfVariablesByCompentry for the instance, so the scopedgetVariables()had nothing to return. The CSS custom properties for the same sub-composition were unaffected, because that path reads the defaults differently.The fix
isFullHtmlDocumentin core'shtmlDocument.tsdecides document versus fragment once. It skips leading whitespace and comments (an empty<!-->included), then looks for<!doctypeor<htmlfollowed by whitespace or>. So a<html-card>element no longer counts.parseHTMLContentuses it. Every compiler path that parses a composition goes throughparseHTMLContent, so the bundler, the sub-composition inliner and the template mount all see the file's real<html>element.data-composition-variablesfrom<html>and nested a second<html>inside<body>. That copy is deleted, and the preview imports the core predicate through@hyperframes/core/compiler/html-document.Tests
htmlDocument.test.ts: a document that starts with a comment keeps its<html>attributes.htmlDocument.test.ts: document versus fragment past leading comments, an empty comment, and a<html-card>element.htmlBundler.test.ts: a sub-composition that starts with the install marker has its declared default in__hfVariablesByCompafter bundling.subComposition.test.ts(studio-server): an installed block's preview keepsdata-composition-variableson<html>and nests no<html>in<body>.The first bundler and document tests fail on
main, and the studio-server test fails on the previous studio-server code. The core suite passes (3199 tests), as do the studio-server helper tests (348) and both typechecks.Before
carousel-orbit-1added withhyperframes add, its snippet wrapped in a rootindex.html, bundled withbundleToSingleHtml(runtime inline) and loaded in Chromium onmain. There are 48 failed image requests for bare names such as/artist-bob-seger.jpg, and every card is white.After
The same project bundled on this branch. The bundle carries the block's 24 image defaults, there are 0 failed requests, and the cards show their images.
Not in this PR
root_composition_missing_html_wrappermakes its own start-of-file check and would flag a rootindex.htmlthat begins with a comment. Installed blocks are not root files, so they do not reach it.getVariables()returns nothing for an image. It should keep theassets/carousel-images/folder. That affects 25 registry blocks and the generated catalog pages, so it is a separate PR.