@openpresentation/opf 0.26.3 → 0.26.5

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 (39) hide show
  1. package/README.md +3 -1
  2. package/dist/browser.js +14 -11
  3. package/dist/{chunk-NJWI6MPT.js → chunk-CIWC7DRZ.js} +1985 -366
  4. package/dist/{chunk-7RY7QWWJ.js → chunk-DXTPLVAK.js} +1 -1
  5. package/dist/{chunk-54OV2WQC.js → chunk-EFMR32A5.js} +1 -1
  6. package/dist/{chunk-PXOXTJTN.js → chunk-HPEZCAYC.js} +1 -1
  7. package/dist/{chunk-2ZQBMZTZ.js → chunk-K5Q3LLYK.js} +2 -2
  8. package/dist/chunk-KPALXWX3.js +712 -0
  9. package/dist/{chunk-34LIUOT7.js → chunk-L7YEVQHP.js} +6 -6
  10. package/dist/chunk-MD3CJ5YJ.js +452 -0
  11. package/dist/{chunk-WASENX2R.js → chunk-MLH5LIGF.js} +29 -647
  12. package/dist/chunk-RYZPBJLB.js +4 -0
  13. package/dist/{chunk-FXNUM2PN.js → chunk-STIYINEL.js} +4 -4
  14. package/dist/{chunk-YVNFACTC.js → chunk-TAV5S2JG.js} +1 -1
  15. package/dist/{chunk-GLLR3AQ5.js → chunk-UFEWQDQI.js} +1 -1
  16. package/dist/chunk-UY6SQVR2.js +639 -0
  17. package/dist/{chunk-PB5X2VSV.js → chunk-WAZDP2WS.js} +12 -20
  18. package/dist/{conversion-BjsKgxBZ.d.ts → conversion-C7o2EpDb.d.ts} +2 -2
  19. package/dist/conversion-PMJWLHDV.js +21 -0
  20. package/dist/convert.js +5 -5
  21. package/dist/deck.js +9 -7
  22. package/dist/diff.js +2 -2
  23. package/dist/docs.js +3 -3
  24. package/dist/explain-JSuESV-Y.d.ts +71 -0
  25. package/dist/index.d.ts +3 -2
  26. package/dist/index.js +18 -15
  27. package/dist/markdown.js +7 -5
  28. package/dist/node-engine.d.ts +2 -2
  29. package/dist/node-engine.js +18 -15
  30. package/dist/pagination.js +2 -2
  31. package/dist/patch.js +1 -1
  32. package/dist/schema.js +1 -1
  33. package/dist/source.d.ts +184 -5
  34. package/dist/source.js +391 -11
  35. package/dist/validator.js +1 -1
  36. package/dist/yaml.js +5 -4
  37. package/package.json +5 -5
  38. package/dist/chunk-DEI2M2H6.js +0 -194
  39. package/dist/conversion-F4UCOGR7.js +0 -18
package/dist/source.js CHANGED
@@ -1,12 +1,379 @@
1
- import { createLocator, parsePointer } from './chunk-NJWI6MPT.js';
2
- export { analyzeJsonSyntax, applyTextEdits } from './chunk-NJWI6MPT.js';
1
+ export { explain } from './chunk-MD3CJ5YJ.js';
2
+ import { readMarkdown, frontMatter, splitSegments, isOutline, NOTES, fenceStart, fenceClose, COMMENT } from './chunk-MLH5LIGF.js';
3
+ import './chunk-DXTPLVAK.js';
4
+ import { splitLines } from './chunk-KPALXWX3.js';
5
+ export { analyzeYamlSyntax } from './chunk-KPALXWX3.js';
6
+ import './chunk-HPEZCAYC.js';
7
+ import { rememberByText, SLIDE_OPTION_KEYS, FENCE_KINDS, createLocator, parsePointer } from './chunk-CIWC7DRZ.js';
8
+ export { BLOCK_AS_VALUES, BLOCK_OPTION_KEYS, FENCE_ATTRIBUTES, FENCE_KINDS, LINE_KEYWORDS, METRIC_KEYS, PATTERN_PHRASES, SLIDE_OPTION_KEYS, SPAN_FLAGS, SPAN_VALUES, analyzeJsonSyntax, applyTextEdits, describeFinding, distance, nearest, segmentsOf as pointerSegments, starterValue } from './chunk-CIWC7DRZ.js';
3
9
  import './chunk-XRMV2GMB.js';
4
10
  import './chunk-F4HFDP6I.js';
5
11
  import { findNodeAtOffset, getNodePath, parseTree } from 'jsonc-parser';
12
+ import { parseDocument, isMap, isSeq, isScalar, isAlias } from 'yaml';
6
13
 
14
+ var read = rememberByText(readText);
15
+ function readText(text) {
16
+ const bom = text.startsWith("\uFEFF") ? 1 : 0;
17
+ const body = bom ? text.slice(1) : text;
18
+ const document = parseDocument(body, { prettyErrors: false, uniqueKeys: false, merge: false, strict: false });
19
+ return { text: body, root: document.contents ?? null, shift: bom };
20
+ }
21
+ var isBlank = (char) => char === " " || char === " " || char === "\n" || char === "\r";
22
+ function endOf(text, node) {
23
+ let end = node.range[1];
24
+ const start = node.range[0];
25
+ while (end > start && isBlank(text[end - 1])) end--;
26
+ return end;
27
+ }
28
+ var startOf = (node) => node.range[0];
29
+ var keyName = (key) => isScalar(key) ? String(key.value) : isAlias(key) ? void 0 : key !== null && typeof key === "object" && "toString" in key ? String(key.toString()) : void 0;
30
+ var hasText = (text, node) => !!node && node.range[0] < endOf(text, node);
31
+ var pairKey = (pair) => pair.key ?? null;
32
+ var pairValue = (pair) => pair.value ?? null;
33
+ function colonEnd(text, key) {
34
+ let at = key.range[1];
35
+ while (text[at] === " " || text[at] === " ") at++;
36
+ return text[at] === ":" ? at + 1 : key.range[1];
37
+ }
38
+ function member(node, segment) {
39
+ if (isMap(node)) {
40
+ const pair = node.items.find((item) => keyName(item.key) === segment);
41
+ return pair ? { pair, value: pairValue(pair) } : void 0;
42
+ }
43
+ if (isSeq(node)) {
44
+ if (!/^(?:0|[1-9][0-9]*)$/.test(segment)) return void 0;
45
+ const item = node.items[Number(segment)];
46
+ return item === void 0 ? void 0 : { value: item };
47
+ }
48
+ return void 0;
49
+ }
50
+ function openOf(text, value) {
51
+ const start = startOf(value);
52
+ if (isMap(value) && !value.flow) {
53
+ const first = value.items[0];
54
+ const key = first ? pairKey(first) : null;
55
+ if (key) return { offset: startOf(key), length: key.range[1] - startOf(key) };
56
+ }
57
+ return { offset: start, length: Math.min(1, endOf(text, value) - start) };
58
+ }
59
+ function locateYaml(text, segments, part) {
60
+ const { text: body, root, shift } = read(text);
61
+ if (!root || !hasText(body, root)) return void 0;
62
+ let value = root;
63
+ let pair;
64
+ let depth = 0;
65
+ for (const segment of segments) {
66
+ const next = value ? member(value, segment) : void 0;
67
+ if (!value || !next) break;
68
+ pair = next.pair;
69
+ value = next.value;
70
+ depth++;
71
+ }
72
+ const exact = depth === segments.length;
73
+ const key = pair ? pairKey(pair) : null;
74
+ const keySpan = key ? { offset: startOf(key), length: key.range[1] - startOf(key) } : void 0;
75
+ const keyAndColon = key ? { offset: startOf(key), length: colonEnd(body, key) - startOf(key) } : void 0;
76
+ const valueSpan = hasText(body, value) ? { offset: startOf(value), length: endOf(body, value) - startOf(value) } : void 0;
77
+ const choose = (wanted) => {
78
+ switch (wanted) {
79
+ case "value":
80
+ return valueSpan ?? keyAndColon;
81
+ case "open":
82
+ return hasText(body, value) ? openOf(body, value) : keyAndColon;
83
+ case "key":
84
+ return keySpan;
85
+ case "colon":
86
+ return keyAndColon;
87
+ case "entry":
88
+ return keySpan ? { offset: keySpan.offset, length: (valueSpan ? valueSpan.offset + valueSpan.length : (keyAndColon?.offset ?? 0) + (keyAndColon?.length ?? 0)) - keySpan.offset } : void 0;
89
+ }
90
+ };
91
+ const found = choose(part) ?? choose("value") ?? (depth === 0 ? { offset: startOf(root), length: endOf(body, root) - startOf(root) } : void 0);
92
+ return found ? { offset: found.offset + shift, length: found.length, exact } : void 0;
93
+ }
94
+ function pathAtYaml(text, offset) {
95
+ const { text: body, root, shift } = read(text);
96
+ const at = offset - shift;
97
+ const none = { path: [], part: "none" };
98
+ if (!root || !hasText(body, root) || at < startOf(root) || at > endOf(body, root)) return none;
99
+ const span = (node) => ({ offset: startOf(node) + shift, length: endOf(body, node) - startOf(node) });
100
+ const inside = (node) => hasText(body, node) && at >= startOf(node) && at <= endOf(body, node);
101
+ const walk = (node, path) => {
102
+ if (isMap(node)) {
103
+ for (const pair of node.items) {
104
+ const key = pairKey(pair);
105
+ const value = pairValue(pair);
106
+ const name = keyName(pair.key);
107
+ if (name === void 0) continue;
108
+ if (key && at >= startOf(key) && at <= key.range[1]) return { path: [...path, name], part: "key", range: span(key) };
109
+ if (inside(value)) return walk(value, [...path, name]);
110
+ if (key && at > key.range[1] && at <= (hasText(body, value) ? startOf(value) : colonEnd(body, key))) {
111
+ const end = hasText(body, value) ? startOf(value) : colonEnd(body, key);
112
+ return { path: [...path, name], part: "between", range: { offset: startOf(key) + shift, length: end - startOf(key) } };
113
+ }
114
+ }
115
+ return { path, part: "between", range: span(node) };
116
+ }
117
+ if (isSeq(node)) {
118
+ for (const [index, item] of node.items.entries()) if (inside(item)) return walk(item, [...path, String(index)]);
119
+ return { path, part: "between", range: span(node) };
120
+ }
121
+ return { path, part: "value", range: span(node) };
122
+ };
123
+ return walk(root, []);
124
+ }
125
+
126
+ // src/source-markdown.ts
127
+ var BLANK = /^\s*$/;
128
+ var readMarkdown2 = rememberByText((text) => readMarkdown(text));
129
+ var scanMemo = rememberByText((text) => scanUncached(text));
130
+ var isFenceKind = (word) => FENCE_KINDS.includes(word);
131
+ function scanMarkdown(source2, options = {}) {
132
+ return options.split === void 0 ? scanMemo(source2) : scanUncached(source2, options);
133
+ }
134
+ function scanUncached(source2, options = {}) {
135
+ let lines = splitLines(source2);
136
+ if (lines[0]?.text.startsWith("\uFEFF")) lines = [{ ...lines[0], text: lines[0].text.slice(1), start: lines[0].start + 1 }, ...lines.slice(1)];
137
+ const scan = { slides: [], separators: [], comments: [], fences: [], notes: [] };
138
+ const matter = frontMatter(lines);
139
+ let body = lines;
140
+ if (matter === "unterminated") {
141
+ const first = lines[0];
142
+ scan.frontMatter = { from: first.start, to: source2.length, line: 1, yamlFrom: first.end, yamlTo: source2.length, closed: false };
143
+ body = lines.slice(1);
144
+ } else if (matter) {
145
+ const closing = lines[matter.end - 1];
146
+ scan.frontMatter = { from: lines[0].start, to: closing.end, line: 1, yamlFrom: matter.yaml.start, yamlTo: matter.yaml.end, closed: true };
147
+ body = lines.slice(matter.end);
148
+ }
149
+ const split = options.split ?? "auto";
150
+ const segments = splitSegments(body, split === "headings" || split === "auto" && isOutline(body) ? "headings" : "rules");
151
+ const inSegment = new Set(segments.flat());
152
+ for (const line of body) if (!inSegment.has(line) && !BLANK.test(line.text)) scan.separators.push(line.start);
153
+ let index = 0;
154
+ for (const segment of segments) {
155
+ const first = segment.find((line) => !BLANK.test(line.text));
156
+ if (!first) continue;
157
+ const last = [...segment].reverse().find((line) => !BLANK.test(line.text));
158
+ scan.slides.push({ index, from: first.start, to: last.end, line: first.no });
159
+ scanSegment(segment, index, scan);
160
+ index++;
161
+ }
162
+ return scan;
163
+ }
164
+ function scanSegment(lines, slide, scan) {
165
+ let i = 0;
166
+ while (i < lines.length) {
167
+ const line = lines[i];
168
+ const text = line.text;
169
+ if (BLANK.test(text)) {
170
+ i++;
171
+ continue;
172
+ }
173
+ if (NOTES.test(text)) {
174
+ scan.notes.push({ from: line.start, to: lines.at(-1).end, line: line.no, slide });
175
+ return;
176
+ }
177
+ const open = fenceStart(text);
178
+ if (open) {
179
+ const close = fenceClose(open.fence);
180
+ let end = i + 1;
181
+ while (end < lines.length && !close.test(lines[end].text)) end++;
182
+ const closed = end < lines.length;
183
+ const last = closed ? lines[end] : lines.at(-1);
184
+ const indent = /^ */.exec(text)[0].length;
185
+ const marker = open.fence;
186
+ const infoFrom = line.start + indent + marker.length + /^[ \t]*/.exec(text.slice(indent + marker.length))[0].length;
187
+ const word = /^[^\s{]*/.exec(open.info)[0];
188
+ const bodyLines = lines.slice(i + 1, closed ? end : lines.length);
189
+ scan.fences.push({
190
+ from: line.start,
191
+ to: last.end,
192
+ line: line.no,
193
+ marker,
194
+ info: open.info,
195
+ infoFrom,
196
+ infoTo: infoFrom + open.info.length,
197
+ word,
198
+ kind: isFenceKind(word) ? word : "code",
199
+ bodyFrom: bodyLines[0]?.start ?? line.end,
200
+ bodyTo: bodyLines.at(-1)?.end ?? line.end,
201
+ closed,
202
+ slide
203
+ });
204
+ i = closed ? end + 1 : lines.length;
205
+ continue;
206
+ }
207
+ if (COMMENT.test(text)) {
208
+ let end = i;
209
+ while (end < lines.length && !lines[end].text.includes("-->", end === i ? lines[end].text.indexOf("<!--") + 4 : 0)) end++;
210
+ const closed = end < lines.length;
211
+ const last = closed ? lines[end] : lines.at(-1);
212
+ const open2 = text.indexOf("<!--");
213
+ const innerFrom = line.start + open2 + 4;
214
+ const closeAt = closed ? last.start + last.text.indexOf("-->", end === i ? open2 + 4 : 0) : last.end;
215
+ const inner = source(lines, i, closed ? end : lines.length - 1).slice(open2 + 4);
216
+ const kind = /^\s*(slide|block)(?::|(?=\s*(?:-->|$)))/.exec(inner);
217
+ scan.comments.push({ from: line.start, to: closed ? closeAt + 3 : last.end, line: line.no, kind: kind?.[1] ?? "comment", innerFrom, innerTo: closeAt, closed, slide });
218
+ i = closed ? end + 1 : lines.length;
219
+ continue;
220
+ }
221
+ i++;
222
+ }
223
+ }
224
+ function source(lines, first, last) {
225
+ return lines.slice(first, last + 1).map((line) => line.text).join(" ");
226
+ }
227
+ var segmentsOfPointer = (path) => path.map((segment) => `/${segment.replaceAll("~", "~0").replaceAll("/", "~1")}`).join("");
228
+ var SLIDE_OPTIONS = new Set(SLIDE_OPTION_KEYS);
229
+ var OPTIONS_COMMENT = /^\s*<!--/;
230
+ function firstLine(text, range) {
231
+ const end = text.slice(range.start, range.end).search(/[\r\n]/);
232
+ return { offset: range.start, length: end < 0 ? range.end - range.start : end };
233
+ }
234
+ function optionToken(text, comment, key, nth = 0) {
235
+ const inner = text.slice(comment.start, comment.end);
236
+ const open = inner.indexOf("<!--");
237
+ const colon = inner.indexOf(":", open);
238
+ const from = colon < 0 ? open + 4 : colon + 1;
239
+ const pattern = /(?:^|[\s,])([A-Za-z][\w-]*)(=("(?:[^"\\]|\\.)*"|[^\s,"]+))?/g;
240
+ const tail = inner.slice(from);
241
+ let seen = 0;
242
+ for (const match of tail.matchAll(pattern)) {
243
+ if (match[1] !== key) continue;
244
+ if (seen++ !== nth) continue;
245
+ const keyStart = comment.start + from + match.index + match[0].indexOf(match[1]);
246
+ const keySpan = { offset: keyStart, length: key.length };
247
+ const value = match[3] === void 0 ? void 0 : { offset: keyStart + key.length + 1, length: match[3].length };
248
+ return { key: keySpan, ...value ? { value } : {}, entry: { offset: keyStart, length: (value ? value.offset + value.length : keyStart + key.length) - keyStart } };
249
+ }
250
+ return void 0;
251
+ }
252
+ var MARKER = /^( {0,3}(?:#{1,6}|[-+*]|\d{1,9}[.)])[ \t]+)/;
253
+ function afterMarker(text, range) {
254
+ const line = firstLine(text, range);
255
+ const lineText = text.slice(line.offset, line.offset + line.length);
256
+ const match = MARKER.exec(lineText);
257
+ if (!match) return void 0;
258
+ const lead = match[1];
259
+ const markerLength = lead.trimEnd().length;
260
+ const content = lineText.slice(lead.length);
261
+ const trimmed = content.replace(/(?:^|[ \t]+)#+[ \t]*$/, "").trimEnd();
262
+ return { marker: { offset: line.offset + lead.length - lead.trimStart().length, length: markerLength - (lead.length - lead.trimStart().length) }, content: { offset: line.offset + lead.length, length: trimmed.length } };
263
+ }
264
+ function embeddedFenceAt(scan, offset) {
265
+ return scan.fences.find((fence) => (fence.kind === "opf-block" || fence.kind === "opf-slide") && offset >= fence.from && offset <= fence.to);
266
+ }
267
+ function locateMarkdown(text, segments, part) {
268
+ const { ctx, front } = readMarkdown2(text);
269
+ if (segments.length === 0) {
270
+ const trimmed = text.replace(/\s+$/, "").length;
271
+ return trimmed > 0 ? { offset: 0, length: trimmed, exact: true } : void 0;
272
+ }
273
+ if (segments[0] !== "slides") {
274
+ if (!front) return void 0;
275
+ const found = locateYaml(text.slice(front.start, front.end), segments, part);
276
+ if (found) return { offset: found.offset + front.start, length: found.length, exact: found.exact };
277
+ return { offset: front.start, length: Math.max(0, front.end - front.start), exact: false };
278
+ }
279
+ const slidesSpan = () => {
280
+ const first = ctx.ranges.get("/slides/0");
281
+ let last;
282
+ for (let index = 0; ctx.ranges.get(`/slides/${index}`); index++) last = ctx.ranges.get(`/slides/${index}`);
283
+ return first && last ? { start: first.start, end: last.end } : void 0;
284
+ };
285
+ let consumed = segments.length;
286
+ let range;
287
+ for (; consumed > 1; consumed--) {
288
+ range = ctx.ranges.get(segmentsOfPointer(segments.slice(0, consumed)));
289
+ if (range) break;
290
+ }
291
+ if (!range) {
292
+ const whole = slidesSpan();
293
+ return whole ? { offset: whole.start, length: whole.end - whole.start, exact: segments.length === 1 } : void 0;
294
+ }
295
+ const exact = consumed === segments.length;
296
+ const field = segments[2];
297
+ if (consumed >= 3 && field !== void 0 && SLIDE_OPTIONS.has(field) && OPTIONS_COMMENT.test(text.slice(range.start, range.end))) {
298
+ const beatIndex = field === "beat" && consumed === 3 && segments[3] !== void 0 && /^\d+$/.test(segments[3]) ? Number(segments[3]) : 0;
299
+ const token = optionToken(text, range, field, beatIndex);
300
+ if (token) {
301
+ const span = part === "key" ? token.key : part === "entry" || part === "colon" ? token.entry : token.value ?? token.key;
302
+ return { ...span, exact: exact || field === "beat" && consumed === 3 && segments.length === 4 };
303
+ }
304
+ }
305
+ if (!exact) {
306
+ const fence = embeddedFenceAt(scanMarkdown(text), range.start);
307
+ if (fence) {
308
+ const rest = consumed >= 4 && segments[2] === "blocks" ? segments.slice(4) : consumed === 3 ? segments.slice(2) : void 0;
309
+ const inside = rest?.length ? locateYaml(text.slice(fence.bodyFrom, fence.bodyTo), rest, part) : void 0;
310
+ if (inside) return { offset: inside.offset + fence.bodyFrom, length: inside.length, exact: inside.exact };
311
+ }
312
+ }
313
+ const title = consumed === 3 && (field === "title" || field === "subtitle");
314
+ const item = exact && segments.length >= 4 && /^\d+$/.test(segments[segments.length - 1]) && segments[segments.length - 2] !== "blocks";
315
+ if (exact && (title || item)) {
316
+ const marked = afterMarker(text, range);
317
+ if (marked) {
318
+ const span = part === "key" ? marked.marker : part === "entry" ? firstLine(text, range) : marked.content;
319
+ if (span.length > 0) return { ...span, exact: true };
320
+ }
321
+ }
322
+ if (part === "open") return { ...firstLine(text, range), exact };
323
+ return { offset: range.start, length: Math.max(0, range.end - range.start), exact };
324
+ }
325
+ var unescapeSegment = (segment) => segment.replaceAll("~1", "/").replaceAll("~0", "~");
326
+ var spanOf = (range) => ({ offset: range.start, length: range.end - range.start });
327
+ function pathAtMarkdown(text, offset) {
328
+ const { ctx, front } = readMarkdown2(text);
329
+ if (front && offset >= front.start && offset <= front.end) {
330
+ const inside = pathAtYaml(text.slice(front.start, front.end), offset - front.start);
331
+ return { path: inside.path, part: inside.part === "none" ? "between" : inside.part, ...inside.range ? { range: { offset: inside.range.offset + front.start, length: inside.range.length } } : {} };
332
+ }
333
+ const scan = scanMarkdown(text);
334
+ const fence = embeddedFenceAt(scan, offset);
335
+ if (fence && offset >= fence.bodyFrom && offset <= fence.bodyTo) {
336
+ const inside = pathAtYaml(text.slice(fence.bodyFrom, fence.bodyTo), offset - fence.bodyFrom);
337
+ if (inside.part !== "none" && inside.path.length) {
338
+ const block = fence.kind === "opf-block" ? blockIndex(ctx.ranges, fence.slide, fence.from) : -1;
339
+ const prefix = block >= 0 ? ["slides", String(fence.slide), "blocks", String(block)] : ["slides", String(fence.slide)];
340
+ return { path: [...prefix, ...inside.path], part: inside.part, ...inside.range ? { range: { offset: inside.range.offset + fence.bodyFrom, length: inside.range.length } } : {} };
341
+ }
342
+ }
343
+ let best;
344
+ for (const [pointer, range] of ctx.ranges) {
345
+ if (!pointer.startsWith("/slides/") || offset < range.start || offset > range.end) continue;
346
+ const depth = pointer.split("/").length;
347
+ if (!best || depth > best.depth || depth === best.depth && range.end - range.start < best.range.end - best.range.start) best = { pointer, range, depth };
348
+ }
349
+ if (!best) return { path: [], part: "none" };
350
+ const path = best.pointer.split("/").slice(1).map(unescapeSegment);
351
+ const field = path[2];
352
+ if (path.length === 3 && field && SLIDE_OPTIONS.has(field) && OPTIONS_COMMENT.test(text.slice(best.range.start, best.range.end))) {
353
+ for (const key of SLIDE_OPTIONS) {
354
+ for (let nth = 0; ; nth++) {
355
+ const token = optionToken(text, best.range, key, nth);
356
+ if (!token) break;
357
+ const at = key === "beat" ? [path[0], path[1], key, String(nth)] : [path[0], path[1], key];
358
+ if (offset >= token.key.offset && offset <= token.key.offset + token.key.length) return { path: at, part: "key", range: token.key };
359
+ if (token.value && offset >= token.value.offset && offset <= token.value.offset + token.value.length) return { path: at, part: "value", range: token.value };
360
+ }
361
+ }
362
+ return { path: path.slice(0, 2), part: "between", range: spanOf(best.range) };
363
+ }
364
+ return { path, part: "value", range: spanOf(best.range) };
365
+ }
366
+ function blockIndex(ranges, slide, start) {
367
+ for (let index = 0; ranges.has(`/slides/${slide}/blocks/${index}`); index++) if (ranges.get(`/slides/${slide}/blocks/${index}`).start === start) return index;
368
+ return -1;
369
+ }
370
+
371
+ // src/source-locate.ts
372
+ var indexOrKey = (segment) => /^(?:0|[1-9][0-9]*)$/.test(segment) ? Number(segment) : segment;
7
373
  var isJson = (format) => format === "json";
374
+ var isMarkdown = (format) => format === "md" || format === "markdown";
8
375
  var parseText = (text) => parseTree(text.startsWith("\uFEFF") ? ` ${text.slice(1)}` : text, [], { allowTrailingComma: true, allowEmptyContent: true, disallowComments: false });
9
- function segmentsOf(pointer) {
376
+ function segmentsOf2(pointer) {
10
377
  if (Array.isArray(pointer)) return pointer.map(String);
11
378
  if (typeof pointer !== "string") return void 0;
12
379
  try {
@@ -15,7 +382,7 @@ function segmentsOf(pointer) {
15
382
  return void 0;
16
383
  }
17
384
  }
18
- function member(node, segment) {
385
+ function member2(node, segment) {
19
386
  if (node.type === "array") return /^(?:0|[1-9][0-9]*)$/.test(segment) ? node.children?.[Number(segment)] : void 0;
20
387
  if (node.type === "object") return node.children?.find((property) => property.children?.[0]?.value === segment);
21
388
  return void 0;
@@ -37,17 +404,26 @@ function partOf(value, property, part) {
37
404
  }
38
405
  }
39
406
  function locate(text, format, pointer, options = {}) {
40
- if (!isJson(format)) return void 0;
41
- const segments = segmentsOf(pointer);
42
- const root = segments ? parseText(text) : void 0;
43
- if (!segments || !root) return void 0;
407
+ const segments = segmentsOf2(pointer);
408
+ if (!segments) return void 0;
44
409
  const part = options.part ?? "value";
45
410
  const place = createLocator(text);
411
+ if (format === "yaml") {
412
+ const found2 = locateYaml(text, segments, part);
413
+ return found2 ? { ...place(found2.offset, found2.length), ...found2.exact ? {} : { exact: false } } : void 0;
414
+ }
415
+ if (isMarkdown(format)) {
416
+ const found2 = locateMarkdown(text, segments, part);
417
+ return found2 ? { ...place(found2.offset, found2.length), ...found2.exact ? {} : { exact: false } } : void 0;
418
+ }
419
+ if (!isJson(format)) return void 0;
420
+ const root = parseText(text);
421
+ if (!root) return void 0;
46
422
  let value = root;
47
423
  let property;
48
424
  let depth = 0;
49
425
  for (const segment of segments) {
50
- const next = value ? member(value, segment) : void 0;
426
+ const next = value ? member2(value, segment) : void 0;
51
427
  if (!value || !next) break;
52
428
  if (value.type === "object") {
53
429
  property = next;
@@ -64,9 +440,13 @@ function locate(text, format, pointer, options = {}) {
64
440
  return { ...place(found.offset, found.length), ...exact ? {} : { exact: false } };
65
441
  }
66
442
  function pathAt(text, format, offset) {
443
+ const place = createLocator(text);
444
+ if (format === "yaml" || isMarkdown(format)) {
445
+ const found = format === "yaml" ? pathAtYaml(text, offset) : pathAtMarkdown(text, offset);
446
+ return { path: found.path.map(indexOrKey), part: found.part, ...found.range ? { range: place(found.range.offset, found.range.length) } : {} };
447
+ }
67
448
  if (!isJson(format)) return void 0;
68
449
  const root = parseText(text);
69
- const place = createLocator(text);
70
450
  const none = { path: [], part: "none" };
71
451
  if (!root || offset < root.offset || offset > root.offset + root.length) return none;
72
452
  const node = findNodeAtOffset(root, offset, true);
@@ -87,4 +467,4 @@ function pathAt(text, format, offset) {
87
467
  return { path: getNodePath(node), part: "value", range: range(node) };
88
468
  }
89
469
 
90
- export { locate, pathAt };
470
+ export { locate, pathAt, scanMarkdown };
package/dist/validator.js CHANGED
@@ -1,3 +1,3 @@
1
- export { DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, findValidationRule, validate, validateCatalogRecord, validationCategories, validationRules } from './chunk-NJWI6MPT.js';
1
+ export { DEFAULT_VALIDATION_THRESHOLDS, OPFValidationError, assertValid, assertValidCatalogRecord, findValidationRule, validate, validateCatalogRecord, validationCategories, validationRules } from './chunk-CIWC7DRZ.js';
2
2
  export { promotedRegionKeys } from './chunk-XRMV2GMB.js';
3
3
  import './chunk-F4HFDP6I.js';
package/dist/yaml.js CHANGED
@@ -1,7 +1,8 @@
1
- export { OPFYamlError, YAML_SCHEMA_URL, fromYaml, parseYamlData, scanYamlComments, toYaml } from './chunk-PB5X2VSV.js';
2
- import './chunk-DEI2M2H6.js';
3
- import './chunk-PXOXTJTN.js';
4
- import './chunk-NJWI6MPT.js';
1
+ export { OPFYamlError, YAML_SCHEMA_URL, fromYaml, parseYamlData, scanYamlComments, toYaml } from './chunk-WAZDP2WS.js';
2
+ import './chunk-RYZPBJLB.js';
3
+ import './chunk-KPALXWX3.js';
4
+ import './chunk-HPEZCAYC.js';
5
+ import './chunk-CIWC7DRZ.js';
5
6
  import './chunk-XRMV2GMB.js';
6
7
  import './chunk-EQ6S5SEZ.js';
7
8
  import './chunk-F4HFDP6I.js';
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@openpresentation/opf",
3
- "version": "0.26.3",
3
+ "version": "0.26.5",
4
4
  "description": "Canonical Open Presentation Format schemas, TypeScript types, local validation and composition; in Node, the file API and the CLI defaults register the pptx.gallery catalog of @openpresentation/gallery.",
5
5
  "license": "MIT",
6
6
  "author": "Open Presentation",
@@ -145,7 +145,7 @@
145
145
  "ajv-formats": "^3.0.1",
146
146
  "jsonc-parser": "3.3.1",
147
147
  "yaml": "^2.9.1",
148
- "@openpresentation/gallery": "^0.26.3"
148
+ "@openpresentation/gallery": "^0.26.5"
149
149
  },
150
150
  "devDependencies": {
151
151
  "@expo-google-fonts/arimo": "0.4.3",
@@ -165,8 +165,8 @@
165
165
  "typescript": "~5.9.3"
166
166
  },
167
167
  "peerDependencies": {
168
- "@openpresentation/opf-pptx": "^0.26.3",
169
- "@openpresentation/opf-render": "^0.26.3"
168
+ "@openpresentation/opf-pptx": "^0.26.5",
169
+ "@openpresentation/opf-render": "^0.26.5"
170
170
  },
171
171
  "peerDependenciesMeta": {
172
172
  "@openpresentation/opf-pptx": {
@@ -186,5 +186,5 @@
186
186
  "test:packed": "node test/packed-install-smoke.mjs",
187
187
  "pack:dry-run": "pnpm run build:deps && pnpm run build && npm pack --dry-run --cache /tmp/opf-npm-cache"
188
188
  },
189
- "gitHead": "570ebe0c803e9613f6b9f9fcca8160b38b16a826"
189
+ "gitHead": "750d120e715b6c4930906aa71322d092d057c58d"
190
190
  }