@hyperframes/parsers 0.7.60 → 0.7.61
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 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/compositionContract.ts"],"sourcesContent":["/**\n * Browser-safe authored composition contract.\n *\n * Source HTML is authored with data-start + data-duration + data-track-index.\n * data-end is compiler-derived and data-layer is legacy input only. Readers\n * accept legacy documents; writers always emit the canonical representation.\n */\n\nexport const COMPOSITION_CONTRACT_VERSION = 1 as const;\n\nexport const COMPOSITION_ATTRIBUTES = Object.freeze({\n start: \"data-start\",\n duration: \"data-duration\",\n trackIndex: \"data-track-index\",\n derivedEnd: \"data-end\",\n legacyTrack: \"data-layer\",\n} as const);\n\nexport const CANONICAL_AUTHORED_TIMING_ATTRIBUTES = Object.freeze([\n COMPOSITION_ATTRIBUTES.start,\n COMPOSITION_ATTRIBUTES.duration,\n COMPOSITION_ATTRIBUTES.trackIndex,\n] as const);\n\nexport const DERIVED_TIMING_ATTRIBUTES = Object.freeze([\n COMPOSITION_ATTRIBUTES.derivedEnd,\n] as const);\n\nexport const LEGACY_TIMING_ATTRIBUTES = Object.freeze([\n COMPOSITION_ATTRIBUTES.derivedEnd,\n COMPOSITION_ATTRIBUTES.legacyTrack,\n] as const);\n\nexport type ReferenceExpression =\n | { kind: \"absolute\"; value: number }\n | { kind: \"reference\"; refId: string; offset: number };\n\nexport type ClipTimingDiagnosticCode =\n | \"invalid-start\"\n | \"unresolved-start-reference\"\n | \"invalid-duration\"\n | \"invalid-end\"\n | \"end-before-start\"\n | \"deprecated-end\"\n | \"conflicting-end\"\n | \"invalid-track-index\"\n | \"deprecated-layer\"\n | \"conflicting-layer\";\n\nexport interface ClipTimingDiagnostic {\n code: ClipTimingDiagnosticCode;\n attribute: string;\n value: string | null;\n}\n\nexport interface ClipAttributeReader {\n getAttribute(name: string): string | null;\n}\n\nexport interface ClipAttributeWriter extends ClipAttributeReader {\n setAttribute(name: string, value: string): void;\n removeAttribute(name: string): void;\n}\n\nexport interface ReadClipTimingOptions {\n /** Resolve a reference to the referenced clip's absolute end time. */\n resolveReferenceEnd?: (refId: string) => number | null | undefined;\n /** Start used when data-start is absent. Defaults to zero. */\n defaultStart?: number | null;\n}\n\nexport interface ClipTiming {\n startExpression: ReferenceExpression | null;\n start: number | null;\n duration: number | null;\n end: number | null;\n trackIndex: number;\n durationSource: \"duration\" | \"legacy-end\" | \"missing\" | \"invalid\";\n trackSource: \"track-index\" | \"legacy-layer\" | \"default\" | \"invalid\";\n diagnostics: ClipTimingDiagnostic[];\n}\n\nexport interface ClipTimingUpdate {\n start?: number | string | ReferenceExpression;\n duration?: number | null;\n trackIndex?: number | null;\n}\n\nexport class ClipTimingWriteError extends Error {\n readonly code: \"invalid-start\" | \"invalid-duration\" | \"invalid-track-index\";\n\n constructor(code: ClipTimingWriteError[\"code\"], message: string) {\n super(message);\n this.name = \"ClipTimingWriteError\";\n this.code = code;\n }\n}\n\n/** Parse a value to a finite number, or null if it is absent/invalid. */\nexport function parseNumeric(value: string | null | undefined): number | null {\n if (value == null || value.trim() === \"\") return null;\n const parsed = Number(value);\n return Number.isFinite(parsed) ? parsed : null;\n}\n\nconst REFERENCE_ID_PATTERN = /^[A-Za-z0-9_.:-]+$/;\n\nfunction isAsciiDigitAt(value: string, index: number): boolean {\n const code = value.charCodeAt(index);\n return code >= 48 && code <= 57;\n}\n\nfunction skipDigitsLeft(value: string, start: number): number {\n let cursor = start;\n while (cursor >= 0 && isAsciiDigitAt(value, cursor)) cursor--;\n return cursor;\n}\n\nfunction skipWhitespaceLeft(value: string, start: number): number {\n let cursor = start;\n while (cursor >= 0 && (value[cursor] ?? \"\").trim() === \"\") cursor--;\n return cursor;\n}\n\nfunction findMagnitudeStart(value: string): number | null {\n const last = value.length - 1;\n if (!isAsciiDigitAt(value, last)) return null;\n let cursor = skipDigitsLeft(value, last);\n if (value[cursor] === \".\") cursor = skipDigitsLeft(value, cursor - 1);\n return cursor + 1;\n}\n\nfunction parseReferenceOffset(\n value: string,\n): { refId: string; operator: \"+\" | \"-\"; magnitude: number } | null {\n const magnitudeStart = findMagnitudeStart(value);\n if (magnitudeStart == null) return null;\n const operatorIndex = skipWhitespaceLeft(value, magnitudeStart - 1);\n const operator = value[operatorIndex];\n if (operator !== \"+\" && operator !== \"-\") return null;\n\n const refId = value.slice(0, operatorIndex).trim();\n if (!REFERENCE_ID_PATTERN.test(refId)) return null;\n const magnitude = Number(value.slice(magnitudeStart));\n if (!Number.isFinite(magnitude)) return null;\n return { refId, operator, magnitude };\n}\n\n/**\n * Parse the data-start grammar: absolute seconds, `clip-id`, or\n * `clip-id +/- offset`, where references resolve to the referenced clip's end.\n */\nexport function parseStartExpression(raw: string | null | undefined): ReferenceExpression | null {\n const normalized = (raw ?? \"\").trim();\n if (!normalized) return null;\n const absolute = parseNumeric(normalized);\n if (absolute != null) return { kind: \"absolute\", value: absolute };\n if (REFERENCE_ID_PATTERN.test(normalized)) {\n return { kind: \"reference\", refId: normalized, offset: 0 };\n }\n const reference = parseReferenceOffset(normalized);\n if (!reference) return null;\n return {\n kind: \"reference\",\n refId: reference.refId,\n offset: reference.operator === \"-\" ? -reference.magnitude : reference.magnitude,\n };\n}\n\nfunction pushDiagnostic(\n diagnostics: ClipTimingDiagnostic[],\n code: ClipTimingDiagnosticCode,\n attribute: string,\n value: string | null,\n): void {\n diagnostics.push({ code, attribute, value });\n}\n\nfunction resolveStart(\n expression: ReferenceExpression | null,\n rawStart: string | null,\n options: ReadClipTimingOptions,\n diagnostics: ClipTimingDiagnostic[],\n): number | null {\n if (rawStart == null || rawStart.trim() === \"\") {\n return options.defaultStart === undefined ? 0 : options.defaultStart;\n }\n if (!expression) {\n pushDiagnostic(diagnostics, \"invalid-start\", COMPOSITION_ATTRIBUTES.start, rawStart);\n return null;\n }\n if (expression.kind === \"absolute\") return Math.max(0, expression.value);\n const referencedEnd = options.resolveReferenceEnd?.(expression.refId);\n if (referencedEnd == null || !Number.isFinite(referencedEnd)) {\n pushDiagnostic(\n diagnostics,\n \"unresolved-start-reference\",\n COMPOSITION_ATTRIBUTES.start,\n rawStart,\n );\n return null;\n }\n return Math.max(0, referencedEnd + expression.offset);\n}\n\ntype DurationRead = Pick<ClipTiming, \"duration\" | \"end\" | \"durationSource\">;\ntype TrackRead = Pick<ClipTiming, \"trackIndex\" | \"trackSource\">;\n\nfunction diagnoseDerivedEnd(\n rawEnd: string,\n canonicalEnd: number | null,\n diagnostics: ClipTimingDiagnostic[],\n): void {\n pushDiagnostic(diagnostics, \"deprecated-end\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n const parsedEnd = parseNumeric(rawEnd);\n if (parsedEnd == null) {\n pushDiagnostic(diagnostics, \"invalid-end\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n } else if (canonicalEnd != null && parsedEnd !== canonicalEnd) {\n pushDiagnostic(diagnostics, \"conflicting-end\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n }\n}\n\nfunction readCanonicalDuration(\n rawDuration: string,\n start: number | null,\n diagnostics: ClipTimingDiagnostic[],\n): DurationRead {\n const duration = parseNumeric(rawDuration);\n if (duration == null || duration < 0) {\n pushDiagnostic(diagnostics, \"invalid-duration\", COMPOSITION_ATTRIBUTES.duration, rawDuration);\n return { duration: null, end: null, durationSource: \"invalid\" };\n }\n return {\n duration,\n end: start == null ? null : start + duration,\n durationSource: \"duration\",\n };\n}\n\nfunction readLegacyEnd(\n rawEnd: string,\n start: number | null,\n diagnostics: ClipTimingDiagnostic[],\n): DurationRead {\n pushDiagnostic(diagnostics, \"deprecated-end\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n const end = parseNumeric(rawEnd);\n if (end == null) {\n pushDiagnostic(diagnostics, \"invalid-end\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n return { duration: null, end: null, durationSource: \"invalid\" };\n }\n if (start == null) return { duration: null, end, durationSource: \"legacy-end\" };\n if (end < start) {\n pushDiagnostic(diagnostics, \"end-before-start\", COMPOSITION_ATTRIBUTES.derivedEnd, rawEnd);\n return { duration: null, end: null, durationSource: \"invalid\" };\n }\n return { duration: end - start, end, durationSource: \"legacy-end\" };\n}\n\nfunction readDuration(\n attributes: ClipAttributeReader,\n start: number | null,\n diagnostics: ClipTimingDiagnostic[],\n): DurationRead {\n const rawDuration = attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration);\n const rawEnd = attributes.getAttribute(COMPOSITION_ATTRIBUTES.derivedEnd);\n if (rawDuration == null) {\n return rawEnd == null\n ? { duration: null, end: null, durationSource: \"missing\" }\n : readLegacyEnd(rawEnd, start, diagnostics);\n }\n const canonical = readCanonicalDuration(rawDuration, start, diagnostics);\n if (rawEnd != null) diagnoseDerivedEnd(rawEnd, canonical.end, diagnostics);\n return canonical;\n}\n\nfunction readTrackValue(\n rawValue: string,\n attribute: string,\n source: \"track-index\" | \"legacy-layer\",\n diagnostics: ClipTimingDiagnostic[],\n): TrackRead {\n const trackIndex = parseNumeric(rawValue);\n if (trackIndex == null || !Number.isInteger(trackIndex)) {\n pushDiagnostic(diagnostics, \"invalid-track-index\", attribute, rawValue);\n return { trackIndex: 0, trackSource: \"invalid\" };\n }\n return { trackIndex, trackSource: source };\n}\n\nfunction readTrack(\n attributes: ClipAttributeReader,\n diagnostics: ClipTimingDiagnostic[],\n): TrackRead {\n const rawTrack = attributes.getAttribute(COMPOSITION_ATTRIBUTES.trackIndex);\n const rawLayer = attributes.getAttribute(COMPOSITION_ATTRIBUTES.legacyTrack);\n if (rawTrack == null && rawLayer == null) return { trackIndex: 0, trackSource: \"default\" };\n if (rawTrack == null && rawLayer != null) {\n pushDiagnostic(diagnostics, \"deprecated-layer\", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);\n return readTrackValue(\n rawLayer,\n COMPOSITION_ATTRIBUTES.legacyTrack,\n \"legacy-layer\",\n diagnostics,\n );\n }\n const canonical = readTrackValue(\n rawTrack ?? \"\",\n COMPOSITION_ATTRIBUTES.trackIndex,\n \"track-index\",\n diagnostics,\n );\n if (rawLayer == null) return canonical;\n pushDiagnostic(diagnostics, \"deprecated-layer\", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);\n const parsedLayer = parseNumeric(rawLayer);\n if (parsedLayer != null && parsedLayer !== canonical.trackIndex) {\n pushDiagnostic(diagnostics, \"conflicting-layer\", COMPOSITION_ATTRIBUTES.legacyTrack, rawLayer);\n }\n return canonical;\n}\n\n/** Read canonical timing, accepting legacy attributes without preferring them. */\nexport function readClipTiming(\n attributes: ClipAttributeReader,\n options: ReadClipTimingOptions = {},\n): ClipTiming {\n const diagnostics: ClipTimingDiagnostic[] = [];\n const rawStart = attributes.getAttribute(COMPOSITION_ATTRIBUTES.start);\n const startExpression = parseStartExpression(rawStart);\n const start = resolveStart(startExpression, rawStart, options, diagnostics);\n const duration = readDuration(attributes, start, diagnostics);\n const track = readTrack(attributes, diagnostics);\n return { startExpression, start, ...duration, ...track, diagnostics };\n}\n\nfunction serializeStartNumber(start: number): string {\n if (!Number.isFinite(start)) {\n throw new ClipTimingWriteError(\"invalid-start\", \"start must be finite\");\n }\n return String(start);\n}\n\nfunction serializeStartReference(start: ReferenceExpression): string {\n if (start.kind === \"absolute\") return serializeStartNumber(start.value);\n if (!start.refId || !Number.isFinite(start.offset)) {\n throw new ClipTimingWriteError(\n \"invalid-start\",\n \"reference start must have an id and finite offset\",\n );\n }\n if (start.offset === 0) return start.refId;\n return `${start.refId} ${start.offset < 0 ? \"-\" : \"+\"} ${Math.abs(start.offset)}`;\n}\n\nfunction serializeStart(start: ClipTimingUpdate[\"start\"]): string {\n if (typeof start === \"number\") return serializeStartNumber(start);\n if (typeof start === \"object\" && start != null) return serializeStartReference(start);\n if (typeof start === \"string\" && parseStartExpression(start)) return start.trim();\n throw new ClipTimingWriteError(\"invalid-start\", `invalid start expression: ${start ?? \"\"}`);\n}\n\nfunction writeDuration(\n attributes: ClipAttributeWriter,\n duration: number | null | undefined,\n current: ClipTiming,\n): void {\n if (duration === null) {\n attributes.removeAttribute(COMPOSITION_ATTRIBUTES.duration);\n return;\n }\n if (duration === undefined) {\n if (\n attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration) == null &&\n current.duration != null\n ) {\n attributes.setAttribute(COMPOSITION_ATTRIBUTES.duration, String(current.duration));\n }\n return;\n }\n if (!Number.isFinite(duration) || duration < 0) {\n throw new ClipTimingWriteError(\n \"invalid-duration\",\n \"duration must be a finite, non-negative number\",\n );\n }\n attributes.setAttribute(COMPOSITION_ATTRIBUTES.duration, String(duration));\n}\n\nfunction writeTrack(\n attributes: ClipAttributeWriter,\n trackIndex: number | null | undefined,\n current: ClipTiming,\n): void {\n if (trackIndex === null) {\n attributes.removeAttribute(COMPOSITION_ATTRIBUTES.trackIndex);\n return;\n }\n if (trackIndex === undefined) {\n if (\n attributes.getAttribute(COMPOSITION_ATTRIBUTES.trackIndex) == null &&\n current.trackSource === \"legacy-layer\"\n ) {\n attributes.setAttribute(COMPOSITION_ATTRIBUTES.trackIndex, String(current.trackIndex));\n }\n return;\n }\n if (!Number.isFinite(trackIndex) || !Number.isInteger(trackIndex)) {\n throw new ClipTimingWriteError(\"invalid-track-index\", \"trackIndex must be a finite integer\");\n }\n attributes.setAttribute(COMPOSITION_ATTRIBUTES.trackIndex, String(trackIndex));\n}\n\n/** Write only canonical authored timing and remove derived/legacy source attributes. */\nexport function writeClipTiming(\n attributes: ClipAttributeWriter,\n update: ClipTimingUpdate,\n): ClipTiming {\n const current = readClipTiming(attributes);\n if (update.start !== undefined) {\n attributes.setAttribute(COMPOSITION_ATTRIBUTES.start, serializeStart(update.start));\n }\n writeDuration(attributes, update.duration, current);\n writeTrack(attributes, update.trackIndex, current);\n // A legacy end paired with an unresolved reference start cannot be converted\n // to data-duration without a reference resolver. On a duration-omitting edit\n // (for example, moving only the track), preserve that sole duration source\n // instead of canonicalizing it into data loss.\n const preserveUnresolvedLegacyEnd =\n update.duration === undefined &&\n attributes.getAttribute(COMPOSITION_ATTRIBUTES.duration) == null &&\n attributes.getAttribute(COMPOSITION_ATTRIBUTES.derivedEnd) != null &&\n current.duration == null;\n if (!preserveUnresolvedLegacyEnd) {\n attributes.removeAttribute(COMPOSITION_ATTRIBUTES.derivedEnd);\n }\n attributes.removeAttribute(COMPOSITION_ATTRIBUTES.legacyTrack);\n return readClipTiming(attributes);\n}\n"],"mappings":"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","names":[]}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared FFmpeg/FFprobe binary resolution for every package that shells out
|
|
3
|
+
* to them (engine, cli, lint, studio-server). Node-only: import via the
|
|
4
|
+
* `@hyperframes/parsers/ff-binaries` subpath, never from a browser bundle.
|
|
5
|
+
*/
|
|
6
|
+
declare const FFMPEG_PATH_ENV = "HYPERFRAMES_FFMPEG_PATH";
|
|
7
|
+
declare const FFPROBE_PATH_ENV = "HYPERFRAMES_FFPROBE_PATH";
|
|
8
|
+
type FfBinaryName = "ffmpeg" | "ffprobe";
|
|
9
|
+
interface FindFfBinaryOptions {
|
|
10
|
+
/**
|
|
11
|
+
* How to treat an env override that points at a missing file: `true`
|
|
12
|
+
* reports the binary as not found (callers that surface an install hint or
|
|
13
|
+
* skip probing), `false`/unset returns the configured path as-is (callers
|
|
14
|
+
* that validate the override separately and want spawn errors to name the
|
|
15
|
+
* path the user configured).
|
|
16
|
+
*/
|
|
17
|
+
configuredMustExist?: boolean;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Resolve an FFmpeg-family binary: env override first, then `which`/`where`,
|
|
21
|
+
* then a manual PATH scan (covers Windows PATHEXT), a project-local
|
|
22
|
+
* `.hyperframes/bin`, then well-known Unix install dirs. System lookups are
|
|
23
|
+
* cached per binary for the process lifetime; the env override is re-read on
|
|
24
|
+
* every call.
|
|
25
|
+
*/
|
|
26
|
+
declare function findFfBinary(name: FfBinaryName, options?: FindFfBinaryOptions): string | undefined;
|
|
27
|
+
/** Test hook: drop cached system lookups so resolution can be re-exercised. */
|
|
28
|
+
declare function clearFfBinaryLookupCache(): void;
|
|
29
|
+
|
|
30
|
+
export { FFMPEG_PATH_ENV, FFPROBE_PATH_ENV, type FfBinaryName, type FindFfBinaryOptions, clearFfBinaryLookupCache, findFfBinary };
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
// src/ffBinaries.ts
|
|
2
|
+
import { execFileSync } from "child_process";
|
|
3
|
+
import { accessSync, constants, existsSync } from "fs";
|
|
4
|
+
import { delimiter, join, resolve } from "path";
|
|
5
|
+
var FFMPEG_PATH_ENV = "HYPERFRAMES_FFMPEG_PATH";
|
|
6
|
+
var FFPROBE_PATH_ENV = "HYPERFRAMES_FFPROBE_PATH";
|
|
7
|
+
var ENV_BY_NAME = {
|
|
8
|
+
ffmpeg: FFMPEG_PATH_ENV,
|
|
9
|
+
ffprobe: FFPROBE_PATH_ENV
|
|
10
|
+
};
|
|
11
|
+
var pathLookupCache = /* @__PURE__ */ new Map();
|
|
12
|
+
function candidateFileName(candidate) {
|
|
13
|
+
return candidate.split(/[\\/]/).at(-1)?.toLowerCase() ?? candidate.toLowerCase();
|
|
14
|
+
}
|
|
15
|
+
function chooseBestPathCandidate(name, candidates) {
|
|
16
|
+
const normalized = candidates.map((candidate) => candidate.trim()).filter(Boolean);
|
|
17
|
+
return normalized.find((candidate) => candidateFileName(candidate) === `${name}.exe`) ?? normalized.find((candidate) => candidateFileName(candidate) === name) ?? normalized.find((candidate) => !candidateFileName(candidate).match(/\.(cmd|bat)$/i)) ?? normalized[0];
|
|
18
|
+
}
|
|
19
|
+
function isExecutablePathCandidate(candidate) {
|
|
20
|
+
if (process.platform === "win32") return existsSync(candidate);
|
|
21
|
+
try {
|
|
22
|
+
accessSync(candidate, constants.X_OK);
|
|
23
|
+
return true;
|
|
24
|
+
} catch {
|
|
25
|
+
return false;
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function scanPath(name) {
|
|
29
|
+
const pathValue = process.env.PATH;
|
|
30
|
+
if (!pathValue) return void 0;
|
|
31
|
+
const extensions = process.platform === "win32" ? [
|
|
32
|
+
".exe",
|
|
33
|
+
...new Set(
|
|
34
|
+
(process.env.PATHEXT ?? ".COM;.EXE;.BAT;.CMD").split(";").map((ext) => ext.trim().toLowerCase()).filter(Boolean)
|
|
35
|
+
),
|
|
36
|
+
""
|
|
37
|
+
] : [""];
|
|
38
|
+
const candidates = [];
|
|
39
|
+
for (const dir of pathValue.split(delimiter)) {
|
|
40
|
+
if (!dir) continue;
|
|
41
|
+
for (const ext of extensions) {
|
|
42
|
+
const candidate = join(dir, `${name}${ext}`);
|
|
43
|
+
if (isExecutablePathCandidate(candidate)) candidates.push(candidate);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
return chooseBestPathCandidate(name, candidates);
|
|
47
|
+
}
|
|
48
|
+
var COMMON_BIN_DIRS = process.platform === "win32" ? [] : ["/opt/homebrew/bin", "/usr/local/bin", "/usr/bin", "/bin", "/snap/bin"];
|
|
49
|
+
function findInCommonDirs(name) {
|
|
50
|
+
for (const dir of COMMON_BIN_DIRS) {
|
|
51
|
+
const candidate = `${dir}/${name}`;
|
|
52
|
+
if (existsSync(candidate)) return candidate;
|
|
53
|
+
}
|
|
54
|
+
return void 0;
|
|
55
|
+
}
|
|
56
|
+
function findInProjectLocalBin(name) {
|
|
57
|
+
const extension = process.platform === "win32" ? ".exe" : "";
|
|
58
|
+
const candidate = resolve(".hyperframes", "bin", `${name}${extension}`);
|
|
59
|
+
return existsSync(candidate) ? candidate : void 0;
|
|
60
|
+
}
|
|
61
|
+
function lookupOnSystem(name) {
|
|
62
|
+
if (pathLookupCache.has(name)) return pathLookupCache.get(name);
|
|
63
|
+
let found;
|
|
64
|
+
try {
|
|
65
|
+
const command = process.platform === "win32" ? "where" : "which";
|
|
66
|
+
const output = execFileSync(command, [name], {
|
|
67
|
+
encoding: "utf-8",
|
|
68
|
+
stdio: ["pipe", "pipe", "pipe"],
|
|
69
|
+
timeout: 5e3
|
|
70
|
+
});
|
|
71
|
+
found = chooseBestPathCandidate(name, output.split(/\r?\n/));
|
|
72
|
+
} catch {
|
|
73
|
+
found = scanPath(name);
|
|
74
|
+
}
|
|
75
|
+
found ??= findInProjectLocalBin(name);
|
|
76
|
+
found ??= findInCommonDirs(name);
|
|
77
|
+
const resolved = found ? resolve(found) : void 0;
|
|
78
|
+
pathLookupCache.set(name, resolved);
|
|
79
|
+
return resolved;
|
|
80
|
+
}
|
|
81
|
+
function findFfBinary(name, options = {}) {
|
|
82
|
+
const configured = process.env[ENV_BY_NAME[name]]?.trim();
|
|
83
|
+
if (configured) {
|
|
84
|
+
if (options.configuredMustExist && !existsSync(configured)) return void 0;
|
|
85
|
+
return resolve(configured);
|
|
86
|
+
}
|
|
87
|
+
return lookupOnSystem(name);
|
|
88
|
+
}
|
|
89
|
+
function clearFfBinaryLookupCache() {
|
|
90
|
+
pathLookupCache.clear();
|
|
91
|
+
}
|
|
92
|
+
export {
|
|
93
|
+
FFMPEG_PATH_ENV,
|
|
94
|
+
FFPROBE_PATH_ENV,
|
|
95
|
+
clearFfBinaryLookupCache,
|
|
96
|
+
findFfBinary
|
|
97
|
+
};
|
|
98
|
+
//# sourceMappingURL=ffBinaries.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/ffBinaries.ts"],"sourcesContent":["import { execFileSync } from \"node:child_process\";\nimport { accessSync, constants, existsSync } from \"node:fs\";\nimport { delimiter, join, resolve } from \"node:path\";\n\n/**\n * Shared FFmpeg/FFprobe binary resolution for every package that shells out\n * to them (engine, cli, lint, studio-server). Node-only: import via the\n * `@hyperframes/parsers/ff-binaries` subpath, never from a browser bundle.\n */\n\nexport const FFMPEG_PATH_ENV = \"HYPERFRAMES_FFMPEG_PATH\";\nexport const FFPROBE_PATH_ENV = \"HYPERFRAMES_FFPROBE_PATH\";\n\nexport type FfBinaryName = \"ffmpeg\" | \"ffprobe\";\n\nconst ENV_BY_NAME: Record<FfBinaryName, string> = {\n ffmpeg: FFMPEG_PATH_ENV,\n ffprobe: FFPROBE_PATH_ENV,\n};\n\nconst pathLookupCache = new Map<FfBinaryName, string | undefined>();\n\nfunction candidateFileName(candidate: string): string {\n return candidate.split(/[\\\\/]/).at(-1)?.toLowerCase() ?? candidate.toLowerCase();\n}\n\nfunction chooseBestPathCandidate(\n name: FfBinaryName,\n candidates: readonly string[],\n): string | undefined {\n const normalized = candidates.map((candidate) => candidate.trim()).filter(Boolean);\n return (\n normalized.find((candidate) => candidateFileName(candidate) === `${name}.exe`) ??\n normalized.find((candidate) => candidateFileName(candidate) === name) ??\n normalized.find((candidate) => !candidateFileName(candidate).match(/\\.(cmd|bat)$/i)) ??\n normalized[0]\n );\n}\n\nfunction isExecutablePathCandidate(candidate: string): boolean {\n if (process.platform === \"win32\") return existsSync(candidate);\n try {\n accessSync(candidate, constants.X_OK);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction scanPath(name: FfBinaryName): string | undefined {\n const pathValue = process.env.PATH;\n if (!pathValue) return undefined;\n\n const extensions =\n process.platform === \"win32\"\n ? [\n \".exe\",\n ...new Set(\n (process.env.PATHEXT ?? \".COM;.EXE;.BAT;.CMD\")\n .split(\";\")\n .map((ext) => ext.trim().toLowerCase())\n .filter(Boolean),\n ),\n \"\",\n ]\n : [\"\"];\n const candidates: string[] = [];\n for (const dir of pathValue.split(delimiter)) {\n if (!dir) continue;\n for (const ext of extensions) {\n const candidate = join(dir, `${name}${ext}`);\n if (isExecutablePathCandidate(candidate)) candidates.push(candidate);\n }\n }\n return chooseBestPathCandidate(name, candidates);\n}\n\n// GUI/Dock/launchd-spawned processes on macOS don't inherit the shell PATH, so\n// `which ffmpeg` fails even when ffmpeg is installed via Homebrew. Probe the\n// well-known install dirs as a last resort. (No-op on Windows, where `where`\n// and installer-added PATH entries cover it.)\nconst COMMON_BIN_DIRS =\n process.platform === \"win32\"\n ? []\n : [\"/opt/homebrew/bin\", \"/usr/local/bin\", \"/usr/bin\", \"/bin\", \"/snap/bin\"];\n\nfunction findInCommonDirs(name: FfBinaryName): string | undefined {\n for (const dir of COMMON_BIN_DIRS) {\n const candidate = `${dir}/${name}`;\n if (existsSync(candidate)) return candidate;\n }\n return undefined;\n}\n\nfunction findInProjectLocalBin(name: FfBinaryName): string | undefined {\n const extension = process.platform === \"win32\" ? \".exe\" : \"\";\n const candidate = resolve(\".hyperframes\", \"bin\", `${name}${extension}`);\n return existsSync(candidate) ? candidate : undefined;\n}\n\nfunction lookupOnSystem(name: FfBinaryName): string | undefined {\n if (pathLookupCache.has(name)) return pathLookupCache.get(name);\n let found: string | undefined;\n try {\n const command = process.platform === \"win32\" ? \"where\" : \"which\";\n const output = execFileSync(command, [name], {\n encoding: \"utf-8\",\n stdio: [\"pipe\", \"pipe\", \"pipe\"],\n timeout: 5000,\n });\n found = chooseBestPathCandidate(name, output.split(/\\r?\\n/));\n } catch {\n found = scanPath(name);\n }\n found ??= findInProjectLocalBin(name);\n found ??= findInCommonDirs(name);\n const resolved = found ? resolve(found) : undefined;\n pathLookupCache.set(name, resolved);\n return resolved;\n}\n\nexport interface FindFfBinaryOptions {\n /**\n * How to treat an env override that points at a missing file: `true`\n * reports the binary as not found (callers that surface an install hint or\n * skip probing), `false`/unset returns the configured path as-is (callers\n * that validate the override separately and want spawn errors to name the\n * path the user configured).\n */\n configuredMustExist?: boolean;\n}\n\n/**\n * Resolve an FFmpeg-family binary: env override first, then `which`/`where`,\n * then a manual PATH scan (covers Windows PATHEXT), a project-local\n * `.hyperframes/bin`, then well-known Unix install dirs. System lookups are\n * cached per binary for the process lifetime; the env override is re-read on\n * every call.\n */\nexport function findFfBinary(\n name: FfBinaryName,\n options: FindFfBinaryOptions = {},\n): string | undefined {\n const configured = process.env[ENV_BY_NAME[name]]?.trim();\n if (configured) {\n if (options.configuredMustExist && !existsSync(configured)) return undefined;\n return resolve(configured);\n }\n return lookupOnSystem(name);\n}\n\n/** Test hook: drop cached system lookups so resolution can be re-exercised. */\nexport function clearFfBinaryLookupCache(): void {\n pathLookupCache.clear();\n}\n"],"mappings":"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","names":[]}
|
package/dist/gsapParser.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { G as GsapAnimation, P as ParsedGsap, A as ArcPathConfig, a as ArcPathSegment } from './gsapSerialize-
|
|
2
|
-
export { m as GsapKeyframeFormat, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-
|
|
1
|
+
import { G as GsapAnimation, P as ParsedGsap, A as ArcPathConfig, a as ArcPathSegment } from './gsapSerialize-cLD37cjI.js';
|
|
2
|
+
export { m as GsapKeyframeFormat, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-cLD37cjI.js';
|
|
3
3
|
export { PROPERTY_GROUPS, PropertyGroupName, SUPPORTED_EASES, SUPPORTED_PROPS, classifyPropertyGroup, classifyTweenPropertyGroup } from './gsapConstants.js';
|
|
4
4
|
export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
|
|
5
|
-
import './types-
|
|
5
|
+
import './types-ewozML_N.js';
|
|
6
6
|
|
|
7
7
|
declare function parseGsapScript(script: string): ParsedGsap;
|
|
8
8
|
declare function updateAnimationInScript(script: string, animationId: string, updates: Partial<GsapAnimation> & {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { P as ParsedGsap, c as GsapMethod, G as GsapAnimation } from './gsapSerialize-
|
|
2
|
-
export { A as ArcPathConfig, a as ArcPathSegment, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, M as MotionPathShape, l as buildArcPath, h as editabilityForProvenance } from './gsapSerialize-
|
|
3
|
-
import './types-
|
|
1
|
+
import { P as ParsedGsap, c as GsapMethod, G as GsapAnimation } from './gsapSerialize-cLD37cjI.js';
|
|
2
|
+
export { A as ArcPathConfig, a as ArcPathSegment, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, M as MotionPathShape, l as buildArcPath, h as editabilityForProvenance } from './gsapSerialize-cLD37cjI.js';
|
|
3
|
+
import './types-ewozML_N.js';
|
|
4
4
|
import './gsapConstants.js';
|
|
5
5
|
|
|
6
6
|
interface TweenCallInfo {
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { A as ArcPathConfig, a as ArcPathSegment, G as GsapAnimation, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, P as ParsedGsap, S as SplitAnimationsOptions, g as SplitAnimationsResult, h as editabilityForProvenance, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-
|
|
1
|
+
export { A as ArcPathConfig, a as ArcPathSegment, G as GsapAnimation, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, P as ParsedGsap, S as SplitAnimationsOptions, g as SplitAnimationsResult, h as editabilityForProvenance, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-cLD37cjI.js';
|
|
2
2
|
export { isStudioHoldSet } from './gsapParser.js';
|
|
3
3
|
export { PROPERTY_GROUPS, PropertyGroupName, SUPPORTED_EASES, SUPPORTED_PROPS, classifyPropertyGroup, classifyTweenPropertyGroup } from './gsapConstants.js';
|
|
4
4
|
export { SPRING_PRESETS, SpringPreset, generateSpringEaseData } from './springEase.js';
|
|
5
5
|
export { parseGsapScriptAcorn as parseGsapScript } from './gsapParserAcorn.js';
|
|
6
|
-
import './types-
|
|
6
|
+
import './types-ewozML_N.js';
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { G as GsapAnimation, A as ArcPathConfig, S as SplitAnimationsOptions, g as SplitAnimationsResult, a as ArcPathSegment } from './gsapSerialize-
|
|
2
|
-
import './types-
|
|
1
|
+
import { G as GsapAnimation, A as ArcPathConfig, S as SplitAnimationsOptions, g as SplitAnimationsResult, a as ArcPathSegment } from './gsapSerialize-cLD37cjI.js';
|
|
2
|
+
import './types-ewozML_N.js';
|
|
3
3
|
import './gsapConstants.js';
|
|
4
4
|
|
|
5
5
|
declare function updateAnimationInScript(script: string, animationId: string, updates: Partial<GsapAnimation> & {
|
package/dist/index.d.ts
CHANGED
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { C as CompositionVariable, T as TimelineElement, a as CanvasResolution, K as Keyframe, S as StageZoomKeyframe, V as ValidationResult } from './types-
|
|
2
|
-
export { A as AddElementData, b as Asset, B as BooleanVariable, c as CANVAS_DIMENSIONS, d as COMPOSITION_VARIABLE_TYPES, 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, l as KeyframeProperties, M as MediaElementType, m as MediaFile, N as NumberVariable, P as PlayerAPI, n as StageZoom, o as StringVariable, p as TIMELINE_COLORS, q as TimelineCompositionElement, r as TimelineElementBase, s as TimelineElementType, t as TimelineMediaElement, u as TimelineTextElement, v as VALID_CANVAS_RESOLUTIONS, W as WaveformData, w as getDefaultStageZoom, x as
|
|
3
|
-
export { A as ArcPathConfig, a as ArcPathSegment, G as GsapAnimation, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, P as ParsedGsap, S as SplitAnimationsOptions, g as SplitAnimationsResult, h as editabilityForProvenance, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-
|
|
1
|
+
import { C as CompositionVariable, T as TimelineElement, a as CanvasResolution, K as Keyframe, S as StageZoomKeyframe, V as ValidationResult } 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, 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, l as KeyframeProperties, M as MediaElementType, m as MediaFile, N as NumberVariable, P as PlayerAPI, R as ResolvedResolutionFlag, n as StageZoom, o as StringVariable, p as TIMELINE_COLORS, q as TimelineCompositionElement, r as TimelineElementBase, s as TimelineElementType, t as TimelineMediaElement, u as TimelineTextElement, v as VALID_CANVAS_RESOLUTIONS, 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 { A as ArcPathConfig, a as ArcPathSegment, G as GsapAnimation, b as GsapKeyframesData, c as GsapMethod, d as GsapPercentageKeyframe, e as GsapProvenance, f as GsapProvenanceKind, K as KeyframeEditability, P as ParsedGsap, S as SplitAnimationsOptions, g as SplitAnimationsResult, h as editabilityForProvenance, i as getAnimationsForElementId, j as gsapAnimationsToKeyframes, k as keyframesToGsapAnimations, s as serializeGsapAnimations, v as validateCompositionGsap } from './gsapSerialize-cLD37cjI.js';
|
|
4
4
|
export { isStudioHoldSet } from './gsapParser.js';
|
|
5
5
|
export { PROPERTY_GROUPS, PropertyGroupName, SUPPORTED_EASES, SUPPORTED_PROPS, classifyPropertyGroup, classifyTweenPropertyGroup } from './gsapConstants.js';
|
|
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, isCompositionTemplate, mintHfId, walkCompositionDescendants } from './hfIds.js';
|
|
9
9
|
export { ParsableDocumentLike, SubCompositionValidity, SubCompositionValidityReason, checkSubCompositionUsability } from './subCompositionValidity.js';
|
|
10
|
+
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';
|
|
10
11
|
export { CANONICAL_FONT_DISPLAY_NAMES, FONT_ALIAS_KEYS, FONT_ALIAS_MAP, VariableUsageScan, decodeUrlPathVariants, parseCompositionVariables, resolveAliasDisplayName, scanVariableUsage } from './composition.js';
|
|
11
12
|
|
|
12
13
|
/**
|
|
@@ -88,6 +89,22 @@ interface OutputResolutionCompatibility {
|
|
|
88
89
|
*/
|
|
89
90
|
suggestedResolution?: CanvasResolution;
|
|
90
91
|
}
|
|
92
|
+
/**
|
|
93
|
+
* Find the preset that shares the composition's aspect ratio and resolution
|
|
94
|
+
* tier (HD vs 4K) as the user's chosen preset. E.g. a portrait composition
|
|
95
|
+
* with `--resolution landscape-4k` suggests `portrait-4k`, not `portrait`,
|
|
96
|
+
* preserving the user's intent to render at 4K while fixing the orientation.
|
|
97
|
+
*
|
|
98
|
+
* Returns `undefined` when no preset matches the composition's aspect ratio
|
|
99
|
+
* (e.g. a custom, non-preset composition aspect ratio) — in that case there
|
|
100
|
+
* is no unambiguous swap to suggest.
|
|
101
|
+
*
|
|
102
|
+
* Exported so that consumers with permission to auto-apply the swap (see the
|
|
103
|
+
* `--resolution 1080p` aspect-agnostic path in the CLI/producer) can share the
|
|
104
|
+
* same sibling-lookup logic as this module's user-facing "did you mean?" hint,
|
|
105
|
+
* without duplicating the tier-preserving fallback rules.
|
|
106
|
+
*/
|
|
107
|
+
declare function suggestMatchingPreset(compositionWidth: number, compositionHeight: number, chosen: CanvasResolution): CanvasResolution | undefined;
|
|
91
108
|
/**
|
|
92
109
|
* Check whether rendering a composition of the given dimensions with the given
|
|
93
110
|
* `outputResolution` preset (and alpha/HDR modes) is supported.
|
|
@@ -116,4 +133,4 @@ declare function unrollComputedTimeline(script: string): string;
|
|
|
116
133
|
|
|
117
134
|
declare function queryByAttr(root: ParentNode, attr: string, value: string, tag?: string): Element | null;
|
|
118
135
|
|
|
119
|
-
export { CanvasResolution, CompositionHtmlParseError, type CompositionMetadata, CompositionVariable, Keyframe, type OutputResolutionCompatibility, type OutputResolutionIssueKind, type ParsedHtml, StageZoomKeyframe, TimelineElement, ValidationResult, addElementToHtml, checkOutputResolutionCompatibility, extractCompositionMetadata, parseHtml, queryByAttr, removeElementFromHtml, unrollComputedTimeline, updateElementInHtml, validateCompositionHtml };
|
|
136
|
+
export { CanvasResolution, CompositionHtmlParseError, type CompositionMetadata, CompositionVariable, Keyframe, type OutputResolutionCompatibility, type OutputResolutionIssueKind, type ParsedHtml, StageZoomKeyframe, TimelineElement, ValidationResult, addElementToHtml, checkOutputResolutionCompatibility, extractCompositionMetadata, parseHtml, queryByAttr, removeElementFromHtml, suggestMatchingPreset, unrollComputedTimeline, updateElementInHtml, validateCompositionHtml };
|