-
Notifications
You must be signed in to change notification settings - Fork 9
Expand file tree
/
Copy pathsource.ts
More file actions
71 lines (63 loc) · 2 KB
/
Copy pathsource.ts
File metadata and controls
71 lines (63 loc) · 2 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
/**
* Resolve a `<posecode-player>`'s movement source from its three input modes,
* in precedence order:
*
* 1. `doc="<token>"`: a posecode-share token (how permalinks travel)
* 2. `src="<url>"`: fetch a `.posecode` file
* 3. inline text: the element's own text content
*
* DOM-free: the element passes a plain descriptor, so this is unit-testable in
* node. Never throws: every failure comes back as `{ ok: false, error }` so
* the element can render a friendly message instead of a blank canvas.
*/
import { decodePosecode, MAX_SOURCE_LENGTH } from "posecode-share";
export interface SourceInput {
doc?: string | null;
src?: string | null;
/** The element's inline text content. */
text?: string | null;
}
export type Resolved =
| { ok: true; source: string }
| { ok: false; error: string };
export async function resolveSource(
input: SourceInput,
fetchImpl: typeof fetch = globalThis.fetch,
): Promise<Resolved> {
const doc = input.doc?.trim();
if (doc) {
try {
return { ok: true, source: decodePosecode(doc) };
} catch {
return { ok: false, error: "Could not decode the movement token." };
}
}
const src = input.src?.trim();
if (src) {
if (!fetchImpl) {
return { ok: false, error: "No fetch available to load the src URL." };
}
try {
const res = await fetchImpl(src);
if (!res.ok) {
return { ok: false, error: `Could not load ${src} (HTTP ${res.status}).` };
}
const source = await res.text();
return validateLength(source);
} catch {
return { ok: false, error: `Could not fetch ${src}.` };
}
}
const inline = input.text?.trim();
if (inline) return validateLength(inline);
return {
ok: false,
error: "No movement to render: set a doc token, a src URL, or inline text.",
};
}
function validateLength(source: string): Resolved {
if (source.length > MAX_SOURCE_LENGTH) {
return { ok: false, error: "Movement source is too large to render." };
}
return { ok: true, source };
}