@bendyline/squisq 2.12.0 → 2.12.2

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.
Files changed (41) hide show
  1. package/dist/{Doc-DIdmgDsV.d.ts → Doc-BJSPtsQD.d.ts} +27 -2
  2. package/dist/{ImageEditDoc-DXQMA6qH.d.ts → ImageEditDoc-QIzn1qK5.d.ts} +1 -1
  3. package/dist/{chunk-W45PAVYE.js → chunk-5VFC5T4N.js} +88 -1057
  4. package/dist/{chunk-RPPUCFRW.js → chunk-DTAYI7AV.js} +20 -20
  5. package/dist/{chunk-WAX4QYHA.js → chunk-E2NFHYCB.js} +14 -3
  6. package/dist/{chunk-H54A35NZ.js → chunk-EX75I5HX.js} +3 -3
  7. package/dist/{chunk-3H7SYCZS.js → chunk-FTN6SGW5.js} +1 -1
  8. package/dist/{chunk-QHNO67JS.js → chunk-GX3VSKYS.js} +1 -1
  9. package/dist/{chunk-I4L4GYDN.js → chunk-HYJ63N6V.js} +1 -1
  10. package/dist/{chunk-B3AFOXMA.js → chunk-MPEGJKFJ.js} +1031 -3
  11. package/dist/chunk-MWSGNEH6.js +2376 -0
  12. package/dist/{chunk-M6YXFNGO.js → chunk-P53Z4RYC.js} +10 -0
  13. package/dist/{chunk-K2PZMWQ5.js → chunk-TFMDVOUQ.js} +10 -9
  14. package/dist/chunk-Y25EJEZN.js +178 -0
  15. package/dist/{chunk-3Z2NGHLI.js → chunk-YZ66VMBB.js} +1 -1
  16. package/dist/{chunk-VTG7PNOL.js → chunk-ZKDJHO6Y.js} +3 -8
  17. package/dist/doc/index.d.ts +18 -10
  18. package/dist/doc/index.js +41 -39
  19. package/dist/fence/index.d.ts +1 -1
  20. package/dist/generate/index.d.ts +1 -1
  21. package/dist/imageEdit/index.d.ts +3 -3
  22. package/dist/index.d.ts +6 -6
  23. package/dist/index.js +68 -48
  24. package/dist/jsonForm/index.d.ts +1 -1
  25. package/dist/jsonForm/index.js +4 -4
  26. package/dist/markdown/index.d.ts +143 -1
  27. package/dist/markdown/index.js +29 -10
  28. package/dist/{materializePageSection-C33MgcDg.d.ts → materializePageSection-DYnmh8X1.d.ts} +1 -1
  29. package/dist/mediaEdit/index.d.ts +2 -2
  30. package/dist/narration/index.d.ts +1 -1
  31. package/dist/narration/index.js +8 -8
  32. package/dist/recommend/index.js +3 -2
  33. package/dist/schemas/index.d.ts +4 -4
  34. package/dist/schemas/index.js +3 -3
  35. package/dist/{themeLibrary-BaDfxgzt.d.ts → themeLibrary-IHAirzT-.d.ts} +1 -1
  36. package/dist/timing/index.d.ts +1 -1
  37. package/dist/transform/index.d.ts +2 -2
  38. package/dist/transform/index.js +8 -8
  39. package/package.json +1 -1
  40. package/dist/chunk-NNJA7ICB.js +0 -1088
  41. package/dist/chunk-ZYWYSM6W.js +0 -657
@@ -1,1088 +0,0 @@
1
- // src/markdown/mediaReference.ts
2
- var VIDEO_EXTENSIONS = /* @__PURE__ */ new Set(["mp4", "m4v", "mov", "webm", "ogv"]);
3
- var AUDIO_EXTENSIONS = /* @__PURE__ */ new Set(["mp3", "m4a", "aac", "wav", "ogg", "oga", "opus", "flac"]);
4
- var CONTAINER_EXTENSIONS = /* @__PURE__ */ new Set(["webm", "mp4"]);
5
- function mediaKindForUrl(url) {
6
- const path = url.split(/[?#]/, 1)[0] ?? "";
7
- const name = path.slice(path.lastIndexOf("/") + 1);
8
- const dot = name.lastIndexOf(".");
9
- if (dot <= 0) return null;
10
- const ext = name.slice(dot + 1).toLowerCase();
11
- if (AUDIO_EXTENSIONS.has(ext)) return "audio";
12
- if (CONTAINER_EXTENSIONS.has(ext) && /^(?:\.\/)?audio\//i.test(path)) return "audio";
13
- if (VIDEO_EXTENSIONS.has(ext)) return "video";
14
- return null;
15
- }
16
-
17
- // src/markdown/htmlParse.ts
18
- import { fromHtml } from "hast-util-from-html";
19
- var HAST_PROP_TO_ATTR = {
20
- className: "class",
21
- htmlFor: "for",
22
- httpEquiv: "http-equiv",
23
- acceptCharset: "accept-charset"
24
- };
25
- var VOID_ELEMENTS = /* @__PURE__ */ new Set([
26
- "area",
27
- "base",
28
- "br",
29
- "col",
30
- "embed",
31
- "hr",
32
- "img",
33
- "input",
34
- "link",
35
- "meta",
36
- "param",
37
- "source",
38
- "track",
39
- "wbr"
40
- ]);
41
- function propertyToAttribute(prop) {
42
- if (HAST_PROP_TO_ATTR[prop]) return HAST_PROP_TO_ATTR[prop];
43
- if (prop.length > 4 && prop.startsWith("data") && prop[4] >= "A" && prop[4] <= "Z") {
44
- return "data-" + prop.slice(4).replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()).replace(/^-/, "");
45
- }
46
- if (prop.length > 4 && prop.startsWith("aria") && prop[4] >= "A" && prop[4] <= "Z") {
47
- return "aria-" + prop.slice(4).replace(/[A-Z]/g, (m) => "-" + m.toLowerCase()).replace(/^-/, "");
48
- }
49
- return prop.toLowerCase();
50
- }
51
- function convertHastProperties(properties) {
52
- const attrs = {};
53
- for (const [key, value] of Object.entries(properties)) {
54
- if (value === false || value === void 0 || value === null) continue;
55
- const attrName = propertyToAttribute(key);
56
- if (value === true) {
57
- attrs[attrName] = "";
58
- } else if (Array.isArray(value)) {
59
- attrs[attrName] = value.join(" ");
60
- } else {
61
- attrs[attrName] = String(value);
62
- }
63
- }
64
- return attrs;
65
- }
66
- function hastChildrenToNodes(children) {
67
- const result = [];
68
- for (const child of children) {
69
- const node = hastNodeToHtmlNode(child);
70
- if (node) result.push(node);
71
- }
72
- return result;
73
- }
74
- function hastNodeToHtmlNode(node) {
75
- switch (node.type) {
76
- case "element": {
77
- const tagName = node.tagName;
78
- const properties = node.properties ?? {};
79
- const children = node.children ?? [];
80
- return {
81
- type: "htmlElement",
82
- tagName,
83
- attributes: convertHastProperties(properties),
84
- children: hastChildrenToNodes(children),
85
- selfClosing: VOID_ELEMENTS.has(tagName) && children.length === 0
86
- };
87
- }
88
- case "text":
89
- return {
90
- type: "htmlText",
91
- value: node.value
92
- };
93
- case "comment":
94
- return {
95
- type: "htmlComment",
96
- value: node.value
97
- };
98
- case "doctype":
99
- return null;
100
- default:
101
- return null;
102
- }
103
- }
104
- function parseHtmlToNodes(html) {
105
- if (!html || !html.trim()) return [];
106
- try {
107
- const tree = fromHtml(html, { fragment: true });
108
- return hastChildrenToNodes(tree.children);
109
- } catch {
110
- return [{ type: "htmlText", value: html }];
111
- }
112
- }
113
- function escapeHtmlAttr(value) {
114
- return value.replace(/&/g, "&amp;").replace(/"/g, "&quot;").replace(/</g, "&lt;").replace(/>/g, "&gt;");
115
- }
116
- function stringifyNode(node) {
117
- switch (node.type) {
118
- case "htmlElement": {
119
- const attrs = Object.entries(node.attributes).map(([k, v]) => v === "" ? k : `${k}="${escapeHtmlAttr(v)}"`).join(" ");
120
- const open = attrs ? `<${node.tagName} ${attrs}>` : `<${node.tagName}>`;
121
- if (node.selfClosing) return open;
122
- const inner = node.children.map(stringifyNode).join("");
123
- return `${open}${inner}</${node.tagName}>`;
124
- }
125
- case "htmlText":
126
- return node.value;
127
- case "htmlComment":
128
- return `<!--${node.value}-->`;
129
- }
130
- }
131
- function stringifyHtmlNodes(nodes) {
132
- return nodes.map(stringifyNode).join("");
133
- }
134
-
135
- // src/markdown/utils.ts
136
- function getChildren(node) {
137
- if ("children" in node && Array.isArray(node.children)) {
138
- return node.children;
139
- }
140
- return [];
141
- }
142
- function walkMarkdownTree(node, visitor, parent) {
143
- const skip = visitor(node, parent);
144
- if (skip === true) return;
145
- const children = getChildren(node);
146
- for (const child of children) {
147
- walkMarkdownTree(child, visitor, node);
148
- }
149
- }
150
- function findNodesByType(root, type) {
151
- const results = [];
152
- walkMarkdownTree(root, (node) => {
153
- if (node.type === type) {
154
- results.push(node);
155
- }
156
- });
157
- return results;
158
- }
159
- function extractPlainText(node) {
160
- if ("value" in node && typeof node.value === "string") {
161
- return node.value;
162
- }
163
- const children = getChildren(node);
164
- const separator = node.type === "list" || node.type === "listItem" || node.type === "table" ? "\n" : node.type === "tableRow" ? " " : "";
165
- return children.map(extractPlainText).join(separator);
166
- }
167
- function countNodes(node) {
168
- let count = 1;
169
- const children = getChildren(node);
170
- for (const child of children) {
171
- count += countNodes(child);
172
- }
173
- return count;
174
- }
175
- var YAML_TRUE = /* @__PURE__ */ new Set(["true", "True", "TRUE"]);
176
- var YAML_FALSE = /* @__PURE__ */ new Set(["false", "False", "FALSE"]);
177
- var YAML_NULL = /* @__PURE__ */ new Set(["null", "Null", "NULL", "~"]);
178
- var YAML_CANONICAL_NUMBER_RE = /^-?(?:0|[1-9][0-9]*)(?:\.[0-9]+)?(?:e[+-][0-9]+)?$/;
179
- function isCanonicalNumber(text) {
180
- return YAML_CANONICAL_NUMBER_RE.test(text) && String(Number(text)) === text;
181
- }
182
- function assignKey(map, key, value) {
183
- Object.defineProperty(map, key, {
184
- value,
185
- enumerable: true,
186
- configurable: true,
187
- writable: true
188
- });
189
- }
190
- function indentOf(line) {
191
- return line.length - line.trimStart().length;
192
- }
193
- function isSkippableLine(line) {
194
- const trimmed = line.trim();
195
- return trimmed === "" || trimmed.startsWith("#");
196
- }
197
- function nextSignificant(cur) {
198
- let j = cur.i;
199
- while (j < cur.lines.length && isSkippableLine(cur.lines[j])) j++;
200
- return j;
201
- }
202
- function isSequenceItem(content) {
203
- return content === "-" || content.startsWith("- ");
204
- }
205
- function readQuotedScalar(text) {
206
- const quote = text[0];
207
- if (quote === '"') {
208
- for (let i = 1; i < text.length; i++) {
209
- if (text[i] === "\\") {
210
- i++;
211
- continue;
212
- }
213
- if (text[i] !== '"') continue;
214
- const raw = text.slice(0, i + 1);
215
- try {
216
- return { value: JSON.parse(raw), rest: text.slice(i + 1) };
217
- } catch {
218
- return { value: raw.slice(1, -1), rest: text.slice(i + 1) };
219
- }
220
- }
221
- return null;
222
- }
223
- if (quote === "'") {
224
- let value = "";
225
- for (let i = 1; i < text.length; i++) {
226
- if (text[i] !== "'") {
227
- value += text[i];
228
- continue;
229
- }
230
- if (text[i + 1] === "'") {
231
- value += "'";
232
- i++;
233
- continue;
234
- }
235
- return { value, rest: text.slice(i + 1) };
236
- }
237
- return null;
238
- }
239
- return null;
240
- }
241
- function splitMappingKey(content) {
242
- if (content.startsWith("{") || content.startsWith("[")) return null;
243
- if (content.startsWith('"') || content.startsWith("'")) {
244
- const quoted = readQuotedScalar(content);
245
- if (!quoted) return null;
246
- const after = quoted.rest;
247
- if (after === ":" || after.startsWith(": ") || after.startsWith(": ")) {
248
- return { key: quoted.value, rest: after.slice(1).trim() };
249
- }
250
- return null;
251
- }
252
- for (let i = 0; i < content.length; i++) {
253
- if (content[i] !== ":") continue;
254
- const next = content[i + 1];
255
- if (next !== void 0 && next !== " " && next !== " ") continue;
256
- const key = content.slice(0, i).trim();
257
- if (!key) return null;
258
- return { key, rest: content.slice(i + 1).trim() };
259
- }
260
- const colon = content.indexOf(":");
261
- if (colon > 0 && content[colon + 1] !== "/") {
262
- const key = content.slice(0, colon).trim();
263
- if (key && !key.includes(" ")) return { key, rest: content.slice(colon + 1).trim() };
264
- }
265
- return null;
266
- }
267
- function foldBlockLines(lines) {
268
- const parts = [];
269
- let i = 0;
270
- while (i < lines.length) {
271
- const line = lines[i];
272
- if (line === "") {
273
- parts.push("\n");
274
- i++;
275
- continue;
276
- }
277
- if (/^\s/.test(line)) {
278
- parts.push((parts.length > 0 ? "\n" : "") + line);
279
- i++;
280
- continue;
281
- }
282
- parts.push(line);
283
- i++;
284
- while (i < lines.length && lines[i] !== "" && !/^\s/.test(lines[i])) {
285
- parts.push(` ${lines[i]}`);
286
- i++;
287
- }
288
- }
289
- return parts.join("");
290
- }
291
- function parseBlockScalar(cur, keyIndent, folded, chomp) {
292
- const blockLines = [];
293
- let j = cur.i;
294
- for (; j < cur.lines.length; j++) {
295
- const line = cur.lines[j];
296
- if (line.trim() === "") {
297
- blockLines.push("");
298
- continue;
299
- }
300
- if (indentOf(line) <= keyIndent) break;
301
- blockLines.push(line);
302
- }
303
- cur.i = j;
304
- if (chomp !== "+") {
305
- while (blockLines.length > 0 && blockLines[blockLines.length - 1] === "") blockLines.pop();
306
- }
307
- let commonIndent = Infinity;
308
- for (const line of blockLines) {
309
- if (line === "") continue;
310
- commonIndent = Math.min(commonIndent, indentOf(line));
311
- }
312
- if (!isFinite(commonIndent)) commonIndent = 0;
313
- const dedented = blockLines.map((line) => line === "" ? "" : line.slice(commonIndent));
314
- return folded ? foldBlockLines(dedented) : dedented.join("\n");
315
- }
316
- function scalarFromText(text) {
317
- if (text === "" || YAML_NULL.has(text)) return null;
318
- if (YAML_TRUE.has(text)) return true;
319
- if (YAML_FALSE.has(text)) return false;
320
- if (isCanonicalNumber(text)) return Number(text);
321
- return text;
322
- }
323
- function collectPlainContinuation(cur, keyIndent, first) {
324
- const parts = [first];
325
- while (cur.i < cur.lines.length) {
326
- const line = cur.lines[cur.i];
327
- if (isSkippableLine(line)) break;
328
- if (indentOf(line) <= keyIndent) break;
329
- parts.push(line.trim());
330
- cur.i++;
331
- }
332
- return parts.join(" ");
333
- }
334
- function parseValue(cur, keyIndent, inline) {
335
- const blockScalar = /^([|>])([0-9]*)([+-]?)$/.exec(inline);
336
- if (blockScalar) {
337
- return parseBlockScalar(cur, keyIndent, blockScalar[1] === ">", blockScalar[3]);
338
- }
339
- if (inline === "") return parseNodeBelowKey(cur, keyIndent);
340
- if (inline.startsWith('"') || inline.startsWith("'")) {
341
- const quoted = readQuotedScalar(inline);
342
- if (quoted && quoted.rest.trim() === "") return quoted.value;
343
- const quote = inline[0];
344
- if (inline.length >= 2 && inline.endsWith(quote)) {
345
- const body = inline.slice(1, -1);
346
- return quote === "'" ? body.replace(/''/g, "'") : body;
347
- }
348
- return inline;
349
- }
350
- if (inline === "[]") return [];
351
- if (inline === "{}") return {};
352
- if (inline.startsWith("{") || inline.startsWith("[")) return inline;
353
- return scalarFromText(collectPlainContinuation(cur, keyIndent, inline));
354
- }
355
- function parseNodeBelowKey(cur, keyIndent) {
356
- const j = nextSignificant(cur);
357
- if (j >= cur.lines.length) return null;
358
- const line = cur.lines[j];
359
- const ind = indentOf(line);
360
- const content = line.slice(ind);
361
- if (isSequenceItem(content) && ind >= keyIndent) {
362
- cur.i = j;
363
- return parseSequence(cur, ind);
364
- }
365
- if (ind > keyIndent) {
366
- cur.i = j;
367
- if (splitMappingKey(content)) return parseMapping(cur, ind);
368
- cur.i = j + 1;
369
- return scalarFromText(collectPlainContinuation(cur, keyIndent, content.trim()));
370
- }
371
- return null;
372
- }
373
- function parseNodeBelowDash(cur, dashIndent) {
374
- const j = nextSignificant(cur);
375
- if (j >= cur.lines.length) return null;
376
- const line = cur.lines[j];
377
- const ind = indentOf(line);
378
- if (ind <= dashIndent) return null;
379
- const content = line.slice(ind);
380
- cur.i = j;
381
- if (isSequenceItem(content)) return parseSequence(cur, ind);
382
- if (splitMappingKey(content)) return parseMapping(cur, ind);
383
- cur.i = j + 1;
384
- return scalarFromText(collectPlainContinuation(cur, dashIndent, content.trim()));
385
- }
386
- function parseSequence(cur, indent) {
387
- const items = [];
388
- for (; ; ) {
389
- const j = nextSignificant(cur);
390
- if (j >= cur.lines.length) {
391
- cur.i = j;
392
- break;
393
- }
394
- const line = cur.lines[j];
395
- const ind = indentOf(line);
396
- if (ind !== indent) break;
397
- const content = line.slice(ind);
398
- if (!isSequenceItem(content)) break;
399
- const afterDash = content.slice(1);
400
- const itemText = afterDash.trimStart();
401
- if (itemText === "") {
402
- cur.i = j + 1;
403
- items.push(parseNodeBelowDash(cur, ind));
404
- continue;
405
- }
406
- const itemCol = ind + 1 + (afterDash.length - itemText.length);
407
- const entry = splitMappingKey(itemText);
408
- if (entry) {
409
- cur.lines[j] = " ".repeat(itemCol) + itemText;
410
- cur.i = j;
411
- items.push(parseMapping(cur, itemCol));
412
- continue;
413
- }
414
- cur.i = j + 1;
415
- items.push(parseValue(cur, ind, itemText));
416
- }
417
- return items;
418
- }
419
- function parseMapping(cur, indent) {
420
- const map = {};
421
- for (; ; ) {
422
- const j = nextSignificant(cur);
423
- if (j >= cur.lines.length) {
424
- cur.i = j;
425
- break;
426
- }
427
- const line = cur.lines[j];
428
- const ind = indentOf(line);
429
- if (ind !== indent) break;
430
- const content = line.slice(ind);
431
- if (isSequenceItem(content)) break;
432
- const entry = splitMappingKey(content);
433
- if (!entry) break;
434
- cur.i = j + 1;
435
- assignKey(map, entry.key, parseValue(cur, indent, entry.rest));
436
- }
437
- return map;
438
- }
439
- function parseFrontmatter(yaml) {
440
- if (!yaml || !yaml.trim()) return null;
441
- const cur = { lines: yaml.replace(/\r\n?/g, "\n").split("\n"), i: 0 };
442
- const result = {};
443
- for (; ; ) {
444
- const j = nextSignificant(cur);
445
- if (j >= cur.lines.length) break;
446
- cur.i = j;
447
- const map = parseMapping(cur, indentOf(cur.lines[j]));
448
- for (const [key, value] of Object.entries(map)) assignKey(result, key, value);
449
- if (cur.i <= j) cur.i = j + 1;
450
- }
451
- return Object.keys(result).length > 0 ? result : null;
452
- }
453
- function formatBlockScalar(value) {
454
- const body = value.split("\n").map((line) => line === "" ? "" : ` ${line}`).join("\n");
455
- return `|-
456
- ${body}`;
457
- }
458
- var FRONTMATTER_BLOCK_RE = /^---\r?\n([\s\S]*?)\r?\n---(\r?\n)?/;
459
- var EMPTY_FRONTMATTER_BLOCK_RE = /^---\r?\n---(\r?\n)?/;
460
- function splitFrontmatterBlock(source) {
461
- const match = FRONTMATTER_BLOCK_RE.exec(source) ?? EMPTY_FRONTMATTER_BLOCK_RE.exec(source);
462
- if (!match) return { frontmatter: null, body: source };
463
- return { frontmatter: match[0], body: source.slice(match[0].length) };
464
- }
465
- function formatFrontmatterValue(value) {
466
- if (typeof value === "boolean" || typeof value === "number") return String(value);
467
- if (/[\r\n]/.test(value)) return formatBlockScalar(value.replace(/\r\n?/g, "\n"));
468
- if (value !== "[]" && value !== "{}" && /^[{[]/.test(value)) return value;
469
- const needsQuote = /^\s|\s$/.test(value) || /^[!&*?|>%@`~]/.test(value) || /[:#]/.test(value) || value === "" || value === "[]" || value === "{}" || YAML_TRUE.has(value) || YAML_FALSE.has(value) || YAML_NULL.has(value) || value !== "" && !Number.isNaN(Number(value)) || /^["']/.test(value) && /["']$/.test(value);
470
- if (!needsQuote) return value;
471
- const escaped = value.replace(/\\/g, "\\\\").replace(/"/g, '\\"');
472
- return `"${escaped}"`;
473
- }
474
- function formatFrontmatterKey(key) {
475
- return /^[A-Za-z0-9_](?:[A-Za-z0-9 _.-]*[A-Za-z0-9_.-])?$/.test(key) ? key : formatFrontmatterValue(key);
476
- }
477
- function isPlainRecord(value) {
478
- if (value === null || typeof value !== "object" || Array.isArray(value)) return false;
479
- const proto = Object.getPrototypeOf(value);
480
- return proto === Object.prototype || proto === null;
481
- }
482
- function isOmittedValue(value) {
483
- return value === void 0 || typeof value === "function" || typeof value === "symbol";
484
- }
485
- function toScalar(value) {
486
- if (typeof value === "string" || typeof value === "number" || typeof value === "boolean") {
487
- return value;
488
- }
489
- if (value instanceof Date) return value.toISOString();
490
- return String(value);
491
- }
492
- function pushScalar(out, pad, prefix, value) {
493
- const formatted = formatFrontmatterValue(toScalar(value));
494
- if (!formatted.includes("\n")) {
495
- out.push(`${pad}${prefix}${formatted}`);
496
- return;
497
- }
498
- const [head, ...body] = formatted.split("\n");
499
- out.push(`${pad}${prefix}${head}`);
500
- for (const line of body) out.push(line === "" ? "" : `${pad}${line}`);
501
- }
502
- function emitSequence(items, indent, out) {
503
- const pad = " ".repeat(indent);
504
- for (const item of items) {
505
- if (item === null || isOmittedValue(item)) {
506
- out.push(`${pad}- null`);
507
- continue;
508
- }
509
- if (Array.isArray(item)) {
510
- if (item.length === 0) {
511
- out.push(`${pad}- []`);
512
- continue;
513
- }
514
- out.push(`${pad}-`);
515
- emitSequence(item, indent + 2, out);
516
- continue;
517
- }
518
- if (isPlainRecord(item)) {
519
- const sub = [];
520
- emitMapping(item, indent + 2, sub);
521
- if (sub.length === 0) {
522
- out.push(`${pad}- {}`);
523
- continue;
524
- }
525
- sub[0] = `${pad}- ${sub[0].slice(indent + 2)}`;
526
- out.push(...sub);
527
- continue;
528
- }
529
- pushScalar(out, pad, "- ", item);
530
- }
531
- }
532
- function emitMapping(map, indent, out) {
533
- const pad = " ".repeat(indent);
534
- for (const [rawKey, value] of Object.entries(map)) {
535
- if (isOmittedValue(value)) continue;
536
- const key = formatFrontmatterKey(rawKey);
537
- if (value === null) {
538
- out.push(`${pad}${key}: null`);
539
- continue;
540
- }
541
- if (Array.isArray(value)) {
542
- if (value.length === 0) {
543
- out.push(`${pad}${key}: []`);
544
- continue;
545
- }
546
- out.push(`${pad}${key}:`);
547
- emitSequence(value, indent + 2, out);
548
- continue;
549
- }
550
- if (isPlainRecord(value)) {
551
- const sub = [];
552
- emitMapping(value, indent + 2, sub);
553
- if (sub.length === 0) {
554
- out.push(`${pad}${key}: {}`);
555
- continue;
556
- }
557
- out.push(`${pad}${key}:`);
558
- out.push(...sub);
559
- continue;
560
- }
561
- pushScalar(out, pad, `${key}: `, value);
562
- }
563
- }
564
- function formatFrontmatterYaml(frontmatter) {
565
- const out = [];
566
- emitMapping(frontmatter, 0, out);
567
- return out.join("\n");
568
- }
569
- function setFrontmatterValues(source, updates) {
570
- const updateKeys = Object.keys(updates);
571
- if (updateKeys.length === 0) return source;
572
- const match = source.match(FRONTMATTER_BLOCK_RE);
573
- const handled = /* @__PURE__ */ new Set();
574
- if (match) {
575
- const inner = match[1];
576
- const lines = inner.split(/\r?\n/);
577
- const newLines = [];
578
- const firstSignificant = lines.find((line) => !isSkippableLine(line));
579
- const rootIndent = firstSignificant === void 0 ? 0 : indentOf(firstSignificant);
580
- let i = 0;
581
- while (i < lines.length) {
582
- const line = lines[i];
583
- const ind = indentOf(line);
584
- const entry = isSkippableLine(line) || ind !== rootIndent ? null : splitMappingKey(line.slice(ind));
585
- if (!entry) {
586
- newLines.push(line);
587
- i++;
588
- continue;
589
- }
590
- let end = i + 1;
591
- while (end < lines.length) {
592
- if (lines[end].trim() === "") {
593
- let probe = end;
594
- while (probe < lines.length && lines[probe].trim() === "") probe++;
595
- if (probe < lines.length && indentOf(lines[probe]) > rootIndent) {
596
- end = probe;
597
- continue;
598
- }
599
- break;
600
- }
601
- if (indentOf(lines[end]) <= rootIndent) break;
602
- end++;
603
- }
604
- if (!Object.prototype.hasOwnProperty.call(updates, entry.key)) {
605
- for (let k = i; k < end; k++) newLines.push(lines[k]);
606
- i = end;
607
- continue;
608
- }
609
- handled.add(entry.key);
610
- const next = updates[entry.key];
611
- if (next !== null && next !== void 0) {
612
- pushScalar(newLines, " ".repeat(rootIndent), `${formatFrontmatterKey(entry.key)}: `, next);
613
- }
614
- i = end;
615
- }
616
- for (const key of updateKeys) {
617
- if (handled.has(key)) continue;
618
- const next = updates[key];
619
- if (next === null || next === void 0) continue;
620
- pushScalar(newLines, "", `${formatFrontmatterKey(key)}: `, next);
621
- }
622
- const nonEmpty = newLines.filter((l) => l.trim().length > 0);
623
- const rest = source.slice(match[0].length);
624
- if (nonEmpty.length === 0) return rest;
625
- return `---
626
- ${newLines.join("\n")}
627
- ---
628
- ${rest}`;
629
- }
630
- const fresh = [];
631
- for (const key of updateKeys) {
632
- const next = updates[key];
633
- if (next === null || next === void 0) continue;
634
- pushScalar(fresh, "", `${formatFrontmatterKey(key)}: `, next);
635
- }
636
- if (fresh.length === 0) return source;
637
- return `---
638
- ${fresh.join("\n")}
639
- ---
640
- ${source}`;
641
- }
642
- function createDocument(...children) {
643
- return {
644
- type: "document",
645
- children
646
- };
647
- }
648
- function inferDocumentTitle(doc) {
649
- const fmTitle = doc.frontmatter?.title;
650
- if (typeof fmTitle === "string") {
651
- const trimmed = fmTitle.trim();
652
- if (trimmed) return trimmed;
653
- }
654
- let best = null;
655
- for (const node of doc.children) {
656
- if (node.type !== "heading") continue;
657
- const text = extractPlainText(node).trim();
658
- if (!text) continue;
659
- if (best === null || node.depth < best.depth) {
660
- best = { depth: node.depth, text };
661
- if (best.depth === 1) break;
662
- }
663
- }
664
- return best?.text;
665
- }
666
- function readFrontmatterThemeId(frontmatter) {
667
- if (!frontmatter) return void 0;
668
- const keys = ["squisq-theme", "themeId", "theme"];
669
- for (const key of keys) {
670
- const raw = frontmatter[key];
671
- if (typeof raw === "string") {
672
- const trimmed = raw.trim();
673
- if (trimmed) return trimmed;
674
- }
675
- }
676
- return void 0;
677
- }
678
- function plainTextFromInlineHtml(html) {
679
- const BLOCK = /* @__PURE__ */ new Set([
680
- "p",
681
- "div",
682
- "h1",
683
- "h2",
684
- "h3",
685
- "h4",
686
- "h5",
687
- "h6",
688
- "li",
689
- "blockquote",
690
- "pre"
691
- ]);
692
- const walk = (nodes) => nodes.map((n) => {
693
- if (n.type === "htmlText") return n.value;
694
- if (n.type !== "htmlElement") return "";
695
- const tag = n.tagName.toLowerCase();
696
- if (tag === "br") return "\n";
697
- const inner = walk(n.children);
698
- return BLOCK.has(tag) ? `${inner}
699
- ` : inner;
700
- }).join("");
701
- return walk(parseHtmlToNodes(html)).replace(/\u00A0/g, " ").replace(/\n{3,}/g, "\n\n").trim();
702
- }
703
-
704
- // src/markdown/videoEmbed.ts
705
- var VIDEO_EMBED_PROVIDERS = [
706
- { id: "youtube", name: "YouTube", example: "https://www.youtube.com/watch?v=dQw4w9WgXcQ" },
707
- { id: "vimeo", name: "Vimeo", example: "https://vimeo.com/76979871" },
708
- {
709
- id: "loom",
710
- name: "Loom",
711
- example: "https://www.loom.com/share/0281766fa2d04bb788eaf19e65135184"
712
- },
713
- { id: "dailymotion", name: "Dailymotion", example: "https://www.dailymotion.com/video/x7tgad0" },
714
- { id: "wistia", name: "Wistia", example: "https://home.wistia.com/medias/e4a27b971d" }
715
- ];
716
- var PROVIDER_NAMES = Object.fromEntries(
717
- VIDEO_EMBED_PROVIDERS.map((p) => [p.id, p.name])
718
- );
719
- var LANDSCAPE = 16 / 9;
720
- var PORTRAIT = 9 / 16;
721
- function unescapeMarkdown(value) {
722
- return value.replace(/\\([!-/:-@[-`{-~])/g, "$1");
723
- }
724
- function toUrl(input) {
725
- let text = unescapeMarkdown(input.trim());
726
- if (text.startsWith("<") && text.endsWith(">")) text = text.slice(1, -1).trim();
727
- if (!text || /\s/.test(text)) return null;
728
- if (text.startsWith("//")) text = `https:${text}`;
729
- else if (!/^[a-z][a-z0-9+.-]*:/i.test(text)) text = `https://${text}`;
730
- let url;
731
- try {
732
- url = new URL(text);
733
- } catch {
734
- return null;
735
- }
736
- if (url.protocol !== "https:" && url.protocol !== "http:") return null;
737
- if (url.username || url.password || url.port) return null;
738
- return url;
739
- }
740
- function baseHost(url) {
741
- return url.hostname.toLowerCase().replace(/^(?:www|m)\./, "");
742
- }
743
- function pathSegments(url) {
744
- return url.pathname.split("/").filter(Boolean).map((segment) => {
745
- try {
746
- return decodeURIComponent(segment);
747
- } catch {
748
- return segment;
749
- }
750
- });
751
- }
752
- function fragmentParam(url, key) {
753
- const hash = url.hash.replace(/^#/, "");
754
- if (!hash) return null;
755
- return new URLSearchParams(hash).get(key);
756
- }
757
- var HMS_RE = /^(?:(\d+)h)?(?:(\d+)m)?(?:(\d+)s?)?$/;
758
- var CLOCK_RE = /^(?:(\d+):)?(\d{1,2}):(\d{2})$/;
759
- function parseVideoStartTime(raw) {
760
- if (!raw) return void 0;
761
- const value = raw.trim().toLowerCase();
762
- if (!value) return void 0;
763
- let total = null;
764
- const hms = HMS_RE.exec(value);
765
- if (hms && (hms[1] || hms[2] || hms[3])) {
766
- total = Number(hms[1] ?? 0) * 3600 + Number(hms[2] ?? 0) * 60 + Number(hms[3] ?? 0);
767
- } else {
768
- const clock = CLOCK_RE.exec(value);
769
- const minutes = Number(clock?.[2]);
770
- const seconds = Number(clock?.[3]);
771
- if (clock && seconds < 60 && (clock[1] === void 0 || minutes < 60)) {
772
- total = Number(clock[1] ?? 0) * 3600 + minutes * 60 + seconds;
773
- }
774
- }
775
- if (total === null || !Number.isFinite(total) || total <= 0) return void 0;
776
- return Math.floor(total);
777
- }
778
- function withQuery(base, params) {
779
- const query = params.filter((entry) => entry[1] !== void 0).map(([key, value]) => `${key}=${encodeURIComponent(value)}`).join("&");
780
- return query ? `${base}?${query}` : base;
781
- }
782
- function build(provider, fields) {
783
- const embed = {
784
- provider,
785
- providerName: PROVIDER_NAMES[provider],
786
- id: fields.id,
787
- embedUrl: fields.embedUrl,
788
- watchUrl: fields.watchUrl,
789
- aspectRatio: fields.aspectRatio ?? LANDSCAPE
790
- };
791
- if (fields.playlistId) embed.playlistId = fields.playlistId;
792
- if (fields.startSeconds) embed.startSeconds = fields.startSeconds;
793
- if (fields.thumbnailUrl) embed.thumbnailUrl = fields.thumbnailUrl;
794
- return embed;
795
- }
796
- var YOUTUBE_HOSTS = /* @__PURE__ */ new Set(["youtube.com", "music.youtube.com", "youtube-nocookie.com"]);
797
- var YOUTUBE_ID_RE = /^[A-Za-z0-9_-]{11}$/;
798
- var YOUTUBE_LIST_RE = /^[A-Za-z0-9_-]{2,80}$/;
799
- var YOUTUBE_ID_PATHS = /* @__PURE__ */ new Set(["embed", "v", "e", "live", "shorts"]);
800
- var YOUTUBE_EMBED_ORIGIN = "https://www.youtube-nocookie.com";
801
- function parseYouTube(url) {
802
- const host = baseHost(url);
803
- const segments = pathSegments(url);
804
- const params = url.searchParams;
805
- let id = null;
806
- let shorts = false;
807
- if (host === "youtu.be") {
808
- id = segments[0] ?? null;
809
- } else if (YOUTUBE_HOSTS.has(host)) {
810
- const [head, second] = segments;
811
- if (head === "watch") id = params.get("v");
812
- else if (head && YOUTUBE_ID_PATHS.has(head) && second !== "videoseries") {
813
- id = second ?? null;
814
- shorts = head === "shorts";
815
- } else if (head !== "playlist" && !(head === "embed" && second === "videoseries")) {
816
- return null;
817
- }
818
- } else {
819
- return null;
820
- }
821
- if (id !== null && !YOUTUBE_ID_RE.test(id)) return null;
822
- const list = params.get("list");
823
- const playlistId = list && YOUTUBE_LIST_RE.test(list) ? list : void 0;
824
- if (!id && !playlistId) return null;
825
- const startSeconds = parseVideoStartTime(
826
- params.get("t") ?? params.get("start") ?? fragmentParam(url, "t")
827
- );
828
- const start = startSeconds ? String(startSeconds) : void 0;
829
- if (!id) {
830
- return build("youtube", {
831
- id: playlistId,
832
- playlistId,
833
- embedUrl: withQuery(`${YOUTUBE_EMBED_ORIGIN}/embed/videoseries`, [["list", playlistId]]),
834
- watchUrl: withQuery("https://www.youtube.com/playlist", [["list", playlistId]])
835
- });
836
- }
837
- return build("youtube", {
838
- id,
839
- playlistId,
840
- startSeconds,
841
- embedUrl: withQuery(`${YOUTUBE_EMBED_ORIGIN}/embed/${id}`, [
842
- ["list", playlistId],
843
- ["start", start]
844
- ]),
845
- watchUrl: shorts ? `https://www.youtube.com/shorts/${id}` : withQuery("https://www.youtube.com/watch", [
846
- ["v", id],
847
- ["list", playlistId],
848
- ["t", start && `${start}s`]
849
- ]),
850
- thumbnailUrl: `https://i.ytimg.com/vi/${id}/hqdefault.jpg`,
851
- aspectRatio: shorts ? PORTRAIT : LANDSCAPE
852
- });
853
- }
854
- var VIMEO_ID_RE = /^\d{1,12}$/;
855
- var VIMEO_HASH_RE = /^[0-9a-f]{6,24}$/i;
856
- function vimeoIdFromSegments(segments) {
857
- const [a, b, c, d] = segments;
858
- if (a && VIMEO_ID_RE.test(a)) {
859
- return { id: a, ...b && VIMEO_HASH_RE.test(b) ? { hash: b } : {} };
860
- }
861
- if (a === "video" && b && VIMEO_ID_RE.test(b)) return { id: b };
862
- if (a === "channels" && c && VIMEO_ID_RE.test(c)) return { id: c };
863
- if (a === "groups" && c === "videos" && d && VIMEO_ID_RE.test(d)) return { id: d };
864
- if ((a === "album" || a === "showcase") && c === "video" && d && VIMEO_ID_RE.test(d)) {
865
- return { id: d };
866
- }
867
- return null;
868
- }
869
- function parseVimeo(url) {
870
- const host = baseHost(url);
871
- if (host !== "vimeo.com" && host !== "player.vimeo.com") return null;
872
- const found = vimeoIdFromSegments(pathSegments(url));
873
- if (!found) return null;
874
- const queryHash = url.searchParams.get("h");
875
- const hash = found.hash ?? (queryHash && VIMEO_HASH_RE.test(queryHash) ? queryHash : void 0);
876
- const startSeconds = parseVideoStartTime(
877
- fragmentParam(url, "t") ?? url.searchParams.get("t") ?? url.searchParams.get("start")
878
- );
879
- const timeFragment = startSeconds ? `#t=${startSeconds}s` : "";
880
- return build("vimeo", {
881
- id: found.id,
882
- startSeconds,
883
- embedUrl: withQuery(`https://player.vimeo.com/video/${found.id}`, [["h", hash]]) + timeFragment,
884
- watchUrl: `https://vimeo.com/${found.id}${hash ? `/${hash}` : ""}${timeFragment}`
885
- });
886
- }
887
- var LOOM_ID_RE = /(?:^|-)([0-9a-f]{32})$/i;
888
- function parseLoom(url) {
889
- if (baseHost(url) !== "loom.com") return null;
890
- const [head, second] = pathSegments(url);
891
- if (head !== "share" && head !== "embed" || !second) return null;
892
- const match = LOOM_ID_RE.exec(second);
893
- if (!match) return null;
894
- const id = match[1].toLowerCase();
895
- return build("loom", {
896
- id,
897
- embedUrl: `https://www.loom.com/embed/${id}`,
898
- watchUrl: `https://www.loom.com/share/${id}`
899
- });
900
- }
901
- var DAILYMOTION_ID_RE = /^[A-Za-z0-9]{5,20}$/;
902
- function parseDailymotion(url) {
903
- const host = baseHost(url);
904
- const segments = pathSegments(url);
905
- let raw = null;
906
- if (host === "dai.ly") raw = segments[0] ?? null;
907
- else if (host === "dailymotion.com") {
908
- if (segments[0] === "video") raw = segments[1] ?? null;
909
- else if (segments[0] === "embed" && segments[1] === "video") raw = segments[2] ?? null;
910
- else return null;
911
- } else if (host === "geo.dailymotion.com") {
912
- raw = url.searchParams.get("video");
913
- } else {
914
- return null;
915
- }
916
- const id = raw?.split("_")[0];
917
- if (!id || !DAILYMOTION_ID_RE.test(id)) return null;
918
- const startSeconds = parseVideoStartTime(url.searchParams.get("start"));
919
- const start = startSeconds ? String(startSeconds) : void 0;
920
- return build("dailymotion", {
921
- id,
922
- startSeconds,
923
- embedUrl: withQuery(`https://www.dailymotion.com/embed/video/${id}`, [["start", start]]),
924
- watchUrl: withQuery(`https://www.dailymotion.com/video/${id}`, [["start", start]]),
925
- thumbnailUrl: `https://www.dailymotion.com/thumbnail/video/${id}`
926
- });
927
- }
928
- var WISTIA_ID_RE = /^[a-z0-9]{10}$/;
929
- var WISTIA_ACCOUNT_HOST_RE = /^[a-z0-9-]{1,63}\.wistia\.com$/;
930
- function parseWistia(url) {
931
- const host = url.hostname.toLowerCase();
932
- const fastHost = host === "fast.wistia.net" || host === "fast.wistia.com";
933
- if (!fastHost && !WISTIA_ACCOUNT_HOST_RE.test(host)) return null;
934
- const segments = pathSegments(url);
935
- let raw;
936
- if (segments[0] === "medias") raw = segments[1];
937
- else if (segments[0] === "embed" && (segments[1] === "iframe" || segments[1] === "medias")) {
938
- raw = segments[2];
939
- }
940
- const id = raw?.replace(/\.jsonp$/, "");
941
- if (!id || !WISTIA_ID_RE.test(id)) return null;
942
- const embedUrl = `https://fast.wistia.net/embed/iframe/${id}`;
943
- return build("wistia", {
944
- id,
945
- embedUrl,
946
- // A media page lives on the account's own subdomain; the fast host only
947
- // serves the player, which doubles as a viewable page.
948
- watchUrl: fastHost ? embedUrl : `https://${host}/medias/${id}`
949
- });
950
- }
951
- var PARSERS = [
952
- parseYouTube,
953
- parseVimeo,
954
- parseLoom,
955
- parseDailymotion,
956
- parseWistia
957
- ];
958
- function parseVideoEmbedUrl(input) {
959
- if (typeof input !== "string") return null;
960
- const url = toUrl(input);
961
- if (!url) return null;
962
- for (const parse of PARSERS) {
963
- const embed = parse(url);
964
- if (embed) return embed;
965
- }
966
- return null;
967
- }
968
- function isVideoEmbedUrl(input) {
969
- return parseVideoEmbedUrl(input) !== null;
970
- }
971
- var VIDEO_EMBED_IFRAME_ALLOW = "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share; fullscreen";
972
- function videoEmbedIframeAttributes(embed, title) {
973
- return {
974
- src: embed.embedUrl,
975
- title: title?.trim() || `${embed.providerName} video`,
976
- allow: VIDEO_EMBED_IFRAME_ALLOW,
977
- allowfullscreen: "",
978
- referrerpolicy: "strict-origin-when-cross-origin",
979
- loading: "lazy"
980
- };
981
- }
982
- var GENERIC_PLAYER_TITLE_RE = /^(?:[\w .-]+[ -])?(?:video[ -])?player$/i;
983
- function attributeOf(element, name) {
984
- for (const [key, value] of Object.entries(element.attributes)) {
985
- if (key.toLowerCase() === name) return value;
986
- }
987
- return void 0;
988
- }
989
- function soleIframe(nodes) {
990
- let found = null;
991
- let disqualified = false;
992
- const visit = (list) => {
993
- for (const node of list) {
994
- if (disqualified) return;
995
- if (node.type === "htmlText") {
996
- if (node.value.trim()) disqualified = true;
997
- continue;
998
- }
999
- if (node.type !== "htmlElement") continue;
1000
- const tag = node.tagName.toLowerCase();
1001
- if (tag === "iframe") {
1002
- if (found) disqualified = true;
1003
- found = node;
1004
- continue;
1005
- }
1006
- if (tag === "script" || tag === "style" || tag === "noscript") continue;
1007
- visit(node.children);
1008
- }
1009
- };
1010
- visit(nodes);
1011
- return disqualified ? null : found;
1012
- }
1013
- function iframeEmbed(element) {
1014
- const embed = parseVideoEmbedUrl(attributeOf(element, "src"));
1015
- if (!embed) return null;
1016
- const title = attributeOf(element, "title")?.trim() ?? "";
1017
- const generic = GENERIC_PLAYER_TITLE_RE.test(title) || title.toLowerCase() === `${embed.providerName} video`.toLowerCase();
1018
- return { embed, title: title && !generic ? title : null };
1019
- }
1020
- function videoEmbedFromIframe(element) {
1021
- return element.tagName.toLowerCase() === "iframe" ? iframeEmbed(element) : null;
1022
- }
1023
- function parseVideoEmbedInput(input) {
1024
- if (typeof input !== "string") return null;
1025
- const text = input.trim();
1026
- if (!text) return null;
1027
- if (/^<(?!https?:)/i.test(text)) {
1028
- if (!/<iframe\b/i.test(text)) return null;
1029
- const iframe = soleIframe(parseHtmlToNodes(text));
1030
- return iframe ? iframeEmbed(iframe) : null;
1031
- }
1032
- const embed = parseVideoEmbedUrl(text);
1033
- return embed ? { embed, title: null } : null;
1034
- }
1035
- function isBlankInline(node) {
1036
- return node.type === "text" && !node.value.trim() || node.type === "htmlInline" && node.htmlChildren.length === 0;
1037
- }
1038
- function findBlockVideoEmbed(node) {
1039
- if (node.type === "htmlBlock") {
1040
- const iframe = soleIframe(node.htmlChildren);
1041
- const found = iframe ? iframeEmbed(iframe) : null;
1042
- return found ? { ...found, form: "iframe" } : null;
1043
- }
1044
- if (node.type !== "paragraph") return null;
1045
- const text = extractPlainText(node).trim();
1046
- if (text && !/\s/.test(text)) {
1047
- const bare = parseVideoEmbedUrl(text);
1048
- if (bare) return { embed: bare, title: null, form: "url" };
1049
- }
1050
- const significant = node.children.filter((child) => !isBlankInline(child));
1051
- if (significant.length !== 1 || significant[0].type !== "link") return null;
1052
- const link = significant[0];
1053
- const embed = parseVideoEmbedUrl(link.url);
1054
- if (!embed) return null;
1055
- const label = extractPlainText(link).trim();
1056
- const title = label && !isVideoEmbedUrl(label) && label !== link.url ? label : null;
1057
- return { embed, title, form: title ? "link" : "url" };
1058
- }
1059
-
1060
- export {
1061
- mediaKindForUrl,
1062
- parseHtmlToNodes,
1063
- stringifyHtmlNodes,
1064
- getChildren,
1065
- walkMarkdownTree,
1066
- findNodesByType,
1067
- extractPlainText,
1068
- countNodes,
1069
- parseFrontmatter,
1070
- formatBlockScalar,
1071
- splitFrontmatterBlock,
1072
- formatFrontmatterValue,
1073
- formatFrontmatterYaml,
1074
- setFrontmatterValues,
1075
- createDocument,
1076
- inferDocumentTitle,
1077
- readFrontmatterThemeId,
1078
- plainTextFromInlineHtml,
1079
- VIDEO_EMBED_PROVIDERS,
1080
- parseVideoStartTime,
1081
- parseVideoEmbedUrl,
1082
- isVideoEmbedUrl,
1083
- VIDEO_EMBED_IFRAME_ALLOW,
1084
- videoEmbedIframeAttributes,
1085
- videoEmbedFromIframe,
1086
- parseVideoEmbedInput,
1087
- findBlockVideoEmbed
1088
- };