mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-08 10:46:06 +00:00
feat(cli): report which catalog items a render actually used (#3470)
`registry_item_added` fires when a catalog block is installed and `render_complete` fires when a video is produced, but nothing joined them, so "did this video use the catalog?" had no answer. `hyperframes add` now records each installed item in `hyperframes.json` (installed files are plain composition HTML with no provenance marker, so this manifest is the only record that a file came from the registry), and `render_complete` reports both the items the project installed and the blocks the rendered composition actually reaches. An item installed and then never mounted was tried and dropped, which no add-time event can express. The scan answering "which sub-compositions does this file mount" now has one owner, `collectSubCompositionSrcs` in `@hyperframes/parsers`, shared with lint's `lintMissingOrEmptySubComposition`. It holds two invariants that were previously restated per call site and got re-derived wrongly: it is a text scan rather than a DOM query, because `<template>` content is inert and every sub-composition except the render entry is wrapped in one; and references resolve root-relative at every nesting level, matching `parseSubCompositions`. It walks tag by tag rather than running open-ended spans across the whole file, so a malformed composition cannot stall the render plan. Also: `registryItems` is declared in the config schema, which closes with `additionalProperties: false`, with an ajv-backed test pinning every key the CLI writes; counts are never truncated by the name cap, and the reported used blocks stay a subset of the reported installed ones, with `registry_items_truncated` marking a windowed list; and an unreadable manifest reports itself rather than posing as a project that never used the catalog.
This commit is contained in:
@@ -7,6 +7,7 @@ import { checkSubCompositionUsability } from "@hyperframes/parsers/sub-compositi
|
||||
import { parseHTML } from "linkedom";
|
||||
import {
|
||||
cleanAssetUrl,
|
||||
collectSubCompositionSrcs,
|
||||
isRemoteOrInlineUrl,
|
||||
isUnresolvedAssetPlaceholder,
|
||||
isWithinProjectRoot,
|
||||
@@ -588,14 +589,9 @@ function lintMissingOrEmptySubComposition(
|
||||
|
||||
// fallow-ignore-next-line complexity
|
||||
const walk = (html: string): void => {
|
||||
const compositionSrcRe = /<[^>]*\bdata-composition-src\s*=\s*["']([^"']+)["'][^>]*>/gi;
|
||||
const scannable = maskNonScannableRanges(html);
|
||||
let match: RegExpExecArray | null;
|
||||
while ((match = compositionSrcRe.exec(scannable)) !== null) {
|
||||
const srcPath = (match[1] ?? "").trim();
|
||||
if (!srcPath) continue;
|
||||
if (isUnresolvedAssetPlaceholder(srcPath)) continue; // __UPPER__ placeholder or late-bound templating token
|
||||
|
||||
// Shared scanner — see collectSubCompositionSrcs for why this must be a
|
||||
// text scan rather than a DOM query (template content is inert).
|
||||
for (const srcPath of collectSubCompositionSrcs(html)) {
|
||||
// data-composition-src is always written root-relative (even from a
|
||||
// nested sub-composition) — matches the resolution the renderer uses
|
||||
// in packages/producer/src/services/htmlCompiler.ts (parseSubCompositions
|
||||
|
||||
Reference in New Issue
Block a user