@ericsanchezok/synergy-util 2.4.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/binary.d.ts +7 -0
- package/dist/binary.js +40 -0
- package/dist/browser-protocol.d.ts +97 -0
- package/dist/browser-protocol.js +51 -0
- package/dist/capability.d.ts +289 -0
- package/dist/capability.js +841 -0
- package/dist/encode.d.ts +4 -0
- package/dist/encode.js +28 -0
- package/dist/error.d.ts +182 -0
- package/dist/error.js +43 -0
- package/dist/fn.d.ts +6 -0
- package/dist/fn.js +9 -0
- package/dist/identifier.d.ts +5 -0
- package/dist/identifier.js +41 -0
- package/dist/iife.d.ts +1 -0
- package/dist/iife.js +3 -0
- package/dist/json.d.ts +1 -0
- package/dist/json.js +209 -0
- package/dist/lazy.d.ts +1 -0
- package/dist/lazy.js +11 -0
- package/dist/model-limit.d.ts +37 -0
- package/dist/model-limit.js +35 -0
- package/dist/note-markdown.d.ts +24 -0
- package/dist/note-markdown.js +630 -0
- package/dist/path.d.ts +39 -0
- package/dist/path.js +84 -0
- package/dist/plugin-policy.d.ts +100 -0
- package/dist/plugin-policy.js +240 -0
- package/dist/retry.d.ts +8 -0
- package/dist/retry.js +33 -0
- package/package.json +22 -0
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
export var NoteMarkdown;
|
|
2
|
+
(function (NoteMarkdown) {
|
|
3
|
+
const DEFAULT_PREVIEW_BLOCKS = 16;
|
|
4
|
+
function renderMarks(text, marks) {
|
|
5
|
+
if (!marks || marks.length === 0)
|
|
6
|
+
return text;
|
|
7
|
+
let result = text;
|
|
8
|
+
for (const mark of marks) {
|
|
9
|
+
switch (mark.type) {
|
|
10
|
+
case "bold":
|
|
11
|
+
result = `**${result}**`;
|
|
12
|
+
break;
|
|
13
|
+
case "italic":
|
|
14
|
+
result = `*${result}*`;
|
|
15
|
+
break;
|
|
16
|
+
case "code":
|
|
17
|
+
result = `\`${result}\``;
|
|
18
|
+
break;
|
|
19
|
+
case "strike":
|
|
20
|
+
result = `~~${result}~~`;
|
|
21
|
+
break;
|
|
22
|
+
case "link":
|
|
23
|
+
result = `[${result}](${mark.attrs?.href ?? ""})`;
|
|
24
|
+
break;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
function renderInline(nodes) {
|
|
30
|
+
let result = "";
|
|
31
|
+
for (const node of nodes) {
|
|
32
|
+
if (node.type === "text") {
|
|
33
|
+
result += renderMarks(node.text ?? "", node.marks);
|
|
34
|
+
}
|
|
35
|
+
else if (node.type === "hardBreak") {
|
|
36
|
+
result += "\n";
|
|
37
|
+
}
|
|
38
|
+
else if (node.type === "inlineMath") {
|
|
39
|
+
const latex = node.attrs?.latex ?? "";
|
|
40
|
+
result += node.attrs?.display === "yes" ? `$$\n${latex}\n$$` : `$${latex}$`;
|
|
41
|
+
}
|
|
42
|
+
else if (node.type === "image") {
|
|
43
|
+
const alt = node.attrs?.alt ?? "";
|
|
44
|
+
const src = node.attrs?.src ?? "";
|
|
45
|
+
result += ``;
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
return result;
|
|
49
|
+
}
|
|
50
|
+
function renderBlock(node, indent = "") {
|
|
51
|
+
switch (node.type) {
|
|
52
|
+
case "doc":
|
|
53
|
+
return renderChildren(node.content ?? []);
|
|
54
|
+
case "paragraph":
|
|
55
|
+
return indent + renderInline(node.content ?? []);
|
|
56
|
+
case "heading": {
|
|
57
|
+
const level = node.attrs?.level ?? 1;
|
|
58
|
+
const prefix = "#".repeat(level);
|
|
59
|
+
return `${prefix} ${renderInline(node.content ?? [])}`;
|
|
60
|
+
}
|
|
61
|
+
case "bulletList":
|
|
62
|
+
return (node.content ?? []).map((item) => renderListItem(item, indent, "- ")).join("\n");
|
|
63
|
+
case "orderedList":
|
|
64
|
+
return (node.content ?? []).map((item, i) => renderListItem(item, indent, `${i + 1}. `)).join("\n");
|
|
65
|
+
case "taskList":
|
|
66
|
+
return (node.content ?? []).map((item) => renderTaskItem(item, indent)).join("\n");
|
|
67
|
+
case "codeBlock": {
|
|
68
|
+
const lang = node.attrs?.language ?? "";
|
|
69
|
+
const code = renderInline(node.content ?? []);
|
|
70
|
+
return `\`\`\`${lang}\n${code}\n\`\`\``;
|
|
71
|
+
}
|
|
72
|
+
case "blockquote":
|
|
73
|
+
return (node.content ?? [])
|
|
74
|
+
.map((child) => renderBlock(child))
|
|
75
|
+
.join("\n")
|
|
76
|
+
.split("\n")
|
|
77
|
+
.map((line) => `> ${line}`)
|
|
78
|
+
.join("\n");
|
|
79
|
+
case "horizontalRule":
|
|
80
|
+
return "---";
|
|
81
|
+
case "image": {
|
|
82
|
+
const alt = node.attrs?.alt ?? "";
|
|
83
|
+
const src = node.attrs?.src ?? "";
|
|
84
|
+
return ``;
|
|
85
|
+
}
|
|
86
|
+
case "table":
|
|
87
|
+
return renderTable(node);
|
|
88
|
+
default:
|
|
89
|
+
if (node.content)
|
|
90
|
+
return renderChildren(node.content);
|
|
91
|
+
if (node.text)
|
|
92
|
+
return renderMarks(node.text, node.marks);
|
|
93
|
+
return "";
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
function renderListItem(node, indent, bullet) {
|
|
97
|
+
const children = node.content ?? [];
|
|
98
|
+
const lines = [];
|
|
99
|
+
for (let i = 0; i < children.length; i++) {
|
|
100
|
+
const child = children[i];
|
|
101
|
+
if (i === 0) {
|
|
102
|
+
lines.push(indent + bullet + renderBlock(child).trimStart());
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
const nested = renderBlock(child, indent + " ".repeat(bullet.length));
|
|
106
|
+
lines.push(nested);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return lines.join("\n");
|
|
110
|
+
}
|
|
111
|
+
function renderTaskItem(node, indent) {
|
|
112
|
+
const checked = node.attrs?.checked ? "x" : " ";
|
|
113
|
+
const children = node.content ?? [];
|
|
114
|
+
const text = children
|
|
115
|
+
.map((child) => renderBlock(child))
|
|
116
|
+
.join("\n")
|
|
117
|
+
.trimStart();
|
|
118
|
+
return `${indent}- [${checked}] ${text}`;
|
|
119
|
+
}
|
|
120
|
+
function renderTable(node) {
|
|
121
|
+
const rows = node.content ?? [];
|
|
122
|
+
if (rows.length === 0)
|
|
123
|
+
return "";
|
|
124
|
+
const matrix = [];
|
|
125
|
+
for (const row of rows) {
|
|
126
|
+
const cells = (row.content ?? []).map((cell) => {
|
|
127
|
+
const inner = (cell.content ?? []).map((child) => renderBlock(child)).join(" ");
|
|
128
|
+
return inner.trim();
|
|
129
|
+
});
|
|
130
|
+
matrix.push(cells);
|
|
131
|
+
}
|
|
132
|
+
const colCount = Math.max(...matrix.map((r) => r.length));
|
|
133
|
+
const widths = Array.from({ length: colCount }, () => 3);
|
|
134
|
+
for (const row of matrix) {
|
|
135
|
+
for (let i = 0; i < row.length; i++) {
|
|
136
|
+
widths[i] = Math.max(widths[i], row[i].length);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
const formatRow = (cells) => {
|
|
140
|
+
const padded = widths.map((w, i) => (cells[i] ?? "").padEnd(w));
|
|
141
|
+
return `| ${padded.join(" | ")} |`;
|
|
142
|
+
};
|
|
143
|
+
const lines = [];
|
|
144
|
+
lines.push(formatRow(matrix[0] ?? []));
|
|
145
|
+
lines.push(`| ${widths.map((w) => "-".repeat(w)).join(" | ")} |`);
|
|
146
|
+
for (let i = 1; i < matrix.length; i++) {
|
|
147
|
+
lines.push(formatRow(matrix[i]));
|
|
148
|
+
}
|
|
149
|
+
return lines.join("\n");
|
|
150
|
+
}
|
|
151
|
+
function renderChildren(nodes) {
|
|
152
|
+
return nodes.map((node) => renderBlock(node)).join("\n\n");
|
|
153
|
+
}
|
|
154
|
+
function toMarkdown(content) {
|
|
155
|
+
if (!content || typeof content !== "object")
|
|
156
|
+
return "";
|
|
157
|
+
return renderBlock(content).trim();
|
|
158
|
+
}
|
|
159
|
+
NoteMarkdown.toMarkdown = toMarkdown;
|
|
160
|
+
function fromMarkdown(markdown) {
|
|
161
|
+
const lines = markdown.split("\n");
|
|
162
|
+
const blocks = parseBlocks(lines, 0, lines.length);
|
|
163
|
+
return { type: "doc", content: blocks.length > 0 ? blocks : [{ type: "paragraph" }] };
|
|
164
|
+
}
|
|
165
|
+
NoteMarkdown.fromMarkdown = fromMarkdown;
|
|
166
|
+
function parseBlocks(lines, start, end) {
|
|
167
|
+
const blocks = [];
|
|
168
|
+
let i = start;
|
|
169
|
+
while (i < end) {
|
|
170
|
+
const line = lines[i];
|
|
171
|
+
if (line.trim() === "") {
|
|
172
|
+
i++;
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (/^```/.test(line)) {
|
|
176
|
+
const lang = line.slice(3).trim();
|
|
177
|
+
const codeLines = [];
|
|
178
|
+
i++;
|
|
179
|
+
while (i < end && !/^```\s*$/.test(lines[i])) {
|
|
180
|
+
codeLines.push(lines[i]);
|
|
181
|
+
i++;
|
|
182
|
+
}
|
|
183
|
+
i++;
|
|
184
|
+
const node = { type: "codeBlock", content: [{ type: "text", text: codeLines.join("\n") }] };
|
|
185
|
+
if (lang)
|
|
186
|
+
node.attrs = { language: lang };
|
|
187
|
+
blocks.push(node);
|
|
188
|
+
continue;
|
|
189
|
+
}
|
|
190
|
+
const headingMatch = line.match(/^(#{1,6})\s+(.*)$/);
|
|
191
|
+
if (headingMatch) {
|
|
192
|
+
blocks.push({
|
|
193
|
+
type: "heading",
|
|
194
|
+
attrs: { level: headingMatch[1].length },
|
|
195
|
+
content: parseInline(headingMatch[2]),
|
|
196
|
+
});
|
|
197
|
+
i++;
|
|
198
|
+
continue;
|
|
199
|
+
}
|
|
200
|
+
if (/^---\s*$/.test(line) || /^\*\*\*\s*$/.test(line) || /^___\s*$/.test(line)) {
|
|
201
|
+
blocks.push({ type: "horizontalRule" });
|
|
202
|
+
i++;
|
|
203
|
+
continue;
|
|
204
|
+
}
|
|
205
|
+
// Block math: $$ ... $$
|
|
206
|
+
if (/^\$\$/.test(line)) {
|
|
207
|
+
const mathLines = [];
|
|
208
|
+
i++; // skip opening $$
|
|
209
|
+
while (i < end && !/^\$\$/.test(lines[i])) {
|
|
210
|
+
mathLines.push(lines[i]);
|
|
211
|
+
i++;
|
|
212
|
+
}
|
|
213
|
+
i++; // skip closing $$
|
|
214
|
+
blocks.push({
|
|
215
|
+
type: "paragraph",
|
|
216
|
+
content: [
|
|
217
|
+
{
|
|
218
|
+
type: "inlineMath",
|
|
219
|
+
attrs: { latex: mathLines.join("\n").trim(), evaluate: "no", display: "yes" },
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
});
|
|
223
|
+
continue;
|
|
224
|
+
}
|
|
225
|
+
if (/^\|/.test(line)) {
|
|
226
|
+
const tableResult = parseTable(lines, i, end);
|
|
227
|
+
blocks.push(tableResult.node);
|
|
228
|
+
i = tableResult.nextIndex;
|
|
229
|
+
continue;
|
|
230
|
+
}
|
|
231
|
+
if (/^>\s?/.test(line)) {
|
|
232
|
+
const quoteLines = [];
|
|
233
|
+
while (i < end && /^>\s?/.test(lines[i])) {
|
|
234
|
+
quoteLines.push(lines[i].replace(/^>\s?/, ""));
|
|
235
|
+
i++;
|
|
236
|
+
}
|
|
237
|
+
blocks.push({ type: "blockquote", content: parseBlocks(quoteLines, 0, quoteLines.length) });
|
|
238
|
+
continue;
|
|
239
|
+
}
|
|
240
|
+
if (/^[-*]\s\[[ x]\]\s/.test(line)) {
|
|
241
|
+
const taskResult = parseTaskList(lines, i, end);
|
|
242
|
+
blocks.push(taskResult.node);
|
|
243
|
+
i = taskResult.nextIndex;
|
|
244
|
+
continue;
|
|
245
|
+
}
|
|
246
|
+
if (/^[-*]\s/.test(line)) {
|
|
247
|
+
const listResult = parseBulletList(lines, i, end);
|
|
248
|
+
blocks.push(listResult.node);
|
|
249
|
+
i = listResult.nextIndex;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (/^\d+\.\s/.test(line)) {
|
|
253
|
+
const listResult = parseOrderedList(lines, i, end);
|
|
254
|
+
blocks.push(listResult.node);
|
|
255
|
+
i = listResult.nextIndex;
|
|
256
|
+
continue;
|
|
257
|
+
}
|
|
258
|
+
const imgMatch = line.match(/^!\[([^\]]*)\]\(([^)]+)\)\s*$/);
|
|
259
|
+
if (imgMatch) {
|
|
260
|
+
blocks.push({ type: "image", attrs: { src: imgMatch[2], alt: imgMatch[1] } });
|
|
261
|
+
i++;
|
|
262
|
+
continue;
|
|
263
|
+
}
|
|
264
|
+
const paraLines = [line];
|
|
265
|
+
i++;
|
|
266
|
+
while (i < end && lines[i].trim() !== "" && !isBlockStart(lines[i])) {
|
|
267
|
+
paraLines.push(lines[i]);
|
|
268
|
+
i++;
|
|
269
|
+
}
|
|
270
|
+
blocks.push({ type: "paragraph", content: parseInline(paraLines.join("\n")) });
|
|
271
|
+
}
|
|
272
|
+
return blocks;
|
|
273
|
+
}
|
|
274
|
+
function isBlockStart(line) {
|
|
275
|
+
if (/^#{1,6}\s/.test(line))
|
|
276
|
+
return true;
|
|
277
|
+
if (/^```/.test(line))
|
|
278
|
+
return true;
|
|
279
|
+
if (/^\$\$/.test(line))
|
|
280
|
+
return true;
|
|
281
|
+
if (/^---\s*$/.test(line) || /^\*\*\*\s*$/.test(line) || /^___\s*$/.test(line))
|
|
282
|
+
return true;
|
|
283
|
+
if (/^>\s?/.test(line))
|
|
284
|
+
return true;
|
|
285
|
+
if (/^[-*]\s/.test(line))
|
|
286
|
+
return true;
|
|
287
|
+
if (/^\d+\.\s/.test(line))
|
|
288
|
+
return true;
|
|
289
|
+
if (/^\|/.test(line))
|
|
290
|
+
return true;
|
|
291
|
+
if (/^!\[/.test(line))
|
|
292
|
+
return true;
|
|
293
|
+
return false;
|
|
294
|
+
}
|
|
295
|
+
function parseBulletList(lines, start, end) {
|
|
296
|
+
const items = [];
|
|
297
|
+
let i = start;
|
|
298
|
+
while (i < end && /^[-*]\s/.test(lines[i])) {
|
|
299
|
+
const text = lines[i].replace(/^[-*]\s/, "");
|
|
300
|
+
const itemContent = [text];
|
|
301
|
+
i++;
|
|
302
|
+
while (i < end && /^\s{2,}/.test(lines[i]) && !/^[-*]\s/.test(lines[i])) {
|
|
303
|
+
itemContent.push(lines[i].trimStart());
|
|
304
|
+
i++;
|
|
305
|
+
}
|
|
306
|
+
items.push({ type: "listItem", content: [{ type: "paragraph", content: parseInline(itemContent.join("\n")) }] });
|
|
307
|
+
}
|
|
308
|
+
return { node: { type: "bulletList", content: items }, nextIndex: i };
|
|
309
|
+
}
|
|
310
|
+
function parseOrderedList(lines, start, end) {
|
|
311
|
+
const items = [];
|
|
312
|
+
let i = start;
|
|
313
|
+
while (i < end && /^\d+\.\s/.test(lines[i])) {
|
|
314
|
+
const text = lines[i].replace(/^\d+\.\s/, "");
|
|
315
|
+
const itemContent = [text];
|
|
316
|
+
i++;
|
|
317
|
+
while (i < end && /^\s{2,}/.test(lines[i]) && !/^\d+\.\s/.test(lines[i])) {
|
|
318
|
+
itemContent.push(lines[i].trimStart());
|
|
319
|
+
i++;
|
|
320
|
+
}
|
|
321
|
+
items.push({ type: "listItem", content: [{ type: "paragraph", content: parseInline(itemContent.join("\n")) }] });
|
|
322
|
+
}
|
|
323
|
+
return { node: { type: "orderedList", content: items }, nextIndex: i };
|
|
324
|
+
}
|
|
325
|
+
function parseTaskList(lines, start, end) {
|
|
326
|
+
const items = [];
|
|
327
|
+
let i = start;
|
|
328
|
+
while (i < end && /^[-*]\s\[[ x]\]\s/.test(lines[i])) {
|
|
329
|
+
const checked = /^[-*]\s\[x\]\s/i.test(lines[i]);
|
|
330
|
+
const text = lines[i].replace(/^[-*]\s\[[ x]\]\s/i, "");
|
|
331
|
+
items.push({
|
|
332
|
+
type: "taskItem",
|
|
333
|
+
attrs: { checked },
|
|
334
|
+
content: [{ type: "paragraph", content: parseInline(text) }],
|
|
335
|
+
});
|
|
336
|
+
i++;
|
|
337
|
+
}
|
|
338
|
+
return { node: { type: "taskList", content: items }, nextIndex: i };
|
|
339
|
+
}
|
|
340
|
+
function parseTable(lines, start, end) {
|
|
341
|
+
const rows = [];
|
|
342
|
+
let i = start;
|
|
343
|
+
while (i < end && /^\|/.test(lines[i])) {
|
|
344
|
+
const cells = lines[i]
|
|
345
|
+
.replace(/^\|/, "")
|
|
346
|
+
.replace(/\|$/, "")
|
|
347
|
+
.split("|")
|
|
348
|
+
.map((c) => c.trim());
|
|
349
|
+
if (cells.every((c) => /^-+$/.test(c))) {
|
|
350
|
+
i++;
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const isHeader = rows.length === 0;
|
|
354
|
+
const cellNodes = cells.map((cell) => ({
|
|
355
|
+
type: isHeader ? "tableHeader" : "tableCell",
|
|
356
|
+
content: [{ type: "paragraph", content: parseInline(cell) }],
|
|
357
|
+
}));
|
|
358
|
+
rows.push({ type: "tableRow", content: cellNodes });
|
|
359
|
+
i++;
|
|
360
|
+
}
|
|
361
|
+
return { node: { type: "table", content: rows }, nextIndex: i };
|
|
362
|
+
}
|
|
363
|
+
function parseInline(text) {
|
|
364
|
+
if (!text)
|
|
365
|
+
return [];
|
|
366
|
+
const nodes = [];
|
|
367
|
+
const regex = /!\[([^\]]*)\]\(([^)]+)\)|\[([^\]]*)\]\(([^)]+)\)|`([^`]+)`|\*\*\*([^*]+)\*\*\*|\*\*([^*]+)\*\*|\*([^*]+)\*|~~([^~]+)~~|\$([^$]+)\$|(\n)/g;
|
|
368
|
+
let lastIndex = 0;
|
|
369
|
+
let match;
|
|
370
|
+
while ((match = regex.exec(text)) !== null) {
|
|
371
|
+
if (match.index > lastIndex) {
|
|
372
|
+
nodes.push({ type: "text", text: text.slice(lastIndex, match.index) });
|
|
373
|
+
}
|
|
374
|
+
if (match[1] !== undefined || match[2] !== undefined) {
|
|
375
|
+
nodes.push({ type: "image", attrs: { src: match[2], alt: match[1] ?? "" } });
|
|
376
|
+
}
|
|
377
|
+
else if (match[3] !== undefined) {
|
|
378
|
+
nodes.push({ type: "text", text: match[3], marks: [{ type: "link", attrs: { href: match[4] } }] });
|
|
379
|
+
}
|
|
380
|
+
else if (match[5] !== undefined) {
|
|
381
|
+
nodes.push({ type: "text", text: match[5], marks: [{ type: "code" }] });
|
|
382
|
+
}
|
|
383
|
+
else if (match[6] !== undefined) {
|
|
384
|
+
nodes.push({ type: "text", text: match[6], marks: [{ type: "bold" }, { type: "italic" }] });
|
|
385
|
+
}
|
|
386
|
+
else if (match[7] !== undefined) {
|
|
387
|
+
nodes.push({ type: "text", text: match[7], marks: [{ type: "bold" }] });
|
|
388
|
+
}
|
|
389
|
+
else if (match[8] !== undefined) {
|
|
390
|
+
nodes.push({ type: "text", text: match[8], marks: [{ type: "italic" }] });
|
|
391
|
+
}
|
|
392
|
+
else if (match[9] !== undefined) {
|
|
393
|
+
nodes.push({ type: "text", text: match[9], marks: [{ type: "strike" }] });
|
|
394
|
+
}
|
|
395
|
+
else if (match[10] !== undefined) {
|
|
396
|
+
// Inline math: $...$
|
|
397
|
+
nodes.push({ type: "inlineMath", attrs: { latex: match[10], evaluate: "no", display: "no" } });
|
|
398
|
+
}
|
|
399
|
+
else if (match[11] !== undefined) {
|
|
400
|
+
nodes.push({ type: "hardBreak" });
|
|
401
|
+
}
|
|
402
|
+
lastIndex = regex.lastIndex;
|
|
403
|
+
}
|
|
404
|
+
if (lastIndex < text.length) {
|
|
405
|
+
nodes.push({ type: "text", text: text.slice(lastIndex) });
|
|
406
|
+
}
|
|
407
|
+
return nodes.length > 0 ? nodes : [{ type: "text", text }];
|
|
408
|
+
}
|
|
409
|
+
// --- Safe HTML preview (for metadata thumbnail generation) ---
|
|
410
|
+
function escapeHtml(text) {
|
|
411
|
+
return text.replace(/&/g, "&").replace(/</g, "<").replace(/>/g, ">").replace(/"/g, """);
|
|
412
|
+
}
|
|
413
|
+
function trustedPreviewImageSrc(src) {
|
|
414
|
+
if (typeof src !== "string")
|
|
415
|
+
return undefined;
|
|
416
|
+
const trimmed = src.trim();
|
|
417
|
+
if (!trimmed)
|
|
418
|
+
return undefined;
|
|
419
|
+
if (/^data:image\/(?:png|jpe?g|gif|webp);base64,/i.test(trimmed))
|
|
420
|
+
return trimmed;
|
|
421
|
+
if (trimmed.startsWith("/asset/") || trimmed.startsWith("/assets/"))
|
|
422
|
+
return trimmed;
|
|
423
|
+
try {
|
|
424
|
+
const url = new URL(trimmed);
|
|
425
|
+
if ((url.protocol === "http:" || url.protocol === "https:") && url.pathname.startsWith("/asset/")) {
|
|
426
|
+
return trimmed;
|
|
427
|
+
}
|
|
428
|
+
if ((url.protocol === "http:" || url.protocol === "https:") && url.pathname.startsWith("/assets/")) {
|
|
429
|
+
return trimmed;
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
catch {
|
|
433
|
+
return undefined;
|
|
434
|
+
}
|
|
435
|
+
return undefined;
|
|
436
|
+
}
|
|
437
|
+
function renderPreviewMediaPlaceholder(kind, label) {
|
|
438
|
+
const detail = label?.trim();
|
|
439
|
+
return `<div class="note-preview-media-placeholder"><span>${escapeHtml(kind)}</span>${detail ? `<small>${escapeHtml(detail)}</small>` : ""}</div>`;
|
|
440
|
+
}
|
|
441
|
+
function normalizePreviewText(text) {
|
|
442
|
+
return text.replace(/\s+/g, " ").trim().toLowerCase();
|
|
443
|
+
}
|
|
444
|
+
function previewPlainText(node) {
|
|
445
|
+
switch (node.type) {
|
|
446
|
+
case "paragraph":
|
|
447
|
+
case "heading":
|
|
448
|
+
return (node.content ?? []).map(previewPlainText).join("");
|
|
449
|
+
case "text":
|
|
450
|
+
return node.text ?? "";
|
|
451
|
+
case "hardBreak":
|
|
452
|
+
return " ";
|
|
453
|
+
case "inlineMath":
|
|
454
|
+
return node.attrs?.latex ?? "";
|
|
455
|
+
case "image":
|
|
456
|
+
return node.attrs?.alt ?? "";
|
|
457
|
+
default:
|
|
458
|
+
return "";
|
|
459
|
+
}
|
|
460
|
+
}
|
|
461
|
+
function renderPreviewImage(node, mode) {
|
|
462
|
+
const src = trustedPreviewImageSrc(node.attrs?.src);
|
|
463
|
+
const alt = typeof node.attrs?.alt === "string" ? node.attrs.alt : "";
|
|
464
|
+
if (!src) {
|
|
465
|
+
return mode === "inline"
|
|
466
|
+
? `<span class="note-preview-media-chip">Image</span>`
|
|
467
|
+
: renderPreviewMediaPlaceholder("Image", alt || "Preview unavailable");
|
|
468
|
+
}
|
|
469
|
+
const img = `<img src="${escapeHtml(src)}" alt="${escapeHtml(alt)}" loading="lazy" decoding="async">`;
|
|
470
|
+
if (mode === "inline")
|
|
471
|
+
return `<span class="note-preview-image-inline">${img}</span>`;
|
|
472
|
+
const caption = alt ? `<figcaption>${escapeHtml(alt)}</figcaption>` : "";
|
|
473
|
+
return `<figure class="note-preview-figure">${img}${caption}</figure>`;
|
|
474
|
+
}
|
|
475
|
+
function renderPreviewInline(nodes) {
|
|
476
|
+
let result = "";
|
|
477
|
+
for (const node of nodes) {
|
|
478
|
+
if (node.type === "text") {
|
|
479
|
+
let text = escapeHtml(node.text ?? "");
|
|
480
|
+
if (node.marks) {
|
|
481
|
+
for (const mark of node.marks) {
|
|
482
|
+
switch (mark.type) {
|
|
483
|
+
case "bold":
|
|
484
|
+
text = `<strong>${text}</strong>`;
|
|
485
|
+
break;
|
|
486
|
+
case "italic":
|
|
487
|
+
text = `<em>${text}</em>`;
|
|
488
|
+
break;
|
|
489
|
+
case "code":
|
|
490
|
+
text = `<code>${text}</code>`;
|
|
491
|
+
break;
|
|
492
|
+
case "strike":
|
|
493
|
+
text = `<s>${text}</s>`;
|
|
494
|
+
break;
|
|
495
|
+
case "link":
|
|
496
|
+
text = `<span class="note-preview-link">${text}</span>`;
|
|
497
|
+
break;
|
|
498
|
+
}
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
result += text;
|
|
502
|
+
}
|
|
503
|
+
else if (node.type === "hardBreak") {
|
|
504
|
+
result += "<br>";
|
|
505
|
+
}
|
|
506
|
+
else if (node.type === "inlineMath") {
|
|
507
|
+
const latex = escapeHtml(node.attrs?.latex ?? "");
|
|
508
|
+
const display = node.attrs?.display === "yes";
|
|
509
|
+
result += `<span class="${display ? "note-preview-math note-preview-math--display" : "note-preview-math"}">${display ? "$$" : "$"}${latex}${display ? "$$" : "$"}</span>`;
|
|
510
|
+
}
|
|
511
|
+
else if (node.type === "image") {
|
|
512
|
+
result += renderPreviewImage(node, "inline");
|
|
513
|
+
}
|
|
514
|
+
}
|
|
515
|
+
return result;
|
|
516
|
+
}
|
|
517
|
+
function renderPreviewCell(node) {
|
|
518
|
+
if (node.type === "paragraph")
|
|
519
|
+
return renderPreviewInline(node.content ?? []);
|
|
520
|
+
const firstChild = node.content?.[0];
|
|
521
|
+
if (firstChild?.type === "paragraph")
|
|
522
|
+
return renderPreviewInline(firstChild.content ?? []);
|
|
523
|
+
if (node.content)
|
|
524
|
+
return renderPreviewHtml(node.content, 2);
|
|
525
|
+
return renderPreviewInline([node]);
|
|
526
|
+
}
|
|
527
|
+
function renderPreviewTable(node) {
|
|
528
|
+
const rows = node.content ?? [];
|
|
529
|
+
const visibleRows = rows.slice(0, 4);
|
|
530
|
+
const html = visibleRows
|
|
531
|
+
.map((row) => {
|
|
532
|
+
const cells = (row.content ?? []).slice(0, 4);
|
|
533
|
+
return `<tr>${cells
|
|
534
|
+
.map((cell) => {
|
|
535
|
+
const tag = cell.type === "tableHeader" ? "th" : "td";
|
|
536
|
+
return `<${tag}>${renderPreviewCell(cell)}</${tag}>`;
|
|
537
|
+
})
|
|
538
|
+
.join("")}</tr>`;
|
|
539
|
+
})
|
|
540
|
+
.join("");
|
|
541
|
+
const overflow = rows.length > visibleRows.length
|
|
542
|
+
? `<div class="note-preview-table-more">+${rows.length - visibleRows.length} rows</div>`
|
|
543
|
+
: "";
|
|
544
|
+
return `<div class="note-preview-table-wrap"><table>${html}</table>${overflow}</div>`;
|
|
545
|
+
}
|
|
546
|
+
function renderPreviewBlock(node) {
|
|
547
|
+
switch (node.type) {
|
|
548
|
+
case "paragraph":
|
|
549
|
+
return `<p>${renderPreviewInline(node.content ?? [])}</p>`;
|
|
550
|
+
case "heading": {
|
|
551
|
+
const level = Math.min(node.attrs?.level ?? 1, 6);
|
|
552
|
+
return `<h${level}>${renderPreviewInline(node.content ?? [])}</h${level}>`;
|
|
553
|
+
}
|
|
554
|
+
case "bulletList":
|
|
555
|
+
return `<ul>${(node.content ?? [])
|
|
556
|
+
.map((item) => `<li>${renderPreviewBlock((item.content ?? [])[0] ?? { type: "paragraph", content: [] })}</li>`)
|
|
557
|
+
.join("")}</ul>`;
|
|
558
|
+
case "orderedList":
|
|
559
|
+
return `<ol>${(node.content ?? [])
|
|
560
|
+
.map((item) => `<li>${renderPreviewBlock((item.content ?? [])[0] ?? { type: "paragraph", content: [] })}</li>`)
|
|
561
|
+
.join("")}</ol>`;
|
|
562
|
+
case "taskList":
|
|
563
|
+
return `<ul class="note-preview-task-list">${(node.content ?? [])
|
|
564
|
+
.map((item) => {
|
|
565
|
+
const checked = item.attrs?.checked ? " checked" : "";
|
|
566
|
+
const inner = renderPreviewBlock((item.content ?? [])[0] ?? { type: "paragraph", content: [] });
|
|
567
|
+
return `<li><input type="checkbox"${checked} disabled>${inner}</li>`;
|
|
568
|
+
})
|
|
569
|
+
.join("")}</ul>`;
|
|
570
|
+
case "blockquote":
|
|
571
|
+
return `<blockquote>${renderPreviewHtml(node.content ?? [], 10)}</blockquote>`;
|
|
572
|
+
case "codeBlock": {
|
|
573
|
+
const rawCode = (node.content ?? []).map((c) => c.text ?? "").join("\n");
|
|
574
|
+
const lines = rawCode.split("\n");
|
|
575
|
+
const preview = lines.length > 4 ? [...lines.slice(0, 4), "…"].join("\n") : rawCode;
|
|
576
|
+
return `<pre><code>${escapeHtml(preview)}</code></pre>`;
|
|
577
|
+
}
|
|
578
|
+
case "horizontalRule":
|
|
579
|
+
return `<hr>`;
|
|
580
|
+
case "image":
|
|
581
|
+
return renderPreviewImage(node, "block");
|
|
582
|
+
case "video":
|
|
583
|
+
return renderPreviewMediaPlaceholder("Video");
|
|
584
|
+
case "mermaid": {
|
|
585
|
+
const firstLine = String(node.attrs?.content ?? "")
|
|
586
|
+
.trim()
|
|
587
|
+
.split("\n")[0];
|
|
588
|
+
return `<div class="note-preview-diagram"><span>Diagram</span>${firstLine ? `<code>${escapeHtml(firstLine)}</code>` : ""}</div>`;
|
|
589
|
+
}
|
|
590
|
+
case "table":
|
|
591
|
+
return renderPreviewTable(node);
|
|
592
|
+
default:
|
|
593
|
+
if (node.content)
|
|
594
|
+
return renderPreviewHtml(node.content, 10);
|
|
595
|
+
return "";
|
|
596
|
+
}
|
|
597
|
+
}
|
|
598
|
+
function renderPreviewHtml(nodes, maxBlocks, options) {
|
|
599
|
+
let count = 0;
|
|
600
|
+
let result = "";
|
|
601
|
+
const normalizedTitle = normalizePreviewText(options?.title ?? "");
|
|
602
|
+
for (let index = 0; index < nodes.length; index++) {
|
|
603
|
+
const node = nodes[index];
|
|
604
|
+
if (index === 0 && normalizedTitle && normalizePreviewText(previewPlainText(node)) === normalizedTitle) {
|
|
605
|
+
continue;
|
|
606
|
+
}
|
|
607
|
+
if (count >= maxBlocks)
|
|
608
|
+
break;
|
|
609
|
+
const html = renderPreviewBlock(node);
|
|
610
|
+
if (html)
|
|
611
|
+
count++;
|
|
612
|
+
result += html;
|
|
613
|
+
}
|
|
614
|
+
return result;
|
|
615
|
+
}
|
|
616
|
+
/**
|
|
617
|
+
* Generate safe, escaped HTML snippet from Tiptap JSON for note card thumbnails.
|
|
618
|
+
* Produces a compact multi-block preview. Text is HTML-escaped, media is limited
|
|
619
|
+
* to trusted image sources, and no external HTML is rendered.
|
|
620
|
+
*/
|
|
621
|
+
function toPreviewHtml(content, options) {
|
|
622
|
+
if (!content || typeof content !== "object")
|
|
623
|
+
return "";
|
|
624
|
+
const doc = content;
|
|
625
|
+
if (doc.type !== "doc")
|
|
626
|
+
return "";
|
|
627
|
+
return renderPreviewHtml(doc.content ?? [], options?.maxBlocks ?? DEFAULT_PREVIEW_BLOCKS, { title: options?.title });
|
|
628
|
+
}
|
|
629
|
+
NoteMarkdown.toPreviewHtml = toPreviewHtml;
|
|
630
|
+
})(NoteMarkdown || (NoteMarkdown = {}));
|
package/dist/path.d.ts
ADDED
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Extract the last path segment (filename / directory name).
|
|
3
|
+
* Handles both forward slash and backslash separators.
|
|
4
|
+
*/
|
|
5
|
+
export declare function getFilename(path: string | undefined): string;
|
|
6
|
+
/**
|
|
7
|
+
* Extract the parent directory of a path, with a trailing separator.
|
|
8
|
+
* Handles both forward slash and backslash — backslashes are normalized to forward slashes in output.
|
|
9
|
+
*
|
|
10
|
+
* "/home/user/projects" → "/home/user/"
|
|
11
|
+
* "C:\\Users\\projects" → "C:/Users/"
|
|
12
|
+
* "~" → ""
|
|
13
|
+
* "/" → "/"
|
|
14
|
+
*/
|
|
15
|
+
export declare function getDirectory(path: string | undefined): string;
|
|
16
|
+
/**
|
|
17
|
+
* Return the file extension (last dot-segment), or the full path if no dot exists.
|
|
18
|
+
*/
|
|
19
|
+
export declare function getFileExtension(path: string | undefined): string;
|
|
20
|
+
/**
|
|
21
|
+
* Parse a user-typed path string into a parent-directory + search-query pair.
|
|
22
|
+
*
|
|
23
|
+
* Rules (in order):
|
|
24
|
+
* 1. Empty input → homeDir with no query
|
|
25
|
+
* 2. Expand "~" and "~/..." using homeDir
|
|
26
|
+
* 3. Normalize backslashes to forward slashes
|
|
27
|
+
* 4. Absolute paths (Unix `/`, Windows `C:/`, UNC `//`) → split on last `/`; Windows drive roots stay rooted at `C:/`
|
|
28
|
+
* 5. Relative paths → homeDir is the parent, the whole input is the query
|
|
29
|
+
*
|
|
30
|
+
* resolvePathInput("~/projects/myapp", "/home/user") → { path: "/home/user/projects", query: "myapp" }
|
|
31
|
+
* resolvePathInput("C:\\Users\\me", "/home/user") → { path: "C:/Users", query: "me" }
|
|
32
|
+
* resolvePathInput("D:\\data", "/home/user") → { path: "D:/", query: "data" }
|
|
33
|
+
* resolvePathInput("D:", "/home/user") → { path: "D:/", query: "" }
|
|
34
|
+
* resolvePathInput("myproject", "/home/user") → { path: "/home/user", query: "myproject" }
|
|
35
|
+
*/
|
|
36
|
+
export declare function resolvePathInput(input: string, homeDir: string): {
|
|
37
|
+
path: string;
|
|
38
|
+
query: string;
|
|
39
|
+
};
|