Skip to content

Commit 05af338

Browse files
committed
merge: pull in the fallow-audit fixes
2 parents 27fb8a8 + 1a2969a commit 05af338

7 files changed

Lines changed: 129 additions & 113 deletions

File tree

.fallowrc.jsonc

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,28 @@
654654
// inherited clone; consistent with the norm above of leaving parallel
655655
// command-test cases unabstracted.
656656
"packages/cli/src/commands/check.test.ts",
657+
// canary.test.ts: rawFnv is a deliberate independent re-implementation of
658+
// canary.ts's fnv1a32, not copy-paste — its own docstring explains why:
659+
// the test re-derives the hash so it can cross-check canaryBucket against
660+
// a copy that owes it nothing, rather than importing the function under
661+
// test. Importing fnv1a32 here would defeat the point of the assertion.
662+
"packages/core/src/canary.test.ts",
663+
// The audio FX property-panel test files (and the two siblings outside
664+
// this stack, propertyPanelFlatMotionSection.test.tsx and
665+
// propertyPanelFlatEffectsSection.test.tsx) share a `renderInto` React
666+
// mount helper — pre-existing across nine files, not introduced here.
667+
// The FxSection/FlatTextSection `mount()` wrappers additionally look
668+
// alike because both build a props-with-overrides harness for their own
669+
// component; the prop shapes differ per component, so a shared mount
670+
// abstraction would obscure more than it dedupes (same rationale as
671+
// slideshowPanelHelpers.ts above).
672+
"packages/studio/src/components/editor/PropertyPanelEmptyState.test.tsx",
673+
"packages/studio/src/components/editor/propertyPanelFlatColorGradingSection.test.tsx",
674+
"packages/studio/src/components/editor/propertyPanelFlatLayoutSection.test.tsx",
675+
"packages/studio/src/components/editor/propertyPanelFlatPrimitives.test.tsx",
676+
"packages/studio/src/components/editor/propertyPanelFlatTextSection.test.tsx",
677+
"packages/studio/src/components/editor/propertyPanelFlatToggle.test.tsx",
678+
"packages/studio/src/components/editor/propertyPanelFxSection.test.tsx",
657679
],
658680
},
659681
"health": {

packages/core/package.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -556,9 +556,9 @@
556556
"typecheck": "tsc --noEmit && bun run typecheck:runtime",
557557
"typecheck:runtime": "tsc --noEmit -p tsconfig.runtime.json",
558558
"lint:runtime-preview-guards": "bun scripts/lint-runtime-preview-guards.ts",
559-
"build:audio-fx-runtime": "tsx scripts/build-audio-fx-runtime.ts",
559+
"build:audio-fx-runtime": "tsx scripts/build-inline-artifact.ts audio-fx",
560560
"build:hyperframes-runtime": "tsx scripts/build-hyperframes-runtime-artifact.ts",
561-
"build:position-edits-render": "tsx scripts/build-position-edits-render.ts",
561+
"build:position-edits-render": "tsx scripts/build-inline-artifact.ts position-edits",
562562
"check:position-edits-render": "bun run build:position-edits-render && git diff --exit-code -- src/generated/position-edits-render-inline.ts",
563563
"build:hyperframes-runtime:modular": "SANDBOX_RUNTIME_VARIANT=modular tsx scripts/build-hyperframes-runtime-artifact.ts",
564564
"build:hyperframe-runtime": "tsx scripts/build-hyperframes-runtime-artifact.ts",

packages/core/scripts/build-audio-fx-runtime.ts

Lines changed: 0 additions & 50 deletions
This file was deleted.
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
/**
2+
* Bundle one canonical-runtime entry to a minified IIFE with esbuild and write
3+
* it into `src/generated` as a string constant behind a getter.
4+
*
5+
* One script handles both inline artifacts — the audio-FX runtime and the
6+
* position-edits render — since they differ only in the entry, output names,
7+
* and log event. Keeping them as separate files produced a byte-for-byte
8+
* clone that fallow kept re-flagging on every unrelated line shift.
9+
*/
10+
11+
import { mkdirSync, writeFileSync } from "node:fs";
12+
import { dirname, resolve } from "node:path";
13+
import { fileURLToPath } from "node:url";
14+
import { buildSync } from "esbuild";
15+
import { execFileSync } from "node:child_process";
16+
17+
interface InlineArtifactTarget {
18+
entryRelPath: string;
19+
generatedFileName: string;
20+
constName: string;
21+
getterName: string;
22+
/** Filename shown in the esbuild-failure error. */
23+
entryLabel: string;
24+
/** Human phrase for the generated getter's doc comment, e.g. "audio-FX runtime". */
25+
docLabel: string;
26+
event: string;
27+
}
28+
29+
const TARGETS: Record<string, InlineArtifactTarget> = {
30+
"audio-fx": {
31+
entryRelPath: "stubs/audio-fx-runtime-entry.ts",
32+
generatedFileName: "audio-fx-runtime-inline.ts",
33+
constName: "AUDIO_FX_RUNTIME_IIFE",
34+
getterName: "getAudioFxRuntimeScript",
35+
entryLabel: "audio-fx-runtime-entry.ts",
36+
docLabel: "audio-FX runtime",
37+
event: "audio_fx_runtime_generated",
38+
},
39+
"position-edits": {
40+
entryRelPath: "stubs/position-edits-render-entry.ts",
41+
generatedFileName: "position-edits-render-inline.ts",
42+
constName: "POSITION_EDITS_RENDER_IIFE",
43+
getterName: "getPositionEditsRenderScript",
44+
entryLabel: "position-edits-render-entry.ts",
45+
docLabel: "position-edits render",
46+
event: "position_edits_render_generated",
47+
},
48+
};
49+
50+
const key = process.argv[2] ?? "";
51+
const target = TARGETS[key];
52+
if (!target) {
53+
throw new Error(`Usage: build-inline-artifact.ts <${Object.keys(TARGETS).join("|")}>`);
54+
}
55+
56+
const thisDir = dirname(fileURLToPath(import.meta.url));
57+
const repoRoot = resolve(thisDir, "..");
58+
const entry = resolve(repoRoot, target.entryRelPath);
59+
const generatedDir = resolve(repoRoot, "src/generated");
60+
const outPath = resolve(generatedDir, target.generatedFileName);
61+
62+
const result = buildSync({
63+
entryPoints: [entry],
64+
bundle: true,
65+
write: false,
66+
platform: "browser",
67+
format: "iife",
68+
target: ["es2020"],
69+
minify: true,
70+
legalComments: "none",
71+
});
72+
const iife = result.outputFiles[0]?.text ?? "";
73+
if (!iife) throw new Error(`esbuild produced no output for ${target.entryLabel}`);
74+
75+
mkdirSync(generatedDir, { recursive: true });
76+
writeFileSync(
77+
outPath,
78+
[
79+
"// AUTO-GENERATED by scripts/build-inline-artifact.ts - do not edit",
80+
`const ${target.constName}: string = ${JSON.stringify(iife)};`,
81+
"",
82+
`/** Returns the pre-built ${target.docLabel} IIFE as a string constant. */`,
83+
`export function ${target.getterName}(): string {`,
84+
` return ${target.constName};`,
85+
"}",
86+
"",
87+
].join("\n"),
88+
"utf8",
89+
);
90+
91+
try {
92+
execFileSync("bun", ["x", "oxfmt", outPath], { stdio: "ignore" });
93+
} catch {
94+
// Formatting is best effort when the generator runs in a minimal environment.
95+
}
96+
97+
console.log(JSON.stringify({ event: target.event, outPath, bytes: iife.length }));

packages/core/scripts/build-position-edits-render.ts

Lines changed: 0 additions & 52 deletions
This file was deleted.

packages/core/src/generated/position-edits-render-inline.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// AUTO-GENERATED by scripts/build-position-edits-render.ts - do not edit
1+
// AUTO-GENERATED by scripts/build-inline-artifact.ts - do not edit
22
const POSITION_EDITS_RENDER_IIFE: string =
33
'"use strict";(()=>{function A(){return globalThis}function P(e,t){if(typeof window>"u")return;let n=A(),r=n.__hf?.onSwallowed;if(r)try{r({label:e,error:t})}catch(i){}(n.__hfDebug||n.__HYPERFRAMES_DEBUG)&&console.debug(`[hyperframes] ${e} swallowed:`,t)}var T=null;function R(e,t){if(T)try{T({source:"hf-preview",type:"analytics",event:e,properties:t??{}})}catch(n){P("runtime.analytics.site1",n)}}var w="data-hf-edit-base-x",k="data-hf-edit-base-y",y="data-hf-edit-original-translate",S=e=>{let t=parseFloat(e??"");return Number.isFinite(t)?t:0},V=e=>{let t=[],n=0,r="";for(let i of e.trim())i==="("&&(n+=1),i===")"&&(n=Math.max(0,n-1)),/\\s/.test(i)&&n===0?(r&&t.push(r),r=""):r+=i;return r&&t.push(r),t},$=/^-?(?:\\d+(?:\\.\\d+)?|\\.\\d+)px$/,E=(e,t)=>$.test(e)&&$.test(t)?`${parseFloat(e)+parseFloat(t)}px`:`calc(${e} + ${t})`,I=(e,t,n)=>{if(!e||e==="none")return`${t} ${n}`;let[r,i,u]=V(e);if(r===void 0)return`${t} ${n}`;if(i===void 0)return`${E(r,t)} ${n}`;let d=u===void 0?"":` ${u}`;return`${E(r,t)} ${E(i,n)}${d}`},O=e=>{try{e.ownerDocument.defaultView?.gsap?.getProperty?.(e,"x")}catch{}},G=e=>{let t=e.style.getPropertyValue("translate").trim();if(t)return t==="none"?"":t;try{let n=e.ownerDocument.defaultView,r=n?n.getComputedStyle(e).getPropertyValue("translate").trim():"";return r==="none"?"":r}catch{return""}},h=new WeakMap;function H(e,t){let n=h.get(e);if(!t?.force&&n!==void 0&&e.style.getPropertyValue("translate")!==n){R("position_edit_fold_skipped",{hfId:e.getAttribute("data-hf-id")});return}let r=S(e.getAttribute("data-x"))-S(e.getAttribute(w)),i=S(e.getAttribute("data-y"))-S(e.getAttribute(k));e.hasAttribute(y)||e.setAttribute(y,G(e)),n===void 0&&O(e);let u=e.getAttribute(y)??"",d=I(u,`${r}px`,`${i}px`);e.style.setProperty("translate",d),h.set(e,e.style.getPropertyValue("translate"))}function v(e,t){let n=e.defaultView?.HTMLElement,r=e.defaultView?.SVGElement,i=a=>n||r?n!==void 0&&a instanceof n||r!==void 0&&a instanceof r:typeof a.style?.setProperty=="function",u=e.querySelectorAll(`[${y}]:not([${w}]):not([${k}])`);for(let a=0;a<u.length;a++){let l=u[a];if(l===void 0||!i(l))continue;let b=l.getAttribute(y)??"";b===""?l.style.removeProperty("translate"):l.style.setProperty("translate",b),l.removeAttribute(y),h.delete(l)}let d=e.querySelectorAll(`[${w}], [${k}]`),m=0;for(let a=0;a<d.length;a++){let l=d[a];l===void 0||!i(l)||(H(l,t),m+=1)}return m}var x="__hfPositionEditsSeekReapplyWrapped",D=new WeakSet,F=new WeakMap,W=new WeakMap;function L(e){let t=e,n=()=>{try{v(t.document)}catch{}},r=o=>typeof o=="function"&&(D.has(o)||!!o[x]),i=o=>{D.add(o);try{Object.defineProperty(o,x,{value:!0})}catch{}},u=o=>{if(typeof o!="function"||r(o))return o;let s=function(...c){let f=o.apply(this,c);return n(),f};return i(s),s},d=(o,s)=>{let c=F.get(o);if(c?.has(s))return!0;let f=Object.getOwnPropertyDescriptor(o,s);if(f?.configurable===!1){let p=o[s];return typeof p=="function"&&(o[s]=u(p),n()),!1}let g=o[s],_=f?.set;return Object.defineProperty(o,s,{configurable:!0,enumerable:f?.enumerable??!0,get:()=>g,set:p=>{g=u(p),_?.call(o,p)}}),g=u(g),c??(c=new Set),c.add(s),F.set(o,c),n(),!0},m=(o,s)=>{let c=W.get(t),f=Object.getOwnPropertyDescriptor(t,o);if(!c?.has(o)){if(f?.configurable===!1){let p=t[o];return p?d(p,s):!1}let _=t[o];Object.defineProperty(t,o,{configurable:!0,enumerable:f?.enumerable??!0,get:()=>_,set:p=>{_=p,_&&d(_,s)}}),c??(c=new Set),c.add(o),W.set(t,c)}let g=t[o];return g?d(g,s):!1},a=()=>{let o=m("__hf","seek"),s=m("__player","renderSeek");return o&&s};if(a())return;let l=120,b=t.setInterval(()=>{if(a()){t.clearInterval(b);return}l-=1,l<=0&&t.clearInterval(b)},50)}function M(){document.querySelector(`[${w}], [${k}]`)&&(v(document),L(window))}document.readyState==="loading"?document.addEventListener("DOMContentLoaded",M,{once:!0}):M();})();\n';
44

packages/studio/src/components/editor/propertyPanelFxSection.test.tsx

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,11 @@ const click = (el: Element | null | undefined) => {
5959
const byText = (host: HTMLElement, sel: string, text: string) =>
6060
Array.from(host.querySelectorAll(sel)).find((e) => e.textContent?.trim() === text);
6161

62+
const openAddMenuItems = (host: HTMLElement) => {
63+
click(host.querySelector(".hf-fx-add"));
64+
return Array.from(host.querySelectorAll(".hf-fx-add-item")).map((e) => e.textContent?.trim());
65+
};
66+
6267
/**
6368
* React tracks an input's value on the DOM node, so assigning `.value` and
6469
* dispatching looks like a no-op change and the handler never fires. Going
@@ -87,10 +92,7 @@ describe("FxSection chain", () => {
8792
// The add menu is generated, so a new effect upstream appears here with no
8893
// change to the panel.
8994
const { host } = mount();
90-
click(host.querySelector(".hf-fx-add"));
91-
const items = Array.from(host.querySelectorAll(".hf-fx-add-item")).map((e) =>
92-
e.textContent?.trim(),
93-
);
95+
const items = openAddMenuItems(host);
9496
expect(items).toHaveLength(HF_AUDIO_FX.length);
9597
for (const def of HF_AUDIO_FX) expect(items).toContain(def.label);
9698
});
@@ -199,10 +201,7 @@ describe("FxSection carve", () => {
199201
it("is off by default and is not an entry in the chain", () => {
200202
const { host } = mount();
201203
expect(host.querySelector(".hf-fx-carve")).toBeTruthy();
202-
click(host.querySelector(".hf-fx-add"));
203-
const items = Array.from(host.querySelectorAll(".hf-fx-add-item")).map((e) =>
204-
e.textContent?.trim(),
205-
);
204+
const items = openAddMenuItems(host);
206205
expect(items).not.toContain("Voiceover carve");
207206
});
208207

0 commit comments

Comments
 (0)