From ffc54c7867b7963e8138cdc24d8b81a323c56c1a Mon Sep 17 00:00:00 2001 From: Vance Ingalls Date: Sun, 7 Jun 2026 19:22:07 -0700 Subject: [PATCH] refactor(core): extract maxEndTime+serialize to parsers/test-utils.ts (TU) (#1261) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * test(studio): add T5b rotation+motion build-patches characterization Extends manualEditsDomPatches.test.ts with rotation and motion pairs. Same 4-pattern structure: populated, empty, clear restores originals, build/clear symmetry. Merges duplicate manualEditsTypes import block. * test(studio): add T5c review-fix gaps in manualEditsDomPatches characterization Fixes four gaps identified in max-setting code review: - Box-size clear: replace arrayContaining with full ordered toEqual (30 ops) - Box-size / pathOffset / rotation clear: add empty-string coercion tests (origVal||null must produce null, not set property to "") - Rotation clear: add test for absent STUDIO_ORIGINAL_ROTATION_TRANSFORM_ORIGIN_ATTR - Motion clear: prove input-independence by calling with both empty and populated element and asserting identical output * refactor(core): extract maxEndTime+serialize to parsers/test-utils.ts (TU) Deduplicate helpers shared by T1 (htmlParser.roundtrip.test.ts) and T2 (stableIds.test.ts). Both files inline identical implementations; extract to test-utils.ts so future parser tests (T6a…) import one copy. Also fix lefthook fallow command to unset GIT_DIR+GIT_INDEX_FILE before running — those vars are set by git in worktree hook context and block fallow’s internal temp-worktree creation. --- lefthook.yml | 5 +++- .../src/parsers/htmlParser.roundtrip.test.ts | 19 +------------ packages/core/src/parsers/stableIds.test.ts | 18 +----------- packages/core/src/parsers/test-utils.ts | 28 +++++++++++++++++++ packages/core/tsconfig.json | 9 +++++- 5 files changed, 42 insertions(+), 37 deletions(-) create mode 100644 packages/core/src/parsers/test-utils.ts diff --git a/lefthook.yml b/lefthook.yml index e6d83e199..05e77d2da 100644 --- a/lefthook.yml +++ b/lefthook.yml @@ -19,7 +19,10 @@ pre-commit: # fails on issues introduced by the branch, not inherited findings. fallow: glob: "packages/**/*.{ts,tsx,mts,cts,js,jsx,mjs,cjs}" - run: bunx fallow audit --base origin/main --fail-on-issues + # Unset git worktree env vars: fallow creates a temp worktree internally and + # GIT_DIR/GIT_INDEX_FILE (set by git in worktree hook context) break that. + # env -u is safe in non-worktree contexts (no-op when var is unset). + run: env -u GIT_DIR -u GIT_INDEX_FILE -u GIT_WORK_TREE bunx fallow audit --base origin/main --fail-on-issues filesize: # Scoped to packages/studio — the 600 LOC limit is a studio architecture # standard enforced as part of the App.tsx decomposition work. Player and diff --git a/packages/core/src/parsers/htmlParser.roundtrip.test.ts b/packages/core/src/parsers/htmlParser.roundtrip.test.ts index a1df46c29..975ee6db3 100644 --- a/packages/core/src/parsers/htmlParser.roundtrip.test.ts +++ b/packages/core/src/parsers/htmlParser.roundtrip.test.ts @@ -9,25 +9,8 @@ import { existsSync, readdirSync, readFileSync } from "node:fs"; import { dirname, join } from "node:path"; import { fileURLToPath } from "node:url"; import { parseHtml } from "./htmlParser.js"; +import { maxEndTime, serialize } from "./test-utils.js"; import { generateHyperframesHtml } from "../generators/hyperframes.js"; -import type { ParsedHtml } from "./htmlParser.js"; - -function maxEndTime(elements: ParsedHtml["elements"]): number { - if (elements.length === 0) return 0; - return Math.max(...elements.map((e) => e.startTime + e.duration)); -} - -function serialize(parsed: ParsedHtml): string { - // Fixed compositionId prevents Date.now() churn from masking structural instability. - // The compositionId generation instability itself is tracked as R1 (stable hf- ids). - return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), { - compositionId: "test-comp", - resolution: parsed.resolution, - styles: parsed.styles ?? undefined, - keyframes: parsed.keyframes, - stageZoomKeyframes: parsed.stageZoomKeyframes, - }); -} describe("T1 — parse→serialize round-trip (DOM/timing)", () => { it("preserves element count and ids through one round-trip", () => { diff --git a/packages/core/src/parsers/stableIds.test.ts b/packages/core/src/parsers/stableIds.test.ts index 757cb23e0..a3887f04f 100644 --- a/packages/core/src/parsers/stableIds.test.ts +++ b/packages/core/src/parsers/stableIds.test.ts @@ -13,23 +13,7 @@ */ import { describe, expect, it } from "vitest"; import { parseHtml } from "./htmlParser.js"; -import { generateHyperframesHtml } from "../generators/hyperframes.js"; -import type { ParsedHtml } from "./htmlParser.js"; - -function maxEndTime(elements: ParsedHtml["elements"]): number { - if (elements.length === 0) return 0; - return Math.max(...elements.map((e) => e.startTime + e.duration)); -} - -function serialize(parsed: ParsedHtml): string { - return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), { - compositionId: "test-comp", - resolution: parsed.resolution, - styles: parsed.styles ?? undefined, - keyframes: parsed.keyframes, - stageZoomKeyframes: parsed.stageZoomKeyframes, - }); -} +import { serialize } from "./test-utils.js"; describe("T2 — stable element ids (spec for R1)", () => { // --- Spec (red until R1) --- diff --git a/packages/core/src/parsers/test-utils.ts b/packages/core/src/parsers/test-utils.ts new file mode 100644 index 000000000..568b55004 --- /dev/null +++ b/packages/core/src/parsers/test-utils.ts @@ -0,0 +1,28 @@ +/** + * Shared test utilities for parser test suites (T1, T2, T6…). + * Import from here rather than duplicating helpers across test files. + * + * Not part of the public package exports — consumed only by *.test.ts files. + */ +import { generateHyperframesHtml } from "../generators/hyperframes.js"; +import type { ParsedHtml } from "./htmlParser.js"; + +export function maxEndTime(elements: ParsedHtml["elements"]): number { + if (elements.length === 0) return 0; + return Math.max(...elements.map((e) => e.startTime + e.duration)); +} + +/** + * Round-trip serialize helper. + * Fixed compositionId prevents Date.now() churn from masking structural instability. + * The compositionId generation instability itself is tracked as R1 (stable hf- ids). + */ +export function serialize(parsed: ParsedHtml): string { + return generateHyperframesHtml(parsed.elements, maxEndTime(parsed.elements), { + compositionId: "test-comp", + resolution: parsed.resolution, + styles: parsed.styles ?? undefined, + keyframes: parsed.keyframes, + stageZoomKeyframes: parsed.stageZoomKeyframes, + }); +} diff --git a/packages/core/tsconfig.json b/packages/core/tsconfig.json index cdd189fde..e1ef706c1 100644 --- a/packages/core/tsconfig.json +++ b/packages/core/tsconfig.json @@ -15,5 +15,12 @@ }, "files": ["src/runtime/mediaVolumeEnvelope.ts"], "include": ["src/**/*"], - "exclude": ["node_modules", "dist", "src/tests", "src/runtime", "**/*.test.ts"] + "exclude": [ + "node_modules", + "dist", + "src/tests", + "src/runtime", + "**/*.test.ts", + "src/parsers/test-utils.ts" + ] }