mirror of
https://github.com/heygen-com/hyperframes.git
synced 2026-09-11 06:30:03 +00:00
style: apply oxfmt baseline formatting across all source files (#25)
## Summary - Run `oxfmt .` across the entire codebase to establish formatted baseline - 299 files changed — mechanical formatting only, no logic changes - Double quotes, semicolons, 2-space indent, trailing commas, 100 print width Part 3/4 of [VA-851](https://linear.app/heygen/issue/VA-851/pre-migration-configure-eslint-prettier-and-conventional-commits) ## Test plan - [x] `pnpm format:check` — all 426 files pass - [x] `pnpm -r typecheck` — all packages pass - [x] `pnpm build` — all packages build - [x] All 348 tests pass
This commit is contained in:
@@ -218,7 +218,10 @@ describe("gsapAnimationsToKeyframes", () => {
|
||||
targetSelector: "#el1",
|
||||
method: "to",
|
||||
position: 0,
|
||||
properties: { opacity: 1, x: 50, someUnsupportedProp: "value" } as Record<string, number | string>,
|
||||
properties: { opacity: 1, x: 50, someUnsupportedProp: "value" } as Record<
|
||||
string,
|
||||
number | string
|
||||
>,
|
||||
duration: 1,
|
||||
},
|
||||
];
|
||||
@@ -229,7 +232,9 @@ describe("gsapAnimationsToKeyframes", () => {
|
||||
expect(keyframes[0].properties.opacity).toBe(1);
|
||||
expect(keyframes[0].properties.x).toBe(50);
|
||||
// String values are skipped (typeof value !== "number" check)
|
||||
expect((keyframes[0].properties as Record<string, unknown>).someUnsupportedProp).toBeUndefined();
|
||||
expect(
|
||||
(keyframes[0].properties as Record<string, unknown>).someUnsupportedProp,
|
||||
).toBeUndefined();
|
||||
});
|
||||
|
||||
it("skips base set keyframes at time 0 when skipBaseSet is true", () => {
|
||||
@@ -337,9 +342,7 @@ describe("keyframesToGsapAnimations", () => {
|
||||
});
|
||||
|
||||
it("applies base x/y/scale offsets", () => {
|
||||
const keyframes: Keyframe[] = [
|
||||
{ id: "kf-1", time: 0, properties: { x: 10, y: 20, scale: 2 } },
|
||||
];
|
||||
const keyframes: Keyframe[] = [{ id: "kf-1", time: 0, properties: { x: 10, y: 20, scale: 2 } }];
|
||||
|
||||
const animations = keyframesToGsapAnimations("el1", keyframes, 0, {
|
||||
x: 50,
|
||||
@@ -491,8 +494,22 @@ describe("getAnimationsForElement", () => {
|
||||
it("filters animations by element id", () => {
|
||||
const animations: GsapAnimation[] = [
|
||||
{ id: "a1", targetSelector: "#el1", method: "set", position: 0, properties: { opacity: 0 } },
|
||||
{ id: "a2", targetSelector: "#el2", method: "to", position: 0, properties: { opacity: 1 }, duration: 1 },
|
||||
{ id: "a3", targetSelector: "#el1", method: "to", position: 1, properties: { opacity: 1 }, duration: 0.5 },
|
||||
{
|
||||
id: "a2",
|
||||
targetSelector: "#el2",
|
||||
method: "to",
|
||||
position: 0,
|
||||
properties: { opacity: 1 },
|
||||
duration: 1,
|
||||
},
|
||||
{
|
||||
id: "a3",
|
||||
targetSelector: "#el1",
|
||||
method: "to",
|
||||
position: 1,
|
||||
properties: { opacity: 1 },
|
||||
duration: 0.5,
|
||||
},
|
||||
];
|
||||
|
||||
const result = getAnimationsForElement(animations, "el1");
|
||||
|
||||
@@ -78,7 +78,10 @@ function parseObjectLiteral(str: string): Record<string, number | string> {
|
||||
let value: string | number = match[2] ?? "";
|
||||
|
||||
if (typeof value === "string") {
|
||||
if ((value.startsWith('"') && value.endsWith('"')) || (value.startsWith("'") && value.endsWith("'"))) {
|
||||
if (
|
||||
(value.startsWith('"') && value.endsWith('"')) ||
|
||||
(value.startsWith("'") && value.endsWith("'"))
|
||||
) {
|
||||
value = value.slice(1, -1);
|
||||
} else if (!isNaN(Number(value))) {
|
||||
value = Number(value);
|
||||
@@ -108,14 +111,21 @@ export function parseGsapScript(script: string): ParsedGsap {
|
||||
let idCounter = 0;
|
||||
|
||||
const timelineMatch = script.match(/(?:const|let|var)\s+(\w+)\s*=\s*gsap\.timeline/);
|
||||
const timelineVar = timelineMatch ? timelineMatch[1] ?? "tl" : "tl";
|
||||
const timelineVar = timelineMatch ? (timelineMatch[1] ?? "tl") : "tl";
|
||||
|
||||
const preambleMatch = script.match(
|
||||
new RegExp(`^[\\s\\S]*?(?:const|let|var)\\s+${timelineVar}\\s*=\\s*gsap\\.timeline\\s*\\([^)]*\\)\\s*;?`),
|
||||
new RegExp(
|
||||
`^[\\s\\S]*?(?:const|let|var)\\s+${timelineVar}\\s*=\\s*gsap\\.timeline\\s*\\([^)]*\\)\\s*;?`,
|
||||
),
|
||||
);
|
||||
const preamble = preambleMatch ? preambleMatch[0] : `const ${timelineVar} = gsap.timeline({ paused: true });`;
|
||||
const preamble = preambleMatch
|
||||
? preambleMatch[0]
|
||||
: `const ${timelineVar} = gsap.timeline({ paused: true });`;
|
||||
|
||||
const methodPattern = new RegExp(`${timelineVar}\\.(set|to|from|fromTo)\\s*\\(([^)]+(?:\\{[^}]*\\}[^)]*)+)\\)`, "g");
|
||||
const methodPattern = new RegExp(
|
||||
`${timelineVar}\\.(set|to|from|fromTo)\\s*\\(([^)]+(?:\\{[^}]*\\}[^)]*)+)\\)`,
|
||||
"g",
|
||||
);
|
||||
|
||||
let match;
|
||||
while ((match = methodPattern.exec(script)) !== null) {
|
||||
@@ -286,7 +296,11 @@ function serializeObject(obj: Record<string, number | string>): string {
|
||||
return `{ ${entries.join(", ")} }`;
|
||||
}
|
||||
|
||||
export function updateAnimationInScript(script: string, animationId: string, updates: Partial<GsapAnimation>): string {
|
||||
export function updateAnimationInScript(
|
||||
script: string,
|
||||
animationId: string,
|
||||
updates: Partial<GsapAnimation>,
|
||||
): string {
|
||||
const parsed = parseGsapScript(script);
|
||||
|
||||
const updated = parsed.animations.map((anim) => {
|
||||
@@ -322,7 +336,10 @@ export function removeAnimationFromScript(script: string, animationId: string):
|
||||
return serializeGsapAnimations(filtered, parsed.timelineVar);
|
||||
}
|
||||
|
||||
export function getAnimationsForElement(animations: GsapAnimation[], elementId: string): GsapAnimation[] {
|
||||
export function getAnimationsForElement(
|
||||
animations: GsapAnimation[],
|
||||
elementId: string,
|
||||
): GsapAnimation[] {
|
||||
const selector = `#${elementId}`;
|
||||
return animations.filter((a) => a.targetSelector === selector);
|
||||
}
|
||||
@@ -478,7 +495,8 @@ export function gsapAnimationsToKeyframes(
|
||||
} else if (key === "y") {
|
||||
(properties as Record<string, number>).y = value - baseY;
|
||||
} else if (key === "scale") {
|
||||
(properties as Record<string, number>).scale = baseScale !== 0 ? value / baseScale : value;
|
||||
(properties as Record<string, number>).scale =
|
||||
baseScale !== 0 ? value / baseScale : value;
|
||||
} else {
|
||||
(properties as Record<string, number>)[key] = value;
|
||||
}
|
||||
|
||||
@@ -2,7 +2,14 @@
|
||||
* @vitest-environment jsdom
|
||||
*/
|
||||
import { describe, it, expect } from "vitest";
|
||||
import { parseHtml, updateElementInHtml, addElementToHtml, removeElementFromHtml, validateCompositionHtml, extractCompositionMetadata } from "./htmlParser.js";
|
||||
import {
|
||||
parseHtml,
|
||||
updateElementInHtml,
|
||||
addElementToHtml,
|
||||
removeElementFromHtml,
|
||||
validateCompositionHtml,
|
||||
extractCompositionMetadata,
|
||||
} from "./htmlParser.js";
|
||||
|
||||
describe("parseHtml", () => {
|
||||
it("extracts elements with data-start and data-end", () => {
|
||||
@@ -457,7 +464,9 @@ describe("validateCompositionHtml", () => {
|
||||
|
||||
const result = validateCompositionHtml(html);
|
||||
expect(result.valid).toBe(false);
|
||||
expect(result.errors).toContain("Missing data-composition-duration attribute on <html> element");
|
||||
expect(result.errors).toContain(
|
||||
"Missing data-composition-duration attribute on <html> element",
|
||||
);
|
||||
});
|
||||
|
||||
it("reports error for missing #stage", () => {
|
||||
|
||||
@@ -40,7 +40,14 @@ function getElementType(el: Element): TimelineElementType | null {
|
||||
if (dataType === "composition") return "composition";
|
||||
if (dataType === "text") return "text";
|
||||
// Fall back to tag-based detection for backwards compatibility
|
||||
if (tag === "div" || tag === "p" || tag === "h1" || tag === "h2" || tag === "h3" || tag === "span") {
|
||||
if (
|
||||
tag === "div" ||
|
||||
tag === "p" ||
|
||||
tag === "h1" ||
|
||||
tag === "h2" ||
|
||||
tag === "h3" ||
|
||||
tag === "span"
|
||||
) {
|
||||
return "text";
|
||||
}
|
||||
return null;
|
||||
@@ -89,13 +96,17 @@ function parseResolutionFromCss(doc: Document, cssText: string | null): CanvasRe
|
||||
}
|
||||
|
||||
if (cssText) {
|
||||
const stageMatch = cssText.match(/#stage\s*\{[^}]*width:\s*(\d+)px[^}]*height:\s*(\d+)px[^}]*\}/);
|
||||
const stageMatch = cssText.match(
|
||||
/#stage\s*\{[^}]*width:\s*(\d+)px[^}]*height:\s*(\d+)px[^}]*\}/,
|
||||
);
|
||||
if (stageMatch) {
|
||||
const w = parseInt(stageMatch[1] ?? "", 10);
|
||||
const h = parseInt(stageMatch[2] ?? "", 10);
|
||||
return w > h ? "landscape" : "portrait";
|
||||
}
|
||||
const stageMatchReverse = cssText.match(/#stage\s*\{[^}]*height:\s*(\d+)px[^}]*width:\s*(\d+)px[^}]*\}/);
|
||||
const stageMatchReverse = cssText.match(
|
||||
/#stage\s*\{[^}]*height:\s*(\d+)px[^}]*width:\s*(\d+)px[^}]*\}/,
|
||||
);
|
||||
if (stageMatchReverse) {
|
||||
const h = parseInt(stageMatchReverse[1] ?? "", 10);
|
||||
const w = parseInt(stageMatchReverse[2] ?? "", 10);
|
||||
@@ -205,16 +216,22 @@ export function parseHtml(html: string): ParsedHtml {
|
||||
const textOutline = textOutlineAttr === "true" ? true : undefined;
|
||||
const textOutlineColor = el.getAttribute("data-text-outline-color") || undefined;
|
||||
const textOutlineWidthAttr = el.getAttribute("data-text-outline-width");
|
||||
const textOutlineWidth = textOutlineWidthAttr ? parseInt(textOutlineWidthAttr, 10) : undefined;
|
||||
const textOutlineWidth = textOutlineWidthAttr
|
||||
? parseInt(textOutlineWidthAttr, 10)
|
||||
: undefined;
|
||||
|
||||
// Parse highlight properties
|
||||
const textHighlightAttr = el.getAttribute("data-text-highlight");
|
||||
const textHighlight = textHighlightAttr === "true" ? true : undefined;
|
||||
const textHighlightColor = el.getAttribute("data-text-highlight-color") || undefined;
|
||||
const textHighlightPaddingAttr = el.getAttribute("data-text-highlight-padding");
|
||||
const textHighlightPadding = textHighlightPaddingAttr ? parseInt(textHighlightPaddingAttr, 10) : undefined;
|
||||
const textHighlightPadding = textHighlightPaddingAttr
|
||||
? parseInt(textHighlightPaddingAttr, 10)
|
||||
: undefined;
|
||||
const textHighlightRadiusAttr = el.getAttribute("data-text-highlight-radius");
|
||||
const textHighlightRadius = textHighlightRadiusAttr ? parseInt(textHighlightRadiusAttr, 10) : undefined;
|
||||
const textHighlightRadius = textHighlightRadiusAttr
|
||||
? parseInt(textHighlightRadiusAttr, 10)
|
||||
: undefined;
|
||||
|
||||
const textElement: TimelineTextElement = {
|
||||
id,
|
||||
@@ -375,7 +392,9 @@ export function parseHtml(html: string): ParsedHtml {
|
||||
.filter(Boolean)
|
||||
.join("\n\n") || null;
|
||||
|
||||
const customStyleTags = Array.from(styleTags).filter((s) => s.getAttribute("data-hf-custom") === "true");
|
||||
const customStyleTags = Array.from(styleTags).filter(
|
||||
(s) => s.getAttribute("data-hf-custom") === "true",
|
||||
);
|
||||
const customStylesFromTags =
|
||||
customStyleTags
|
||||
.map((s) => s.textContent?.trim())
|
||||
@@ -463,7 +482,9 @@ function parseStageZoomKeyframes(doc: Document): StageZoomKeyframe[] {
|
||||
* Extract x/y positions and scale from GSAP set() calls at position 0
|
||||
* Returns a map of elementId -> { x, y, scale }
|
||||
*/
|
||||
function extractPositionsFromGsap(script: string): Map<string, { x?: number; y?: number; scale?: number }> {
|
||||
function extractPositionsFromGsap(
|
||||
script: string,
|
||||
): Map<string, { x?: number; y?: number; scale?: number }> {
|
||||
const positionMap = new Map<string, { x?: number; y?: number; scale?: number }>();
|
||||
|
||||
try {
|
||||
@@ -482,7 +503,11 @@ function extractPositionsFromGsap(script: string): Map<string, { x?: number; y?:
|
||||
const scale = typeof anim.properties.scale === "number" ? anim.properties.scale : undefined;
|
||||
|
||||
// Only add to map if x, y, or scale is defined and non-default
|
||||
if ((x !== undefined && x !== 0) || (y !== undefined && y !== 0) || (scale !== undefined && scale !== 1)) {
|
||||
if (
|
||||
(x !== undefined && x !== 0) ||
|
||||
(y !== undefined && y !== 0) ||
|
||||
(scale !== undefined && scale !== 1)
|
||||
) {
|
||||
const existing = positionMap.get(elementId) || {};
|
||||
positionMap.set(elementId, {
|
||||
x: x !== undefined ? x : existing.x,
|
||||
@@ -499,7 +524,12 @@ function extractPositionsFromGsap(script: string): Map<string, { x?: number; y?:
|
||||
return positionMap;
|
||||
}
|
||||
|
||||
function normalizeKeyframes(keyframes: Keyframe[], baseX: number, baseY: number, baseScale: number): Keyframe[] {
|
||||
function normalizeKeyframes(
|
||||
keyframes: Keyframe[],
|
||||
baseX: number,
|
||||
baseY: number,
|
||||
baseScale: number,
|
||||
): Keyframe[] {
|
||||
const timeEpsilon = 0.001;
|
||||
const valueEpsilon = 0.00001;
|
||||
|
||||
@@ -543,7 +573,11 @@ function normalizeKeyframes(keyframes: Keyframe[], baseX: number, baseY: number,
|
||||
});
|
||||
}
|
||||
|
||||
export function updateElementInHtml(html: string, elementId: string, updates: Partial<TimelineElement>): string {
|
||||
export function updateElementInHtml(
|
||||
html: string,
|
||||
elementId: string,
|
||||
updates: Partial<TimelineElement>,
|
||||
): string {
|
||||
const parser = new DOMParser();
|
||||
const doc = parser.parseFromString(html, "text/html");
|
||||
|
||||
@@ -732,7 +766,8 @@ export function extractCompositionMetadata(html: string): CompositionMetadata {
|
||||
|
||||
return {
|
||||
compositionId,
|
||||
compositionDuration: compositionDuration && isFinite(compositionDuration) ? compositionDuration : null,
|
||||
compositionDuration:
|
||||
compositionDuration && isFinite(compositionDuration) ? compositionDuration : null,
|
||||
variables,
|
||||
};
|
||||
}
|
||||
@@ -833,7 +868,11 @@ function extractGsapScript(doc: Document): string | null {
|
||||
const scripts = doc.querySelectorAll("script");
|
||||
for (const script of scripts) {
|
||||
const content = script.textContent || "";
|
||||
if (content.includes("gsap.timeline") || content.includes(".set(") || content.includes(".to(")) {
|
||||
if (
|
||||
content.includes("gsap.timeline") ||
|
||||
content.includes(".set(") ||
|
||||
content.includes(".to(")
|
||||
) {
|
||||
return content;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user