Skip to content

Commit 2851fe3

Browse files
committed
refactor(core): extract remaining duplicate blocks
- Extract extractArcWaypoints in gsapParser (replaces 2 inline keyframe x/y extraction blocks in setArcPath/updateArcSegment) - Extract insertAfterAnchor in gsapParser (replaces 2 inline anchor-finding + insertAfter blocks in addAnimation functions) - Extract hoistCompositionScripts in htmlBundler (replaces 2 inline 30-line script hoisting blocks in bundleToSingleHtml)
1 parent 415ef8c commit 2851fe3

4 files changed

Lines changed: 274 additions & 236 deletions

File tree

packages/core/src/compiler/htmlBundler.ts

Lines changed: 92 additions & 80 deletions
Original file line numberDiff line numberDiff line change
@@ -593,6 +593,78 @@ export interface BundleOptions {
593593
* - Inlines sub-composition HTML fragments (data-composition-src)
594594
* - Inlines small textual assets as data URLs
595595
*/
596+
597+
function ensureExternalScriptTag(doc: Document, src: string): void {
598+
if (doc.querySelector(`script[src="${src}"]`)) return;
599+
const el = doc.createElement("script");
600+
el.setAttribute("src", src);
601+
doc.body.appendChild(el);
602+
}
603+
604+
function hoistExternalScript(
605+
src: string,
606+
projectDir: string,
607+
doc: Document,
608+
seenSrcs: Set<string>,
609+
chunks: string[],
610+
): void {
611+
if (seenSrcs.has(src)) return;
612+
seenSrcs.add(src);
613+
if (!isNonRelativeUrl(src) && !isAbsolute(src)) {
614+
const jsPath = resolveWithinProject(projectDir, src);
615+
const js = jsPath ? safeReadFile(jsPath) : null;
616+
if (js != null) {
617+
chunks.push(js);
618+
return;
619+
}
620+
}
621+
ensureExternalScriptTag(doc, src);
622+
}
623+
624+
function hoistCompositionScripts(
625+
container: { querySelectorAll: (sel: string) => NodeListOf<Element> },
626+
opts: {
627+
projectDir: string;
628+
document: Document;
629+
compId: string | null;
630+
runtimeScope: string | undefined;
631+
runtimeCompId: string | undefined;
632+
authoredRootId: string | undefined;
633+
seenCompScriptSrcs: Set<string>;
634+
compScriptChunks: string[];
635+
},
636+
): void {
637+
for (const scriptEl of [...container.querySelectorAll("script")]) {
638+
const externalSrc = (scriptEl.getAttribute("src") || "").trim();
639+
if (externalSrc) {
640+
hoistExternalScript(
641+
externalSrc,
642+
opts.projectDir,
643+
opts.document,
644+
opts.seenCompScriptSrcs,
645+
opts.compScriptChunks,
646+
);
647+
} else {
648+
opts.compScriptChunks.push(
649+
opts.compId
650+
? wrapScopedCompositionScript(
651+
scriptEl.textContent || "",
652+
opts.compId,
653+
"[HyperFrames] composition script error:",
654+
opts.runtimeScope,
655+
opts.runtimeCompId || opts.compId,
656+
opts.authoredRootId,
657+
)
658+
: wrapInlineScriptWithErrorBoundary(
659+
scriptEl.textContent || "",
660+
"[HyperFrames] composition script error:",
661+
),
662+
);
663+
}
664+
scriptEl.remove();
665+
}
666+
}
667+
596668
export async function bundleToSingleHtml(
597669
projectDir: string,
598670
options?: BundleOptions,
@@ -775,47 +847,16 @@ export async function bundleToSingleHtml(
775847
);
776848
styleEl.remove();
777849
}
778-
// Hoist scripts into the collected script chunks
779-
for (const scriptEl of [...innerRoot.querySelectorAll("script")]) {
780-
const externalSrc = (scriptEl.getAttribute("src") || "").trim();
781-
if (externalSrc) {
782-
if (!seenCompScriptSrcs.has(externalSrc)) {
783-
seenCompScriptSrcs.add(externalSrc);
784-
if (isRelativeUrl(externalSrc)) {
785-
const jsPath = resolveWithinProject(projectDir, externalSrc);
786-
const js = jsPath ? safeReadFile(jsPath) : null;
787-
if (js != null) {
788-
compScriptChunks.push(js);
789-
} else if (!document.querySelector(`script[src="${externalSrc}"]`)) {
790-
const extScript = document.createElement("script");
791-
extScript.setAttribute("src", externalSrc);
792-
document.body.appendChild(extScript);
793-
}
794-
} else if (!document.querySelector(`script[src="${externalSrc}"]`)) {
795-
const extScript = document.createElement("script");
796-
extScript.setAttribute("src", externalSrc);
797-
document.body.appendChild(extScript);
798-
}
799-
}
800-
} else {
801-
compScriptChunks.push(
802-
compId
803-
? wrapScopedCompositionScript(
804-
scriptEl.textContent || "",
805-
compId,
806-
"[HyperFrames] composition script error:",
807-
runtimeScope,
808-
runtimeCompId || compId,
809-
authoredRootId,
810-
)
811-
: wrapInlineScriptWithErrorBoundary(
812-
scriptEl.textContent || "",
813-
"[HyperFrames] composition script error:",
814-
),
815-
);
816-
}
817-
scriptEl.remove();
818-
}
850+
hoistCompositionScripts(innerRoot, {
851+
projectDir,
852+
document,
853+
compId,
854+
runtimeScope,
855+
runtimeCompId,
856+
authoredRootId: authoredRootId ?? undefined,
857+
seenCompScriptSrcs,
858+
compScriptChunks,
859+
});
819860

820861
// Copy dimension attributes from inner root to host if not already set
821862
const innerW = innerRoot.getAttribute("data-width");
@@ -831,45 +872,16 @@ export async function bundleToSingleHtml(
831872
compStyleChunks.push(compId ? scopeCssToComposition(css, compId, runtimeScope) : css);
832873
styleEl.remove();
833874
}
834-
for (const scriptEl of [...innerDoc.querySelectorAll("script")]) {
835-
const externalSrc = (scriptEl.getAttribute("src") || "").trim();
836-
if (externalSrc) {
837-
if (!seenCompScriptSrcs.has(externalSrc)) {
838-
seenCompScriptSrcs.add(externalSrc);
839-
if (isRelativeUrl(externalSrc)) {
840-
const jsPath = resolveWithinProject(projectDir, externalSrc);
841-
const js = jsPath ? safeReadFile(jsPath) : null;
842-
if (js != null) {
843-
compScriptChunks.push(js);
844-
} else if (!document.querySelector(`script[src="${externalSrc}"]`)) {
845-
const extScript = document.createElement("script");
846-
extScript.setAttribute("src", externalSrc);
847-
document.body.appendChild(extScript);
848-
}
849-
} else if (!document.querySelector(`script[src="${externalSrc}"]`)) {
850-
const extScript = document.createElement("script");
851-
extScript.setAttribute("src", externalSrc);
852-
document.body.appendChild(extScript);
853-
}
854-
}
855-
} else {
856-
compScriptChunks.push(
857-
compId
858-
? wrapScopedCompositionScript(
859-
scriptEl.textContent || "",
860-
compId,
861-
"[HyperFrames] composition script error:",
862-
runtimeScope,
863-
runtimeCompId || compId,
864-
)
865-
: wrapInlineScriptWithErrorBoundary(
866-
scriptEl.textContent || "",
867-
"[HyperFrames] composition script error:",
868-
),
869-
);
870-
}
871-
scriptEl.remove();
872-
}
875+
hoistCompositionScripts(innerDoc, {
876+
projectDir,
877+
document,
878+
compId,
879+
runtimeScope,
880+
runtimeCompId,
881+
authoredRootId: undefined,
882+
seenCompScriptSrcs,
883+
compScriptChunks,
884+
});
873885

874886
host.innerHTML = innerDoc.body.innerHTML || "";
875887
}

packages/core/src/lint/rules/composition.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -514,7 +514,7 @@ export const compositionRules: Array<(ctx: LintContext) => HyperframeLintFinding
514514
const e = entry as Record<string, unknown>;
515515
const missing: string[] = [];
516516
if (typeof e.id !== "string") missing.push("id");
517-
if (typeof e.type !== "string" || !knownTypes.has(e.type as string)) missing.push("type");
517+
if (typeof e.type !== "string" || !knownTypes.has(e.type)) missing.push("type");
518518
if (typeof e.label !== "string") missing.push("label");
519519
if (!("default" in e)) missing.push("default");
520520
if (missing.length > 0) {

0 commit comments

Comments
 (0)