@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.
- package/README.md +3 -1
- package/dist/browser.js +14 -11
- package/dist/{chunk-NJWI6MPT.js → chunk-CIWC7DRZ.js} +1985 -366
- package/dist/{chunk-7RY7QWWJ.js → chunk-DXTPLVAK.js} +1 -1
- package/dist/{chunk-54OV2WQC.js → chunk-EFMR32A5.js} +1 -1
- package/dist/{chunk-PXOXTJTN.js → chunk-HPEZCAYC.js} +1 -1
- package/dist/{chunk-2ZQBMZTZ.js → chunk-K5Q3LLYK.js} +2 -2
- package/dist/chunk-KPALXWX3.js +712 -0
- package/dist/{chunk-34LIUOT7.js → chunk-L7YEVQHP.js} +6 -6
- package/dist/chunk-MD3CJ5YJ.js +452 -0
- package/dist/{chunk-WASENX2R.js → chunk-MLH5LIGF.js} +29 -647
- package/dist/chunk-RYZPBJLB.js +4 -0
- package/dist/{chunk-FXNUM2PN.js → chunk-STIYINEL.js} +4 -4
- package/dist/{chunk-YVNFACTC.js → chunk-TAV5S2JG.js} +1 -1
- package/dist/{chunk-GLLR3AQ5.js → chunk-UFEWQDQI.js} +1 -1
- package/dist/chunk-UY6SQVR2.js +639 -0
- package/dist/{chunk-PB5X2VSV.js → chunk-WAZDP2WS.js} +12 -20
- package/dist/{conversion-BjsKgxBZ.d.ts → conversion-C7o2EpDb.d.ts} +2 -2
- package/dist/conversion-PMJWLHDV.js +21 -0
- package/dist/convert.js +5 -5
- package/dist/deck.js +9 -7
- package/dist/diff.js +2 -2
- package/dist/docs.js +3 -3
- package/dist/explain-JSuESV-Y.d.ts +71 -0
- package/dist/index.d.ts +3 -2
- package/dist/index.js +18 -15
- package/dist/markdown.js +7 -5
- package/dist/node-engine.d.ts +2 -2
- package/dist/node-engine.js +18 -15
- package/dist/pagination.js +2 -2
- package/dist/patch.js +1 -1
- package/dist/schema.js +1 -1
- package/dist/source.d.ts +184 -5
- package/dist/source.js +391 -11
- package/dist/validator.js +1 -1
- package/dist/yaml.js +5 -4
- package/package.json +5 -5
- package/dist/chunk-DEI2M2H6.js +0 -194
- package/dist/conversion-F4UCOGR7.js +0 -18
package/dist/source.js
CHANGED
|
@@ -1,12 +1,379 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
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
|
|
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
|
|
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
|
-
|
|
41
|
-
|
|
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 ?
|
|
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-
|
|
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-
|
|
2
|
-
import './chunk-
|
|
3
|
-
import './chunk-
|
|
4
|
-
import './chunk-
|
|
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
|
+
"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.
|
|
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.
|
|
169
|
-
"@openpresentation/opf-render": "^0.26.
|
|
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": "
|
|
189
|
+
"gitHead": "750d120e715b6c4930906aa71322d092d057c58d"
|
|
190
190
|
}
|