mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
refactor(core,studio): extract draft-marker constants + R7 code-review fixes (Task 4) (#1292)
* refactor(core,studio): extract draft-marker constants to core (R7, Task 4) Create draftMarkers.ts in core with 5 shared CSS custom property names and the gesture DOM attribute. PreviewAdapter imports from draftMarkers.ts instead of hardcoding strings. Adds @hyperframes/core/studio-api/draft-markers export subpath. Studio's manualEditsTypes.ts re-exports the shared constants from core so all existing call sites are unchanged. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(core): address R7 code-review findings (C1–C14, P6–P7) - previewAdapter: auto-revert previous gesture in applyDraft (C3); clearDraftProps on commitPreview not just revertDraft (C4); isVisible NaN→visible for JSDOM (P7); remove redundant GestureState.hfId field (C12); remove Array.from (C14); extract clearDraftProps/revertGesture helpers (C5/C6) - hfIdPersist: replace string-equality change detection with attribute count to avoid false-positive writes on single-quoted HTML (C1); re-read disk before write for TOCTOU guard (C7); remove normalizeHfIds wrapper (C11) - preview.ts: remove dead null-check on normalizedDisk after diskMain guard (C9); catch path re-reads disk fresh instead of using stale pre-request snapshot (C8) - hfIds.test.ts: replace tautological second stability test with cross-document content-keyed id stability test (P6) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * fix(core): follow-up R7 review fixes — CSS.escape fallback, invariant docs, new edge-case tests - hfIdPersist: remove ensureHfIds re-export (P2); add JSDoc invariant note; improve TOCTOU comment; pass err to console.warn - preview.ts: split import — ensureHfIds from parsers/hfIds.js (not re-export) - previewAdapter: CSS.escape + inline fallback for non-browser environments; add JSDoc for atTime caller-seek contract; add 0.01 opacity-threshold comment - previewAdapter.test: rename atTime test to clarify adapter-does-not-seek; add nested-hf-root-without-id test; add resize→move prop-leak test; add revertDraft-after-commit no-op test Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * test(core): bundle-vs-disk id-stability test; comment double ensureHfIds (P3) - preview.test: add "bundle returning untagged HTML gets same ids as disk" test — guards against id divergence when bundler reads a pre-write cache snapshot; content-keyed FNV1a minting ensures served ids == disk ids for same source HTML - preview.ts: comment the second ensureHfIds call explaining it's intentional for adapter-injected elements and idempotent on the no-bundle path (P3 from miguel) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> * docs(core): wire-contract comment on mintHfId + fallow suppressions (R7) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com> --------- Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Sonnet 4.6
parent
1a23938bef
commit
3d7d7c0291
@@ -88,12 +88,14 @@ describe("ensureHfIds", () => {
|
||||
expect(ids(ensureHfIds(edited))).toContain(originalId);
|
||||
});
|
||||
|
||||
it("pinned id survives attribute edit after first persist", () => {
|
||||
const raw = `<!doctype html><html><body><div class="old">text</div></body></html>`;
|
||||
const persisted = ensureHfIds(raw); // simulates write-back on first serve
|
||||
const [originalId] = ids(persisted);
|
||||
const edited = persisted.replace('class="old"', 'class="new"');
|
||||
expect(ids(ensureHfIds(edited))).toContain(originalId);
|
||||
// Hash-based stability (no prior pin): the same element content yields the
|
||||
// same id regardless of what sibling elements appear in the document.
|
||||
it("content-keyed minting is stable: same element content → same id in different documents", () => {
|
||||
const alone = `<!doctype html><html><body><div class="card">hello</div></body></html>`;
|
||||
const [idAlone] = ids(ensureHfIds(alone));
|
||||
// The <div class="card">hello</div> appears alongside a new sibling here.
|
||||
const withSibling = `<!doctype html><html><body><span>prefix</span><div class="card">hello</div></body></html>`;
|
||||
expect(ids(ensureHfIds(withSibling))).toContain(idAlone);
|
||||
});
|
||||
});
|
||||
|
||||
|
||||
@@ -67,6 +67,13 @@ function contentKey(el: Element): string {
|
||||
* (`if (el.getAttribute("data-hf-id")) continue`), so normal operation
|
||||
* never re-exposes the ordering after first persist.
|
||||
*/
|
||||
// WIRE CONTRACT: id minting is content-keyed (FNV1a of innerHTML + tag). R7's
|
||||
// preview route relies on mintHfId producing identical ids across mint contexts
|
||||
// (disk-persist pass vs. in-memory bundle pass) — see preview.test.ts
|
||||
// "bundle returning untagged HTML gets same ids as disk". Any change that adds
|
||||
// positional, session, or random input to the hash breaks that invariant and
|
||||
// makes hf- ids diverge between disk and served HTML, silently corrupting
|
||||
// drag-to-edit targeting.
|
||||
export function mintHfId(el: Element, assigned: Set<string>): string {
|
||||
const key = contentKey(el);
|
||||
let id = toHfId(fnv1a(key));
|
||||
|
||||
Reference in New Issue
Block a user