@hyperframes/parsers 0.7.22 → 0.7.23
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts
CHANGED
|
@@ -6,8 +6,21 @@ export { PROPERTY_GROUPS, PropertyGroupName, SUPPORTED_EASES, SUPPORTED_PROPS, c
|
|
|
6
6
|
export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
|
|
7
7
|
export { parseGsapScriptAcorn as parseGsapScript } from './gsapParserAcorn.js';
|
|
8
8
|
export { EXCLUDED_TAGS, ensureHfIds, mintHfId } from './hfIds.js';
|
|
9
|
+
export { ParsableDocumentLike, SubCompositionValidity, SubCompositionValidityReason, checkSubCompositionUsability } from './subCompositionValidity.js';
|
|
9
10
|
export { CANONICAL_FONT_DISPLAY_NAMES, FONT_ALIAS_KEYS, FONT_ALIAS_MAP, decodeUrlPathVariants, resolveAliasDisplayName } from './composition.js';
|
|
10
11
|
|
|
12
|
+
/**
|
|
13
|
+
* Thrown by htmlParser functions when the input HTML is empty or does not
|
|
14
|
+
* parse to a document with a `documentElement` — the condition that,
|
|
15
|
+
* unguarded, previously surfaced as a raw
|
|
16
|
+
* `Cannot read properties of null (reading '...')` /
|
|
17
|
+
* `Cannot destructure property 'firstElementChild' of 'documentElement' as
|
|
18
|
+
* it is null` crash deep inside the DOM implementation instead of a clear,
|
|
19
|
+
* catchable error naming which function received bad input.
|
|
20
|
+
*/
|
|
21
|
+
declare class CompositionHtmlParseError extends Error {
|
|
22
|
+
constructor(message: string);
|
|
23
|
+
}
|
|
11
24
|
interface ParsedHtml {
|
|
12
25
|
elements: TimelineElement[];
|
|
13
26
|
gsapScript: string | null;
|
|
@@ -42,4 +55,4 @@ declare function unrollComputedTimeline(script: string): string;
|
|
|
42
55
|
|
|
43
56
|
declare function queryByAttr(root: ParentNode, attr: string, value: string, tag?: string): Element | null;
|
|
44
57
|
|
|
45
|
-
export { CanvasResolution, type CompositionMetadata, CompositionVariable, Keyframe, type ParsedHtml, StageZoomKeyframe, TimelineElement, ValidationResult, addElementToHtml, extractCompositionMetadata, parseHtml, queryByAttr, removeElementFromHtml, unrollComputedTimeline, updateElementInHtml, validateCompositionHtml };
|
|
58
|
+
export { CanvasResolution, CompositionHtmlParseError, type CompositionMetadata, CompositionVariable, Keyframe, type ParsedHtml, StageZoomKeyframe, TimelineElement, ValidationResult, addElementToHtml, extractCompositionMetadata, parseHtml, queryByAttr, removeElementFromHtml, unrollComputedTimeline, updateElementInHtml, validateCompositionHtml };
|
package/dist/index.js
CHANGED
|
@@ -1787,6 +1787,12 @@ function removeAnimationFromScript(script, animationId) {
|
|
|
1787
1787
|
|
|
1788
1788
|
// src/htmlParser.ts
|
|
1789
1789
|
var MEDIA_TYPES = /* @__PURE__ */ new Set(["video", "image", "audio"]);
|
|
1790
|
+
var CompositionHtmlParseError = class extends Error {
|
|
1791
|
+
constructor(message) {
|
|
1792
|
+
super(message);
|
|
1793
|
+
this.name = "CompositionHtmlParseError";
|
|
1794
|
+
}
|
|
1795
|
+
};
|
|
1790
1796
|
function getElementType(el) {
|
|
1791
1797
|
const tag = el.tagName.toLowerCase();
|
|
1792
1798
|
if (tag === "video") return "video";
|
|
@@ -1856,6 +1862,7 @@ function parseResolutionFromCss(doc, cssText) {
|
|
|
1856
1862
|
}
|
|
1857
1863
|
function parseResolutionFromHtml(doc) {
|
|
1858
1864
|
const htmlEl = doc.documentElement;
|
|
1865
|
+
if (!htmlEl) return null;
|
|
1859
1866
|
const resolutionAttr = htmlEl.getAttribute("data-resolution");
|
|
1860
1867
|
if (resolutionAttr === "landscape" || resolutionAttr === "portrait" || resolutionAttr === "landscape-4k" || resolutionAttr === "portrait-4k" || resolutionAttr === "square" || resolutionAttr === "square-4k") {
|
|
1861
1868
|
return resolutionAttr;
|
|
@@ -1891,6 +1898,9 @@ function parseHtml(html) {
|
|
|
1891
1898
|
const keyframes = {};
|
|
1892
1899
|
let idCounter = 0;
|
|
1893
1900
|
const htmlEl = doc.documentElement;
|
|
1901
|
+
if (!htmlEl) {
|
|
1902
|
+
throw new CompositionHtmlParseError("parseHtml: input HTML is empty or could not be parsed");
|
|
1903
|
+
}
|
|
1894
1904
|
const customStylesAttr = htmlEl.getAttribute("data-custom-styles");
|
|
1895
1905
|
let customStyles = null;
|
|
1896
1906
|
if (customStylesAttr) {
|
|
@@ -2201,12 +2211,25 @@ function updateElementInHtml(html, elementId, updates) {
|
|
|
2201
2211
|
el.removeAttribute("data-has-audio");
|
|
2202
2212
|
}
|
|
2203
2213
|
}
|
|
2214
|
+
if (!doc.documentElement) {
|
|
2215
|
+
throw new CompositionHtmlParseError(
|
|
2216
|
+
"updateElementInHtml: input HTML is empty or could not be parsed"
|
|
2217
|
+
);
|
|
2218
|
+
}
|
|
2204
2219
|
return "<!DOCTYPE html>\n" + doc.documentElement.outerHTML;
|
|
2205
2220
|
}
|
|
2206
2221
|
function addElementToHtml(html, element) {
|
|
2207
2222
|
const parser = new DOMParser();
|
|
2208
2223
|
const doc = parser.parseFromString(html, "text/html");
|
|
2224
|
+
if (!doc.documentElement) {
|
|
2225
|
+
throw new CompositionHtmlParseError(
|
|
2226
|
+
"addElementToHtml: input HTML is empty or could not be parsed"
|
|
2227
|
+
);
|
|
2228
|
+
}
|
|
2209
2229
|
const container = doc.querySelector("#stage-zoom-container") || doc.querySelector(".container") || doc.querySelector("#stage") || doc.body;
|
|
2230
|
+
if (!container) {
|
|
2231
|
+
throw new CompositionHtmlParseError("addElementToHtml: input HTML has no <body>");
|
|
2232
|
+
}
|
|
2210
2233
|
const id = element.id || `element-${Date.now()}`;
|
|
2211
2234
|
let newEl;
|
|
2212
2235
|
function applyMediaAttrs(el, mediaEl) {
|
|
@@ -2295,6 +2318,11 @@ function cascadeRemoveGsapById(doc, elementId) {
|
|
|
2295
2318
|
function removeElementFromHtml(html, elementId) {
|
|
2296
2319
|
const parser = new DOMParser();
|
|
2297
2320
|
const doc = parser.parseFromString(html, "text/html");
|
|
2321
|
+
if (!doc.documentElement) {
|
|
2322
|
+
throw new CompositionHtmlParseError(
|
|
2323
|
+
"removeElementFromHtml: input HTML is empty or could not be parsed"
|
|
2324
|
+
);
|
|
2325
|
+
}
|
|
2298
2326
|
doc.getElementById(elementId)?.remove();
|
|
2299
2327
|
cascadeRemoveGsapById(doc, elementId);
|
|
2300
2328
|
return "<!DOCTYPE html>\n" + doc.documentElement.outerHTML;
|
|
@@ -2303,6 +2331,11 @@ function extractCompositionMetadata(html) {
|
|
|
2303
2331
|
const parser = new DOMParser();
|
|
2304
2332
|
const doc = parser.parseFromString(html, "text/html");
|
|
2305
2333
|
const htmlEl = doc.documentElement;
|
|
2334
|
+
if (!htmlEl) {
|
|
2335
|
+
throw new CompositionHtmlParseError(
|
|
2336
|
+
"extractCompositionMetadata: input HTML is empty or could not be parsed"
|
|
2337
|
+
);
|
|
2338
|
+
}
|
|
2306
2339
|
const compositionId = htmlEl.getAttribute("data-composition-id");
|
|
2307
2340
|
const durationStr = htmlEl.getAttribute("data-composition-duration");
|
|
2308
2341
|
const compositionDuration = durationStr ? parseFloat(durationStr) : null;
|
|
@@ -2357,6 +2390,13 @@ function validateCompositionHtml(html) {
|
|
|
2357
2390
|
const parser = new DOMParser();
|
|
2358
2391
|
const doc = parser.parseFromString(html, "text/html");
|
|
2359
2392
|
const htmlEl = doc.documentElement;
|
|
2393
|
+
if (!htmlEl) {
|
|
2394
|
+
return {
|
|
2395
|
+
valid: false,
|
|
2396
|
+
errors: ["Composition HTML is empty or could not be parsed"],
|
|
2397
|
+
warnings: []
|
|
2398
|
+
};
|
|
2399
|
+
}
|
|
2360
2400
|
const compositionId = htmlEl.getAttribute("data-composition-id");
|
|
2361
2401
|
if (!compositionId) {
|
|
2362
2402
|
errors.push("Missing data-composition-id attribute on <html> element");
|
|
@@ -2407,6 +2447,50 @@ function extractGsapScript(doc) {
|
|
|
2407
2447
|
return null;
|
|
2408
2448
|
}
|
|
2409
2449
|
|
|
2450
|
+
// src/subCompositionValidity.ts
|
|
2451
|
+
function checkSubCompositionUsability(html, parseHtml2) {
|
|
2452
|
+
if (html == null || !html.trim()) {
|
|
2453
|
+
return {
|
|
2454
|
+
ok: false,
|
|
2455
|
+
reason: "empty",
|
|
2456
|
+
detail: "the file is empty (0 bytes or whitespace-only)"
|
|
2457
|
+
};
|
|
2458
|
+
}
|
|
2459
|
+
const compDoc = parseHtml2(html);
|
|
2460
|
+
if (!compDoc.documentElement) {
|
|
2461
|
+
return {
|
|
2462
|
+
ok: false,
|
|
2463
|
+
reason: "unparsable",
|
|
2464
|
+
detail: "the file's contents could not be parsed as HTML"
|
|
2465
|
+
};
|
|
2466
|
+
}
|
|
2467
|
+
const contentRoot = compDoc.querySelector("template");
|
|
2468
|
+
const contentHtml = contentRoot ? contentRoot.innerHTML || "" : compDoc.body?.innerHTML || "";
|
|
2469
|
+
if (!contentHtml.trim()) {
|
|
2470
|
+
return {
|
|
2471
|
+
ok: false,
|
|
2472
|
+
reason: "no-content",
|
|
2473
|
+
detail: "the file has no <template> or <body> content to render"
|
|
2474
|
+
};
|
|
2475
|
+
}
|
|
2476
|
+
const contentDoc = parseHtml2(contentHtml);
|
|
2477
|
+
if (!contentDoc.documentElement) {
|
|
2478
|
+
return {
|
|
2479
|
+
ok: false,
|
|
2480
|
+
reason: "unparsable",
|
|
2481
|
+
detail: "the file's <template>/<body> contents could not be parsed as HTML"
|
|
2482
|
+
};
|
|
2483
|
+
}
|
|
2484
|
+
if (!contentDoc.querySelector("[data-composition-id]")) {
|
|
2485
|
+
return {
|
|
2486
|
+
ok: false,
|
|
2487
|
+
reason: "no-composition-root",
|
|
2488
|
+
detail: "the file's <template>/<body> content has no element with a data-composition-id attribute"
|
|
2489
|
+
};
|
|
2490
|
+
}
|
|
2491
|
+
return { ok: true };
|
|
2492
|
+
}
|
|
2493
|
+
|
|
2410
2494
|
// src/gsapUnroll.ts
|
|
2411
2495
|
import * as acorn2 from "acorn";
|
|
2412
2496
|
import MagicString2 from "magic-string";
|
|
@@ -2622,6 +2706,7 @@ export {
|
|
|
2622
2706
|
CANONICAL_FONT_DISPLAY_NAMES,
|
|
2623
2707
|
CANVAS_DIMENSIONS,
|
|
2624
2708
|
COMPOSITION_VARIABLE_TYPES,
|
|
2709
|
+
CompositionHtmlParseError,
|
|
2625
2710
|
DEFAULT_DURATIONS,
|
|
2626
2711
|
EXCLUDED_TAGS,
|
|
2627
2712
|
FONT_ALIAS_KEYS,
|
|
@@ -2633,6 +2718,7 @@ export {
|
|
|
2633
2718
|
TIMELINE_COLORS,
|
|
2634
2719
|
VALID_CANVAS_RESOLUTIONS,
|
|
2635
2720
|
addElementToHtml,
|
|
2721
|
+
checkSubCompositionUsability,
|
|
2636
2722
|
classifyPropertyGroup,
|
|
2637
2723
|
classifyTweenPropertyGroup,
|
|
2638
2724
|
decodeUrlPathVariants,
|