@hyperframes/parsers 0.7.60 → 0.7.62
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/assetResolution.d.ts +19 -0
- package/dist/assetResolution.js +87 -0
- package/dist/assetResolution.js.map +1 -0
- package/dist/composition.d.ts +3 -2
- package/dist/composition.js +299 -1
- package/dist/composition.js.map +1 -1
- package/dist/compositionContract.d.ts +77 -0
- package/dist/compositionContract.js +282 -0
- package/dist/compositionContract.js.map +1 -0
- package/dist/ffBinaries.d.ts +30 -0
- package/dist/ffBinaries.js +98 -0
- package/dist/ffBinaries.js.map +1 -0
- package/dist/gsapParser.d.ts +3 -3
- package/dist/gsapParserAcorn.d.ts +3 -3
- package/dist/gsapParserExports.d.ts +2 -2
- package/dist/{gsapSerialize-CTPaxKTV.d.ts → gsapSerialize-cLD37cjI.d.ts} +1 -1
- package/dist/gsapWriterAcorn.d.ts +2 -2
- package/dist/index.d.ts +21 -4
- package/dist/index.js +338 -28
- package/dist/index.js.map +1 -1
- package/dist/{types-CaeOJXdW.d.ts → types-ewozML_N.d.ts} +43 -1
- package/package.json +14 -2
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared local-asset resolution helpers for every package that maps
|
|
3
|
+
* composition asset URLs to files on disk (lint project rules, the HEVC
|
|
4
|
+
* preview check, studio-server's media codec scan). Import via the
|
|
5
|
+
* `@hyperframes/parsers/asset-resolution` subpath.
|
|
6
|
+
*/
|
|
7
|
+
declare function isRemoteOrInlineUrl(url: string): boolean;
|
|
8
|
+
declare function cleanAssetUrl(url: string): string;
|
|
9
|
+
declare function isWithinProjectRoot(projectDir: string, candidate: string): boolean;
|
|
10
|
+
declare function resolveLocalAssetCandidates(projectDir: string, url: string): string[];
|
|
11
|
+
declare function resolveExistingLocalAsset(projectDir: string, url: string): {
|
|
12
|
+
resolved: string;
|
|
13
|
+
rootRelativePath: string;
|
|
14
|
+
} | null;
|
|
15
|
+
/** Blanks out comments, `<style>`, and `<script>` bodies so tag-scanning
|
|
16
|
+
* regexes don't false-positive on commented-out or scripted markup. */
|
|
17
|
+
declare function maskNonScannableRanges(html: string): string;
|
|
18
|
+
|
|
19
|
+
export { cleanAssetUrl, isRemoteOrInlineUrl, isWithinProjectRoot, maskNonScannableRanges, resolveExistingLocalAsset, resolveLocalAssetCandidates };
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// src/assetResolution.ts
|
|
2
|
+
import { existsSync } from "fs";
|
|
3
|
+
import { isAbsolute, posix, relative, resolve } from "path";
|
|
4
|
+
|
|
5
|
+
// src/utils/urlPath.ts
|
|
6
|
+
function decodeUrlPathVariants(path) {
|
|
7
|
+
const variants = [path];
|
|
8
|
+
try {
|
|
9
|
+
const decoded = decodeURIComponent(path);
|
|
10
|
+
if (decoded !== path) variants.unshift(decoded);
|
|
11
|
+
} catch {
|
|
12
|
+
}
|
|
13
|
+
return variants;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
// src/assetResolution.ts
|
|
17
|
+
function isRemoteOrInlineUrl(url) {
|
|
18
|
+
return /^(https?:|data:|blob:|\/\/|#)/i.test(url);
|
|
19
|
+
}
|
|
20
|
+
function cleanAssetUrl(url) {
|
|
21
|
+
return url.trim().split(/[?#]/, 1)[0] ?? "";
|
|
22
|
+
}
|
|
23
|
+
function isWithinProjectRoot(projectDir, candidate) {
|
|
24
|
+
const projectRoot = resolve(projectDir);
|
|
25
|
+
const relativePath = relative(projectRoot, candidate);
|
|
26
|
+
return relativePath === "" || !relativePath.startsWith("..") && !isAbsolute(relativePath);
|
|
27
|
+
}
|
|
28
|
+
function addCandidate(candidates, candidate) {
|
|
29
|
+
if (!candidates.includes(candidate)) candidates.push(candidate);
|
|
30
|
+
}
|
|
31
|
+
function resolveLocalAssetCandidates(projectDir, url) {
|
|
32
|
+
const cleanUrl = cleanAssetUrl(url);
|
|
33
|
+
const projectRoot = resolve(projectDir);
|
|
34
|
+
const candidates = [];
|
|
35
|
+
for (const variant of decodeUrlPathVariants(cleanUrl)) {
|
|
36
|
+
const projectRelative = variant.startsWith("/") ? variant.slice(1) : variant;
|
|
37
|
+
const resolved = resolve(projectRoot, projectRelative);
|
|
38
|
+
if (isWithinProjectRoot(projectRoot, resolved)) {
|
|
39
|
+
addCandidate(candidates, resolved);
|
|
40
|
+
continue;
|
|
41
|
+
}
|
|
42
|
+
const normalized = posix.normalize(projectRelative.replace(/\\/g, "/"));
|
|
43
|
+
const clamped = normalized.replace(/^(\.\.\/)+/, "");
|
|
44
|
+
if (clamped && !clamped.startsWith("..")) {
|
|
45
|
+
addCandidate(candidates, resolve(projectRoot, clamped));
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return candidates;
|
|
49
|
+
}
|
|
50
|
+
function resolveExistingLocalAsset(projectDir, url) {
|
|
51
|
+
const projectRoot = resolve(projectDir);
|
|
52
|
+
const resolved = resolveLocalAssetCandidates(projectRoot, url).find(existsSync);
|
|
53
|
+
if (!resolved) return null;
|
|
54
|
+
return { resolved, rootRelativePath: relative(projectRoot, resolved) };
|
|
55
|
+
}
|
|
56
|
+
function maskRange(src, pattern) {
|
|
57
|
+
return src.replace(pattern, (m) => " ".repeat(m.length));
|
|
58
|
+
}
|
|
59
|
+
function maskHtmlComments(src) {
|
|
60
|
+
const chunks = [];
|
|
61
|
+
let cursor = 0;
|
|
62
|
+
while (true) {
|
|
63
|
+
const start = src.indexOf("<!--", cursor);
|
|
64
|
+
if (start === -1) break;
|
|
65
|
+
const end = src.indexOf("-->", start + 4);
|
|
66
|
+
if (end === -1) break;
|
|
67
|
+
const afterComment = end + 3;
|
|
68
|
+
chunks.push(src.slice(cursor, start), " ".repeat(afterComment - start));
|
|
69
|
+
cursor = afterComment;
|
|
70
|
+
}
|
|
71
|
+
return chunks.length === 0 ? src : chunks.join("") + src.slice(cursor);
|
|
72
|
+
}
|
|
73
|
+
function maskNonScannableRanges(html) {
|
|
74
|
+
let out = maskHtmlComments(html);
|
|
75
|
+
out = maskRange(out, /<style\b[^>]*>[\s\S]*?<\/style\b[^>]*>/gi);
|
|
76
|
+
out = maskRange(out, /<script\b[^>]*>[\s\S]*?<\/script\b[^>]*>/gi);
|
|
77
|
+
return out;
|
|
78
|
+
}
|
|
79
|
+
export {
|
|
80
|
+
cleanAssetUrl,
|
|
81
|
+
isRemoteOrInlineUrl,
|
|
82
|
+
isWithinProjectRoot,
|
|
83
|
+
maskNonScannableRanges,
|
|
84
|
+
resolveExistingLocalAsset,
|
|
85
|
+
resolveLocalAssetCandidates
|
|
86
|
+
};
|
|
87
|
+
//# sourceMappingURL=assetResolution.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/assetResolution.ts","../src/utils/urlPath.ts"],"sourcesContent":["import { existsSync } from \"node:fs\";\nimport { isAbsolute, posix, relative, resolve } from \"node:path\";\nimport { decodeUrlPathVariants } from \"./composition.js\";\n\n/**\n * Shared local-asset resolution helpers for every package that maps\n * composition asset URLs to files on disk (lint project rules, the HEVC\n * preview check, studio-server's media codec scan). Import via the\n * `@hyperframes/parsers/asset-resolution` subpath.\n */\n\nexport function isRemoteOrInlineUrl(url: string): boolean {\n return /^(https?:|data:|blob:|\\/\\/|#)/i.test(url);\n}\n\nexport function cleanAssetUrl(url: string): string {\n return url.trim().split(/[?#]/, 1)[0] ?? \"\";\n}\n\nexport function isWithinProjectRoot(projectDir: string, candidate: string): boolean {\n const projectRoot = resolve(projectDir);\n const relativePath = relative(projectRoot, candidate);\n return relativePath === \"\" || (!relativePath.startsWith(\"..\") && !isAbsolute(relativePath));\n}\n\nfunction addCandidate(candidates: string[], candidate: string): void {\n if (!candidates.includes(candidate)) candidates.push(candidate);\n}\n\nexport function resolveLocalAssetCandidates(projectDir: string, url: string): string[] {\n const cleanUrl = cleanAssetUrl(url);\n const projectRoot = resolve(projectDir);\n const candidates: string[] = [];\n\n for (const variant of decodeUrlPathVariants(cleanUrl)) {\n const projectRelative = variant.startsWith(\"/\") ? variant.slice(1) : variant;\n const resolved = resolve(projectRoot, projectRelative);\n if (isWithinProjectRoot(projectRoot, resolved)) {\n addCandidate(candidates, resolved);\n continue;\n }\n\n const normalized = posix.normalize(projectRelative.replace(/\\\\/g, \"/\"));\n const clamped = normalized.replace(/^(\\.\\.\\/)+/, \"\");\n if (clamped && !clamped.startsWith(\"..\")) {\n addCandidate(candidates, resolve(projectRoot, clamped));\n }\n }\n\n return candidates;\n}\n\nexport function resolveExistingLocalAsset(\n projectDir: string,\n url: string,\n): { resolved: string; rootRelativePath: string } | null {\n const projectRoot = resolve(projectDir);\n const resolved = resolveLocalAssetCandidates(projectRoot, url).find(existsSync);\n if (!resolved) return null;\n return { resolved, rootRelativePath: relative(projectRoot, resolved) };\n}\n\nfunction maskRange(src: string, pattern: RegExp): string {\n return src.replace(pattern, (m) => \" \".repeat(m.length));\n}\n\nfunction maskHtmlComments(src: string): string {\n const chunks: string[] = [];\n let cursor = 0;\n\n while (true) {\n const start = src.indexOf(\"<!--\", cursor);\n if (start === -1) break;\n const end = src.indexOf(\"-->\", start + 4);\n if (end === -1) break;\n const afterComment = end + 3;\n chunks.push(src.slice(cursor, start), \" \".repeat(afterComment - start));\n cursor = afterComment;\n }\n\n return chunks.length === 0 ? src : chunks.join(\"\") + src.slice(cursor);\n}\n\n/** Blanks out comments, `<style>`, and `<script>` bodies so tag-scanning\n * regexes don't false-positive on commented-out or scripted markup. */\nexport function maskNonScannableRanges(html: string): string {\n let out = maskHtmlComments(html);\n out = maskRange(out, /<style\\b[^>]*>[\\s\\S]*?<\\/style\\b[^>]*>/gi);\n out = maskRange(out, /<script\\b[^>]*>[\\s\\S]*?<\\/script\\b[^>]*>/gi);\n return out;\n}\n","export function decodeUrlPathVariants(path: string): string[] {\n const variants = [path];\n try {\n const decoded = decodeURIComponent(path);\n if (decoded !== path) variants.unshift(decoded);\n } catch {\n // Malformed percent sequences may be literal filesystem names.\n }\n\n return variants;\n}\n"],"mappings":";AAAA,SAAS,kBAAkB;AAC3B,SAAS,YAAY,OAAO,UAAU,eAAe;;;ACD9C,SAAS,sBAAsB,MAAwB;AAC5D,QAAM,WAAW,CAAC,IAAI;AACtB,MAAI;AACF,UAAM,UAAU,mBAAmB,IAAI;AACvC,QAAI,YAAY,KAAM,UAAS,QAAQ,OAAO;AAAA,EAChD,QAAQ;AAAA,EAER;AAEA,SAAO;AACT;;;ADCO,SAAS,oBAAoB,KAAsB;AACxD,SAAO,iCAAiC,KAAK,GAAG;AAClD;AAEO,SAAS,cAAc,KAAqB;AACjD,SAAO,IAAI,KAAK,EAAE,MAAM,QAAQ,CAAC,EAAE,CAAC,KAAK;AAC3C;AAEO,SAAS,oBAAoB,YAAoB,WAA4B;AAClF,QAAM,cAAc,QAAQ,UAAU;AACtC,QAAM,eAAe,SAAS,aAAa,SAAS;AACpD,SAAO,iBAAiB,MAAO,CAAC,aAAa,WAAW,IAAI,KAAK,CAAC,WAAW,YAAY;AAC3F;AAEA,SAAS,aAAa,YAAsB,WAAyB;AACnE,MAAI,CAAC,WAAW,SAAS,SAAS,EAAG,YAAW,KAAK,SAAS;AAChE;AAEO,SAAS,4BAA4B,YAAoB,KAAuB;AACrF,QAAM,WAAW,cAAc,GAAG;AAClC,QAAM,cAAc,QAAQ,UAAU;AACtC,QAAM,aAAuB,CAAC;AAE9B,aAAW,WAAW,sBAAsB,QAAQ,GAAG;AACrD,UAAM,kBAAkB,QAAQ,WAAW,GAAG,IAAI,QAAQ,MAAM,CAAC,IAAI;AACrE,UAAM,WAAW,QAAQ,aAAa,eAAe;AACrD,QAAI,oBAAoB,aAAa,QAAQ,GAAG;AAC9C,mBAAa,YAAY,QAAQ;AACjC;AAAA,IACF;AAEA,UAAM,aAAa,MAAM,UAAU,gBAAgB,QAAQ,OAAO,GAAG,CAAC;AACtE,UAAM,UAAU,WAAW,QAAQ,cAAc,EAAE;AACnD,QAAI,WAAW,CAAC,QAAQ,WAAW,IAAI,GAAG;AACxC,mBAAa,YAAY,QAAQ,aAAa,OAAO,CAAC;AAAA,IACxD;AAAA,EACF;AAEA,SAAO;AACT;AAEO,SAAS,0BACd,YACA,KACuD;AACvD,QAAM,cAAc,QAAQ,UAAU;AACtC,QAAM,WAAW,4BAA4B,aAAa,GAAG,EAAE,KAAK,UAAU;AAC9E,MAAI,CAAC,SAAU,QAAO;AACtB,SAAO,EAAE,UAAU,kBAAkB,SAAS,aAAa,QAAQ,EAAE;AACvE;AAEA,SAAS,UAAU,KAAa,SAAyB;AACvD,SAAO,IAAI,QAAQ,SAAS,CAAC,MAAM,IAAI,OAAO,EAAE,MAAM,CAAC;AACzD;AAEA,SAAS,iBAAiB,KAAqB;AAC7C,QAAM,SAAmB,CAAC;AAC1B,MAAI,SAAS;AAEb,SAAO,MAAM;AACX,UAAM,QAAQ,IAAI,QAAQ,QAAQ,MAAM;AACxC,QAAI,UAAU,GAAI;AAClB,UAAM,MAAM,IAAI,QAAQ,OAAO,QAAQ,CAAC;AACxC,QAAI,QAAQ,GAAI;AAChB,UAAM,eAAe,MAAM;AAC3B,WAAO,KAAK,IAAI,MAAM,QAAQ,KAAK,GAAG,IAAI,OAAO,eAAe,KAAK,CAAC;AACtE,aAAS;AAAA,EACX;AAEA,SAAO,OAAO,WAAW,IAAI,MAAM,OAAO,KAAK,EAAE,IAAI,IAAI,MAAM,MAAM;AACvE;AAIO,SAAS,uBAAuB,MAAsB;AAC3D,MAAI,MAAM,iBAAiB,IAAI;AAC/B,QAAM,UAAU,KAAK,0CAA0C;AAC/D,QAAM,UAAU,KAAK,4CAA4C;AACjE,SAAO;AACT;","names":[]}
|
package/dist/composition.d.ts
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { C as CompositionVariable } from './types-
|
|
2
|
-
export { A as AddElementData, b as Asset, B as BooleanVariable, c as CANVAS_DIMENSIONS, d as COMPOSITION_VARIABLE_TYPES, a as CanvasResolution, e as ColorVariable, f as CompositionAPI, g as CompositionAsset, h as CompositionSpec, i as CompositionVariableBase, j as CompositionVariableType, D as DEFAULT_DURATIONS, E as ElementKeyframes, k as EnumVariable, F as FontVariable, I as ImageVariable, K as Keyframe, l as KeyframeProperties, M as MediaElementType, m as MediaFile, N as NumberVariable, P as PlayerAPI, n as StageZoom, S as StageZoomKeyframe, o as StringVariable, p as TIMELINE_COLORS, q as TimelineCompositionElement, T as TimelineElement, r as TimelineElementBase, s as TimelineElementType, t as TimelineMediaElement, u as TimelineTextElement, v as VALID_CANVAS_RESOLUTIONS, V as ValidationResult, W as WaveformData, w as getDefaultStageZoom, x as
|
|
1
|
+
import { C as CompositionVariable } from './types-ewozML_N.js';
|
|
2
|
+
export { A as AddElementData, b as Asset, B as BooleanVariable, c as CANVAS_DIMENSIONS, d as COMPOSITION_VARIABLE_TYPES, a as CanvasResolution, e as ColorVariable, f as CompositionAPI, g as CompositionAsset, h as CompositionSpec, i as CompositionVariableBase, j as CompositionVariableType, D as DEFAULT_DURATIONS, E as ElementKeyframes, k as EnumVariable, F as FontVariable, I as ImageVariable, K as Keyframe, l as KeyframeProperties, M as MediaElementType, m as MediaFile, N as NumberVariable, P as PlayerAPI, R as ResolvedResolutionFlag, n as StageZoom, S as StageZoomKeyframe, o as StringVariable, p as TIMELINE_COLORS, q as TimelineCompositionElement, T as TimelineElement, r as TimelineElementBase, s as TimelineElementType, t as TimelineMediaElement, u as TimelineTextElement, v as VALID_CANVAS_RESOLUTIONS, V as ValidationResult, W as WaveformData, w as getDefaultStageZoom, x as isAspectAgnosticResolutionAlias, y as isCompositionElement, z as isMediaElement, G as isTextElement, H as normalizeResolutionFlag, J as resolveResolutionFlagPair } from './types-ewozML_N.js';
|
|
3
|
+
export { CANONICAL_AUTHORED_TIMING_ATTRIBUTES, COMPOSITION_ATTRIBUTES, COMPOSITION_CONTRACT_VERSION, ClipAttributeReader, ClipAttributeWriter, ClipTiming, ClipTimingDiagnostic, ClipTimingDiagnosticCode, ClipTimingUpdate, ClipTimingWriteError, DERIVED_TIMING_ATTRIBUTES, LEGACY_TIMING_ATTRIBUTES, ReadClipTimingOptions, ReferenceExpression, parseNumeric, parseStartExpression, readClipTiming, writeClipTiming } from './compositionContract.js';
|
|
3
4
|
|
|
4
5
|
/**
|
|
5
6
|
* Browser-safe parser for the `data-composition-variables` schema attribute.
|
package/dist/composition.js
CHANGED
|
@@ -22,6 +22,12 @@ var RESOLUTION_ALIASES = {
|
|
|
22
22
|
"square-1080p": "square",
|
|
23
23
|
"4k-square": "square-4k"
|
|
24
24
|
};
|
|
25
|
+
var ASPECT_AGNOSTIC_RESOLUTION_ALIASES = /* @__PURE__ */ new Set([
|
|
26
|
+
"1080p",
|
|
27
|
+
"hd",
|
|
28
|
+
"4k",
|
|
29
|
+
"uhd"
|
|
30
|
+
]);
|
|
25
31
|
function normalizeResolutionFlag(input) {
|
|
26
32
|
if (!input) return void 0;
|
|
27
33
|
const lowered = input.toLowerCase();
|
|
@@ -30,6 +36,16 @@ function normalizeResolutionFlag(input) {
|
|
|
30
36
|
}
|
|
31
37
|
return RESOLUTION_ALIASES[lowered];
|
|
32
38
|
}
|
|
39
|
+
function isAspectAgnosticResolutionAlias(input) {
|
|
40
|
+
if (!input) return false;
|
|
41
|
+
return ASPECT_AGNOSTIC_RESOLUTION_ALIASES.has(input.toLowerCase());
|
|
42
|
+
}
|
|
43
|
+
function resolveResolutionFlagPair(input) {
|
|
44
|
+
return {
|
|
45
|
+
outputResolution: normalizeResolutionFlag(input),
|
|
46
|
+
outputResolutionAspectAgnostic: isAspectAgnosticResolutionAlias(input)
|
|
47
|
+
};
|
|
48
|
+
}
|
|
33
49
|
var COMPOSITION_VARIABLE_TYPES = [
|
|
34
50
|
"string",
|
|
35
51
|
"number",
|
|
@@ -334,17 +350,294 @@ function scanVariableUsage(scriptText) {
|
|
|
334
350
|
}
|
|
335
351
|
return { usedIds, scanIncomplete };
|
|
336
352
|
}
|
|
353
|
+
|
|
354
|
+
// src/compositionContract.ts
|
|
355
|
+
var COMPOSITION_CONTRACT_VERSION = 1;
|
|
356
|
+
var COMPOSITION_ATTRIBUTES = Object.freeze({
|
|
357
|
+
start: "data-start",
|
|
358
|
+
duration: "data-duration",
|
|
359
|
+
trackIndex: "data-track-index",
|
|
360
|
+
derivedEnd: "data-end",
|
|
361
|
+
legacyTrack: "data-layer"
|
|
362
|
+
});
|
|
363
|
+
var CANONICAL_AUTHORED_TIMING_ATTRIBUTES = Object.freeze([
|
|
364
|
+
COMPOSITION_ATTRIBUTES.start,
|
|
365
|
+
COMPOSITION_ATTRIBUTES.duration,
|
|
366
|
+
COMPOSITION_ATTRIBUTES.trackIndex
|
|
367
|
+
]);
|
|
368
|
+
var DERIVED_TIMING_ATTRIBUTES = Object.freeze([
|
|
369
|
+
COMPOSITION_ATTRIBUTES.derivedEnd
|
|
370
|
+
]);
|
|
371
|
+
var LEGACY_TIMING_ATTRIBUTES = Object.freeze([
|
|
372
|
+
COMPOSITION_ATTRIBUTES.derivedEnd,
|
|
373
|
+
COMPOSITION_ATTRIBUTES.legacyTrack
|
|
374
|
+
]);
|
|
375
|
+
var ClipTimingWriteError = class extends Error {
|
|
376
|
+
code;
|
|
377
|
+
constructor(code, message) {
|
|
378
|
+
super(message);
|
|
379
|
+
this.name = "ClipTimingWriteError";
|
|
380
|
+
this.code = code;
|
|
381
|
+
}
|
|
382
|
+
};
|
|
383
|
+
function parseNumeric(value) {
|
|
384
|
+
if (value == null || value.trim() === "") return null;
|
|
385
|
+
const parsed = Number(value);
|
|
386
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
387
|
+
}
|
|
388
|
+
var REFERENCE_ID_PATTERN = /^[A-Za-z0-9_.:-]+$/;
|
|
389
|
+
function isAsciiDigitAt(value, index) {
|
|
390
|
+
const code = value.charCodeAt(index);
|
|
391
|
+
return code >= 48 && code <= 57;
|
|
392
|
+
}
|
|
393
|
+
function skipDigitsLeft(value, start) {
|
|
394
|
+
let cursor = start;
|
|
395
|
+
while (cursor >= 0 && isAsciiDigitAt(value, cursor)) cursor--;
|
|
396
|
+
return cursor;
|
|
397
|
+
}
|
|
398
|
+
function skipWhitespaceLeft(value, start) {
|
|
399
|
+
let cursor = start;
|
|
400
|
+
while (cursor >= 0 && (value[cursor] ?? "").trim() === "") cursor--;
|
|
401
|
+
return cursor;
|
|
402
|
+
}
|
|
403
|
+
function findMagnitudeStart(value) {
|
|
404
|
+
const last = value.length - 1;
|
|
405
|
+
if (!isAsciiDigitAt(value, last)) return null;
|
|
406
|
+
let cursor = skipDigitsLeft(value, last);
|
|
407
|
+
if (value[cursor] === ".") cursor = skipDigitsLeft(value, cursor - 1);
|
|
408
|
+
return cursor + 1;
|
|
409
|
+
}
|
|
410
|
+
function parseReferenceOffset(value) {
|
|
411
|
+
const magnitudeStart = findMagnitudeStart(value);
|
|
412
|
+
if (magnitudeStart == null) return null;
|
|
413
|
+
const operatorIndex = skipWhitespaceLeft(value, magnitudeStart - 1);
|
|
414
|
+
const operator = value[operatorIndex];
|
|
415
|
+
if (operator !== "+" && operator !== "-") return null;
|
|
416
|
+
const refId = value.slice(0, operatorIndex).trim();
|
|
417
|
+
if (!REFERENCE_ID_PATTERN.test(refId)) return null;
|
|
418
|
+
const magnitude = Number(value.slice(magnitudeStart));
|
|
419
|
+
if (!Number.isFinite(magnitude)) return null;
|
|
420
|
+
return { refId, operator, magnitude };
|
|
421
|
+
}
|
|
422
|
+
function parseStartExpression(raw) {
|
|
423
|
+
const normalized = (raw ?? "").trim();
|
|
424
|
+
if (!normalized) return null;
|
|
425
|
+
const absolute = parseNumeric(normalized);
|
|
426
|
+
if (absolute != null) return { kind: "absolute", value: absolute };
|
|
427
|
+
if (REFERENCE_ID_PATTERN.test(normalized)) {
|
|
428
|
+
return { kind: "reference", refId: normalized, offset: 0 };
|
|
429
|
+
}
|
|
430
|
+
const reference = parseReferenceOffset(normalized);
|
|
431
|
+
if (!reference) return null;
|
|
432
|
+
return {
|
|
433
|
+
kind: "reference",
|
|
434
|
+
refId: reference.refId,
|
|
435
|
+
offset: reference.operator === "-" ? -reference.magnitude : reference.magnitude
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
function pushDiagnostic(diagnostics, code, attribute, value) {
|
|
439
|
+
diagnostics.push({ code, attribute, value });
|
|
440
|
+
}
|
|
441
|
+
function resolveStart(expression, rawStart, options, diagnostics) {
|
|
442
|
+
if (rawStart == null || rawStart.trim() === "") {
|
|
443
|
+
return options.defaultStart === void 0 ? 0 : options.defaultStart;
|
|
444
|
+
}
|
|
445
|
+
if (!expression) {
|
|
446
|
+
pushDiagnostic(diagnostics, "invalid-start", COMPOSITION_ATTRIBUTES.start, rawStart);
|
|
447
|
+
return null;
|
|
448
|
+
}
|
|
449
|
+
if (expression.kind === "absolute") return Math.max(0, expression.value);
|
|
450
|
+
const referencedEnd = options.resolveReferenceEnd?.(expression.refId);
|
|
451
|
+
if (referencedEnd == null || !Number.isFinite(referencedEnd)) {
|
|
452
|
+
pushDiagnostic(
|
|
453
|
+
diagnostics,
|
|
454
|
+
"unresolved-start-reference",
|
|
455
|
+
COMPOSITION_ATTRIBUTES.start,
|
|
456
|
+
rawStart
|
|
457
|
+
);
|
|
458
|
+
return null;
|
|
459
|
+
}
|
|
460
|
+
return Math.max(0, referencedEnd + expression.offset);
|
|
461
|
+
}
|
|
462
|
+
function diagnoseDerivedEnd(rawEnd, canonicalEnd, diagnostics) {
|
|
463
|
+
pushDiagnostic(diagnostics, "deprecated-end", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
464
|
+
const parsedEnd = parseNumeric(rawEnd);
|
|
465
|
+
if (parsedEnd == null) {
|
|
466
|
+
pushDiagnostic(diagnostics, "invalid-end", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
467
|
+
} else if (canonicalEnd != null && parsedEnd !== canonicalEnd) {
|
|
468
|
+
pushDiagnostic(diagnostics, "conflicting-end", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
function readCanonicalDuration(rawDuration, start, diagnostics) {
|
|
472
|
+
const duration = parseNumeric(rawDuration);
|
|
473
|
+
if (duration == null || duration < 0) {
|
|
474
|
+
pushDiagnostic(diagnostics, "invalid-duration", COMPOSITION_ATTRIBUTES.duration, rawDuration);
|
|
475
|
+
return { duration: null, end: null, durationSource: "invalid" };
|
|
476
|
+
}
|
|
477
|
+
return {
|
|
478
|
+
duration,
|
|
479
|
+
end: start == null ? null : start + duration,
|
|
480
|
+
durationSource: "duration"
|
|
481
|
+
};
|
|
482
|
+
}
|
|
483
|
+
function readLegacyEnd(rawEnd, start, diagnostics) {
|
|
484
|
+
pushDiagnostic(diagnostics, "deprecated-end", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
485
|
+
const end = parseNumeric(rawEnd);
|
|
486
|
+
if (end == null) {
|
|
487
|
+
pushDiagnostic(diagnostics, "invalid-end", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
488
|
+
return { duration: null, end: null, durationSource: "invalid" };
|
|
489
|
+
}
|
|
490
|
+
if (start == null) return { duration: null, end, durationSource: "legacy-end" };
|
|
491
|
+
if (end < start) {
|
|
492
|
+
pushDiagnostic(diagnostics, "end-before-start", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);
|
|
493
|
+
return { duration: null, end: null, durationSource: "invalid" };
|
|
494
|
+
}
|
|
495
|
+
return { duration: end - start, end, durationSource: "legacy-end" };
|
|
496
|
+
}
|
|
497
|
+
function readDuration(attributes, start, diagnostics) {
|
|
498
|
+
const rawDuration = attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration);
|
|
499
|
+
const rawEnd = attributes.getAttribute(COMPOSITION_ATTRIBUTES.derivedEnd);
|
|
500
|
+
if (rawDuration == null) {
|
|
501
|
+
return rawEnd == null ? { duration: null, end: null, durationSource: "missing" } : readLegacyEnd(rawEnd, start, diagnostics);
|
|
502
|
+
}
|
|
503
|
+
const canonical = readCanonicalDuration(rawDuration, start, diagnostics);
|
|
504
|
+
if (rawEnd != null) diagnoseDerivedEnd(rawEnd, canonical.end, diagnostics);
|
|
505
|
+
return canonical;
|
|
506
|
+
}
|
|
507
|
+
function readTrackValue(rawValue, attribute, source, diagnostics) {
|
|
508
|
+
const trackIndex = parseNumeric(rawValue);
|
|
509
|
+
if (trackIndex == null || !Number.isInteger(trackIndex)) {
|
|
510
|
+
pushDiagnostic(diagnostics, "invalid-track-index", attribute, rawValue);
|
|
511
|
+
return { trackIndex: 0, trackSource: "invalid" };
|
|
512
|
+
}
|
|
513
|
+
return { trackIndex, trackSource: source };
|
|
514
|
+
}
|
|
515
|
+
function readTrack(attributes, diagnostics) {
|
|
516
|
+
const rawTrack = attributes.getAttribute(COMPOSITION_ATTRIBUTES.trackIndex);
|
|
517
|
+
const rawLayer = attributes.getAttribute(COMPOSITION_ATTRIBUTES.legacyTrack);
|
|
518
|
+
if (rawTrack == null && rawLayer == null) return { trackIndex: 0, trackSource: "default" };
|
|
519
|
+
if (rawTrack == null && rawLayer != null) {
|
|
520
|
+
pushDiagnostic(diagnostics, "deprecated-layer", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);
|
|
521
|
+
return readTrackValue(
|
|
522
|
+
rawLayer,
|
|
523
|
+
COMPOSITION_ATTRIBUTES.legacyTrack,
|
|
524
|
+
"legacy-layer",
|
|
525
|
+
diagnostics
|
|
526
|
+
);
|
|
527
|
+
}
|
|
528
|
+
const canonical = readTrackValue(
|
|
529
|
+
rawTrack ?? "",
|
|
530
|
+
COMPOSITION_ATTRIBUTES.trackIndex,
|
|
531
|
+
"track-index",
|
|
532
|
+
diagnostics
|
|
533
|
+
);
|
|
534
|
+
if (rawLayer == null) return canonical;
|
|
535
|
+
pushDiagnostic(diagnostics, "deprecated-layer", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);
|
|
536
|
+
const parsedLayer = parseNumeric(rawLayer);
|
|
537
|
+
if (parsedLayer != null && parsedLayer !== canonical.trackIndex) {
|
|
538
|
+
pushDiagnostic(diagnostics, "conflicting-layer", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);
|
|
539
|
+
}
|
|
540
|
+
return canonical;
|
|
541
|
+
}
|
|
542
|
+
function readClipTiming(attributes, options = {}) {
|
|
543
|
+
const diagnostics = [];
|
|
544
|
+
const rawStart = attributes.getAttribute(COMPOSITION_ATTRIBUTES.start);
|
|
545
|
+
const startExpression = parseStartExpression(rawStart);
|
|
546
|
+
const start = resolveStart(startExpression, rawStart, options, diagnostics);
|
|
547
|
+
const duration = readDuration(attributes, start, diagnostics);
|
|
548
|
+
const track = readTrack(attributes, diagnostics);
|
|
549
|
+
return { startExpression, start, ...duration, ...track, diagnostics };
|
|
550
|
+
}
|
|
551
|
+
function serializeStartNumber(start) {
|
|
552
|
+
if (!Number.isFinite(start)) {
|
|
553
|
+
throw new ClipTimingWriteError("invalid-start", "start must be finite");
|
|
554
|
+
}
|
|
555
|
+
return String(start);
|
|
556
|
+
}
|
|
557
|
+
function serializeStartReference(start) {
|
|
558
|
+
if (start.kind === "absolute") return serializeStartNumber(start.value);
|
|
559
|
+
if (!start.refId || !Number.isFinite(start.offset)) {
|
|
560
|
+
throw new ClipTimingWriteError(
|
|
561
|
+
"invalid-start",
|
|
562
|
+
"reference start must have an id and finite offset"
|
|
563
|
+
);
|
|
564
|
+
}
|
|
565
|
+
if (start.offset === 0) return start.refId;
|
|
566
|
+
return `${start.refId} ${start.offset < 0 ? "-" : "+"} ${Math.abs(start.offset)}`;
|
|
567
|
+
}
|
|
568
|
+
function serializeStart(start) {
|
|
569
|
+
if (typeof start === "number") return serializeStartNumber(start);
|
|
570
|
+
if (typeof start === "object" && start != null) return serializeStartReference(start);
|
|
571
|
+
if (typeof start === "string" && parseStartExpression(start)) return start.trim();
|
|
572
|
+
throw new ClipTimingWriteError("invalid-start", `invalid start expression: ${start ?? ""}`);
|
|
573
|
+
}
|
|
574
|
+
function writeDuration(attributes, duration, current) {
|
|
575
|
+
if (duration === null) {
|
|
576
|
+
attributes.removeAttribute(COMPOSITION_ATTRIBUTES.duration);
|
|
577
|
+
return;
|
|
578
|
+
}
|
|
579
|
+
if (duration === void 0) {
|
|
580
|
+
if (attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration) == null && current.duration != null) {
|
|
581
|
+
attributes.setAttribute(COMPOSITION_ATTRIBUTES.duration, String(current.duration));
|
|
582
|
+
}
|
|
583
|
+
return;
|
|
584
|
+
}
|
|
585
|
+
if (!Number.isFinite(duration) || duration < 0) {
|
|
586
|
+
throw new ClipTimingWriteError(
|
|
587
|
+
"invalid-duration",
|
|
588
|
+
"duration must be a finite, non-negative number"
|
|
589
|
+
);
|
|
590
|
+
}
|
|
591
|
+
attributes.setAttribute(COMPOSITION_ATTRIBUTES.duration, String(duration));
|
|
592
|
+
}
|
|
593
|
+
function writeTrack(attributes, trackIndex, current) {
|
|
594
|
+
if (trackIndex === null) {
|
|
595
|
+
attributes.removeAttribute(COMPOSITION_ATTRIBUTES.trackIndex);
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
if (trackIndex === void 0) {
|
|
599
|
+
if (attributes.getAttribute(COMPOSITION_ATTRIBUTES.trackIndex) == null && current.trackSource === "legacy-layer") {
|
|
600
|
+
attributes.setAttribute(COMPOSITION_ATTRIBUTES.trackIndex, String(current.trackIndex));
|
|
601
|
+
}
|
|
602
|
+
return;
|
|
603
|
+
}
|
|
604
|
+
if (!Number.isFinite(trackIndex) || !Number.isInteger(trackIndex)) {
|
|
605
|
+
throw new ClipTimingWriteError("invalid-track-index", "trackIndex must be a finite integer");
|
|
606
|
+
}
|
|
607
|
+
attributes.setAttribute(COMPOSITION_ATTRIBUTES.trackIndex, String(trackIndex));
|
|
608
|
+
}
|
|
609
|
+
function writeClipTiming(attributes, update) {
|
|
610
|
+
const current = readClipTiming(attributes);
|
|
611
|
+
if (update.start !== void 0) {
|
|
612
|
+
attributes.setAttribute(COMPOSITION_ATTRIBUTES.start, serializeStart(update.start));
|
|
613
|
+
}
|
|
614
|
+
writeDuration(attributes, update.duration, current);
|
|
615
|
+
writeTrack(attributes, update.trackIndex, current);
|
|
616
|
+
const preserveUnresolvedLegacyEnd = update.duration === void 0 && attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration) == null && attributes.getAttribute(COMPOSITION_ATTRIBUTES.derivedEnd) != null && current.duration == null;
|
|
617
|
+
if (!preserveUnresolvedLegacyEnd) {
|
|
618
|
+
attributes.removeAttribute(COMPOSITION_ATTRIBUTES.derivedEnd);
|
|
619
|
+
}
|
|
620
|
+
attributes.removeAttribute(COMPOSITION_ATTRIBUTES.legacyTrack);
|
|
621
|
+
return readClipTiming(attributes);
|
|
622
|
+
}
|
|
337
623
|
export {
|
|
624
|
+
CANONICAL_AUTHORED_TIMING_ATTRIBUTES,
|
|
338
625
|
CANONICAL_FONT_DISPLAY_NAMES,
|
|
339
626
|
CANVAS_DIMENSIONS,
|
|
627
|
+
COMPOSITION_ATTRIBUTES,
|
|
628
|
+
COMPOSITION_CONTRACT_VERSION,
|
|
340
629
|
COMPOSITION_VARIABLE_TYPES,
|
|
630
|
+
ClipTimingWriteError,
|
|
341
631
|
DEFAULT_DURATIONS,
|
|
632
|
+
DERIVED_TIMING_ATTRIBUTES,
|
|
342
633
|
FONT_ALIAS_KEYS,
|
|
343
634
|
FONT_ALIAS_MAP,
|
|
635
|
+
LEGACY_TIMING_ATTRIBUTES,
|
|
344
636
|
TIMELINE_COLORS,
|
|
345
637
|
VALID_CANVAS_RESOLUTIONS,
|
|
346
638
|
decodeUrlPathVariants,
|
|
347
639
|
getDefaultStageZoom,
|
|
640
|
+
isAspectAgnosticResolutionAlias,
|
|
348
641
|
isCompositionElement,
|
|
349
642
|
isCompositionVariable,
|
|
350
643
|
isMediaElement,
|
|
@@ -352,7 +645,12 @@ export {
|
|
|
352
645
|
isTextElement,
|
|
353
646
|
normalizeResolutionFlag,
|
|
354
647
|
parseCompositionVariables,
|
|
648
|
+
parseNumeric,
|
|
649
|
+
parseStartExpression,
|
|
650
|
+
readClipTiming,
|
|
355
651
|
resolveAliasDisplayName,
|
|
356
|
-
|
|
652
|
+
resolveResolutionFlagPair,
|
|
653
|
+
scanVariableUsage,
|
|
654
|
+
writeClipTiming
|
|
357
655
|
};
|
|
358
656
|
//# sourceMappingURL=composition.js.map
|