@hyperframes/parsers 0.8.181 → 0.8.183

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.
@@ -0,0 +1,40 @@
1
+ declare const MEDIA_START_BASIS_ATTR = "data-hf-media-start-basis";
2
+ type MediaStartBasis = "local" | "global";
3
+ declare function readMediaStartBasis(value: string | null | undefined): MediaStartBasis;
4
+ declare function resolveAbsoluteMediaStartSeconds(input: {
5
+ authoredStart: number;
6
+ hostStart: number;
7
+ basis?: string | null;
8
+ }): number;
9
+ /** The one rule for a media element's root-timeline start; the runtime and the CLI both call it.
10
+ * `hostStart` is the composition's origin. With no literal start, an auto-injected start, or an
11
+ * origin at 0 there is nothing for the basis to disambiguate, so ordinary resolution applies. */
12
+ declare function resolveMediaStartSeconds(input: MediaStartInput & {
13
+ ordinaryStart: () => number;
14
+ }): number;
15
+ /** True when the authored start is already root time, so no host offset applies. */
16
+ declare function isRootGlobalMediaStart(input: MediaStartInput): boolean;
17
+ interface MediaStartInput {
18
+ authoredStart: number | null;
19
+ hostStart: number;
20
+ hasAutoStart: boolean;
21
+ basis?: string | null;
22
+ }
23
+ /** A composition host's in-point; only a host with one shifts or cuts what it holds. */
24
+ declare function hostInPointSeconds(host: Pick<Element, "getAttribute">): number;
25
+ /** Main-timeline time of a sub-composition's local t=0: its host's start minus its in-point. */
26
+ declare function compositionOriginSeconds(hostStart: number, host: Pick<Element, "getAttribute">): number;
27
+ interface HostSlot {
28
+ start: number;
29
+ end: number;
30
+ }
31
+ /** Each in-point host cuts the span to its own window. */
32
+ declare function cutToHostSlots(span: {
33
+ start: number;
34
+ end: number;
35
+ }, hosts: readonly HostSlot[]): {
36
+ start: number;
37
+ end: number;
38
+ };
39
+
40
+ export { type HostSlot, MEDIA_START_BASIS_ATTR, type MediaStartBasis, type MediaStartInput, compositionOriginSeconds, cutToHostSlots, hostInPointSeconds, isRootGlobalMediaStart, readMediaStartBasis, resolveAbsoluteMediaStartSeconds, resolveMediaStartSeconds };
@@ -0,0 +1,79 @@
1
+ // src/compositionContract.ts
2
+ var COMPOSITION_ATTRIBUTES = Object.freeze({
3
+ start: "data-start",
4
+ duration: "data-duration",
5
+ trackIndex: "data-track-index",
6
+ derivedEnd: "data-end",
7
+ legacyTrack: "data-layer"
8
+ });
9
+ var CANONICAL_AUTHORED_TIMING_ATTRIBUTES = Object.freeze([
10
+ COMPOSITION_ATTRIBUTES.start,
11
+ COMPOSITION_ATTRIBUTES.duration,
12
+ COMPOSITION_ATTRIBUTES.trackIndex
13
+ ]);
14
+ var DERIVED_TIMING_ATTRIBUTES = Object.freeze([
15
+ COMPOSITION_ATTRIBUTES.derivedEnd
16
+ ]);
17
+ var LEGACY_TIMING_ATTRIBUTES = Object.freeze([
18
+ COMPOSITION_ATTRIBUTES.derivedEnd,
19
+ COMPOSITION_ATTRIBUTES.legacyTrack
20
+ ]);
21
+ function parseNumeric(value) {
22
+ if (value == null || value.trim() === "") return null;
23
+ const parsed = Number(value);
24
+ return Number.isFinite(parsed) ? parsed : null;
25
+ }
26
+
27
+ // src/mediaDuration.ts
28
+ var nonNegative = (raw) => {
29
+ const value = parseNumeric(raw);
30
+ return value !== null && value >= 0 ? value : null;
31
+ };
32
+ function readMediaOffsetSeconds(getAttr) {
33
+ return nonNegative(getAttr("data-playback-start")) ?? nonNegative(getAttr("data-media-start")) ?? 0;
34
+ }
35
+
36
+ // src/mediaTiming.ts
37
+ var MEDIA_START_BASIS_ATTR = "data-hf-media-start-basis";
38
+ function readMediaStartBasis(value) {
39
+ return value?.trim().toLowerCase() === "global" ? "global" : "local";
40
+ }
41
+ function resolveAbsoluteMediaStartSeconds(input) {
42
+ return readMediaStartBasis(input.basis) === "global" ? input.authoredStart : input.hostStart + input.authoredStart;
43
+ }
44
+ function resolveMediaStartSeconds(input) {
45
+ if (!hasLiteralNestedStart(input)) return input.ordinaryStart();
46
+ return resolveAbsoluteMediaStartSeconds({
47
+ authoredStart: input.authoredStart,
48
+ hostStart: input.hostStart,
49
+ basis: input.basis
50
+ });
51
+ }
52
+ function isRootGlobalMediaStart(input) {
53
+ return hasLiteralNestedStart(input) && readMediaStartBasis(input.basis) === "global";
54
+ }
55
+ function hasLiteralNestedStart(input) {
56
+ return !input.hasAutoStart && input.authoredStart != null && input.hostStart !== 0;
57
+ }
58
+ function hostInPointSeconds(host) {
59
+ return readMediaOffsetSeconds((name) => host.getAttribute(name));
60
+ }
61
+ function compositionOriginSeconds(hostStart, host) {
62
+ return hostStart - hostInPointSeconds(host);
63
+ }
64
+ function cutToHostSlots(span, hosts) {
65
+ return hosts.reduce((kept, host) => {
66
+ const start = Math.max(kept.start, host.start);
67
+ return { start, end: Math.max(start, Math.min(kept.end, host.end)) };
68
+ }, span);
69
+ }
70
+ export {
71
+ MEDIA_START_BASIS_ATTR,
72
+ compositionOriginSeconds,
73
+ cutToHostSlots,
74
+ hostInPointSeconds,
75
+ isRootGlobalMediaStart,
76
+ readMediaStartBasis,
77
+ resolveAbsoluteMediaStartSeconds,
78
+ resolveMediaStartSeconds
79
+ };
@@ -0,0 +1,13 @@
1
+ /** Minimal structural DOM shape the reference resolver needs. */
2
+ interface RefResolverEl {
3
+ getAttribute(name: string): string | null;
4
+ }
5
+ interface RefResolverDoc {
6
+ getElementById(id: string): RefResolverEl | null;
7
+ querySelector(selector: string): RefResolverEl | null;
8
+ }
9
+ declare function resolveReferencedStart(doc: RefResolverDoc, el: RefResolverEl, startCache: Map<RefResolverEl, number>, visiting: Set<RefResolverEl>): number;
10
+ /** From `data-duration` or `data-end - start`; null when only the media's own length would settle it. */
11
+ declare function resolveReferencedDuration(doc: RefResolverDoc, el: RefResolverEl, startCache: Map<RefResolverEl, number>, visiting: Set<RefResolverEl>): number | null;
12
+
13
+ export { type RefResolverDoc, type RefResolverEl, resolveReferencedDuration, resolveReferencedStart };
@@ -0,0 +1,125 @@
1
+ // src/compositionContract.ts
2
+ var COMPOSITION_ATTRIBUTES = Object.freeze({
3
+ start: "data-start",
4
+ duration: "data-duration",
5
+ trackIndex: "data-track-index",
6
+ derivedEnd: "data-end",
7
+ legacyTrack: "data-layer"
8
+ });
9
+ var CANONICAL_AUTHORED_TIMING_ATTRIBUTES = Object.freeze([
10
+ COMPOSITION_ATTRIBUTES.start,
11
+ COMPOSITION_ATTRIBUTES.duration,
12
+ COMPOSITION_ATTRIBUTES.trackIndex
13
+ ]);
14
+ var DERIVED_TIMING_ATTRIBUTES = Object.freeze([
15
+ COMPOSITION_ATTRIBUTES.derivedEnd
16
+ ]);
17
+ var LEGACY_TIMING_ATTRIBUTES = Object.freeze([
18
+ COMPOSITION_ATTRIBUTES.derivedEnd,
19
+ COMPOSITION_ATTRIBUTES.legacyTrack
20
+ ]);
21
+ function parseNumeric(value) {
22
+ if (value == null || value.trim() === "") return null;
23
+ const parsed = Number(value);
24
+ return Number.isFinite(parsed) ? parsed : null;
25
+ }
26
+ var REFERENCE_ID_PATTERN = /^[A-Za-z0-9_.:-]+$/;
27
+ function isAsciiDigitAt(value, index) {
28
+ const code = value.charCodeAt(index);
29
+ return code >= 48 && code <= 57;
30
+ }
31
+ function skipDigitsLeft(value, start) {
32
+ let cursor = start;
33
+ while (cursor >= 0 && isAsciiDigitAt(value, cursor)) cursor--;
34
+ return cursor;
35
+ }
36
+ function skipWhitespaceLeft(value, start) {
37
+ let cursor = start;
38
+ while (cursor >= 0 && (value[cursor] ?? "").trim() === "") cursor--;
39
+ return cursor;
40
+ }
41
+ function findMagnitudeStart(value) {
42
+ const last = value.length - 1;
43
+ if (!isAsciiDigitAt(value, last)) return null;
44
+ let cursor = skipDigitsLeft(value, last);
45
+ if (value[cursor] === ".") cursor = skipDigitsLeft(value, cursor - 1);
46
+ return cursor + 1;
47
+ }
48
+ function parseReferenceOffset(value) {
49
+ const magnitudeStart = findMagnitudeStart(value);
50
+ if (magnitudeStart == null) return null;
51
+ const operatorIndex = skipWhitespaceLeft(value, magnitudeStart - 1);
52
+ const operator = value[operatorIndex];
53
+ if (operator !== "+" && operator !== "-") return null;
54
+ const refId = value.slice(0, operatorIndex).trim();
55
+ if (!REFERENCE_ID_PATTERN.test(refId)) return null;
56
+ const magnitude = Number(value.slice(magnitudeStart));
57
+ if (!Number.isFinite(magnitude)) return null;
58
+ return { refId, operator, magnitude };
59
+ }
60
+ function parseStartExpression(raw) {
61
+ const normalized = (raw ?? "").trim();
62
+ if (!normalized) return null;
63
+ const absolute = parseNumeric(normalized);
64
+ if (absolute != null) return { kind: "absolute", value: absolute };
65
+ if (REFERENCE_ID_PATTERN.test(normalized)) {
66
+ return { kind: "reference", refId: normalized, offset: 0 };
67
+ }
68
+ const reference = parseReferenceOffset(normalized);
69
+ if (!reference) return null;
70
+ return {
71
+ kind: "reference",
72
+ refId: reference.refId,
73
+ offset: reference.operator === "-" ? -reference.magnitude : reference.magnitude
74
+ };
75
+ }
76
+
77
+ // src/referenceResolver.ts
78
+ function findReferenceTargetEl(doc, refId) {
79
+ return doc.getElementById(refId) ?? doc.querySelector(`[data-composition-id="${refId}"]`);
80
+ }
81
+ function resolveReferencedStart(doc, el, startCache, visiting) {
82
+ const cached = startCache.get(el);
83
+ if (cached !== void 0) return cached;
84
+ if (visiting.has(el)) return 0;
85
+ visiting.add(el);
86
+ try {
87
+ const expression = parseStartExpression(el.getAttribute("data-start"));
88
+ if (!expression) {
89
+ startCache.set(el, 0);
90
+ return 0;
91
+ }
92
+ if (expression.kind === "absolute") {
93
+ const value = Math.max(0, expression.value);
94
+ startCache.set(el, value);
95
+ return value;
96
+ }
97
+ const target = findReferenceTargetEl(doc, expression.refId);
98
+ if (!target) {
99
+ startCache.set(el, 0);
100
+ return 0;
101
+ }
102
+ const targetStart = resolveReferencedStart(doc, target, startCache, visiting);
103
+ const targetDuration = resolveReferencedDuration(doc, target, startCache, visiting);
104
+ const resolved = targetDuration != null && targetDuration > 0 ? Math.max(0, targetStart + targetDuration + expression.offset) : Math.max(0, targetStart + expression.offset);
105
+ startCache.set(el, resolved);
106
+ return resolved;
107
+ } finally {
108
+ visiting.delete(el);
109
+ }
110
+ }
111
+ function resolveReferencedDuration(doc, el, startCache, visiting) {
112
+ const durationAttr = parseNumeric(el.getAttribute("data-duration"));
113
+ if (durationAttr != null && durationAttr > 0) return durationAttr;
114
+ const endAttr = parseNumeric(el.getAttribute("data-end"));
115
+ if (endAttr != null) {
116
+ const start = resolveReferencedStart(doc, el, startCache, visiting);
117
+ const delta = endAttr - start;
118
+ if (Number.isFinite(delta) && delta > 0) return delta;
119
+ }
120
+ return null;
121
+ }
122
+ export {
123
+ resolveReferencedDuration,
124
+ resolveReferencedStart
125
+ };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hyperframes/parsers",
3
- "version": "0.8.181",
3
+ "version": "0.8.183",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/heygen-com/hyperframes",
@@ -100,6 +100,14 @@
100
100
  "import": "./dist/timeSpans.js",
101
101
  "types": "./dist/timeSpans.d.ts"
102
102
  },
103
+ "./media-timing": {
104
+ "import": "./dist/mediaTiming.js",
105
+ "types": "./dist/mediaTiming.d.ts"
106
+ },
107
+ "./reference-resolver": {
108
+ "import": "./dist/referenceResolver.js",
109
+ "types": "./dist/referenceResolver.d.ts"
110
+ },
103
111
  "./composition-duration": {
104
112
  "import": "./dist/compositionDuration.js",
105
113
  "types": "./dist/compositionDuration.d.ts"
@@ -123,7 +131,7 @@
123
131
  "tsx": "^4.21.0",
124
132
  "typescript": "^5.0.0",
125
133
  "vitest": "^4.1.11",
126
- "@hyperframes/core": "0.8.181"
134
+ "@hyperframes/core": "0.8.183"
127
135
  },
128
136
  "scripts": {
129
137
  "build": "tsup",