@aicayzer/inkkit 0.0.17 → 0.1.0

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 (81) hide show
  1. package/NOTICE +4 -2
  2. package/README.md +12 -6
  3. package/dist/THIRD-PARTY-NOTICES.txt +2742 -0
  4. package/dist/chunks/core-vtCr4MBS.js +56503 -0
  5. package/dist/chunks/highlight-Daj2fv_u.js +14122 -0
  6. package/dist/core.d.ts +4 -0
  7. package/dist/core.js +2 -0
  8. package/dist/editor.d.ts +261 -48
  9. package/dist/index.d.ts +1 -7
  10. package/dist/index.js +5 -2
  11. package/dist/style.css +242 -221
  12. package/dist/types.d.ts +143 -18
  13. package/package.json +26 -15
  14. package/dist/autolink.d.ts +0 -1
  15. package/dist/autolink.js +0 -18
  16. package/dist/callouts.d.ts +0 -26
  17. package/dist/callouts.js +0 -311
  18. package/dist/clipboard.d.ts +0 -11
  19. package/dist/clipboard.js +0 -261
  20. package/dist/code-fences.d.ts +0 -8
  21. package/dist/code-fences.js +0 -166
  22. package/dist/comments.d.ts +0 -55
  23. package/dist/comments.js +0 -494
  24. package/dist/decorations.d.ts +0 -2
  25. package/dist/decorations.js +0 -67
  26. package/dist/dialect.d.ts +0 -9
  27. package/dist/dialect.js +0 -358
  28. package/dist/editor.js +0 -2441
  29. package/dist/files.d.ts +0 -40
  30. package/dist/files.js +0 -133
  31. package/dist/highlight.d.ts +0 -1
  32. package/dist/highlight.js +0 -136
  33. package/dist/image-blocks.d.ts +0 -71
  34. package/dist/image-blocks.js +0 -286
  35. package/dist/images.d.ts +0 -51
  36. package/dist/images.js +0 -398
  37. package/dist/inline-highlight.d.ts +0 -6
  38. package/dist/inline-highlight.js +0 -112
  39. package/dist/labels.d.ts +0 -36
  40. package/dist/labels.js +0 -34
  41. package/dist/linked-syntax.d.ts +0 -48
  42. package/dist/linked-syntax.js +0 -320
  43. package/dist/literals.d.ts +0 -19
  44. package/dist/literals.js +0 -211
  45. package/dist/mermaid.d.ts +0 -8
  46. package/dist/mermaid.js +0 -321
  47. package/dist/outline.d.ts +0 -22
  48. package/dist/outline.js +0 -79
  49. package/dist/paste-html.d.ts +0 -23
  50. package/dist/paste-html.js +0 -441
  51. package/dist/paste.d.ts +0 -26
  52. package/dist/paste.js +0 -482
  53. package/dist/portable-files.d.ts +0 -10
  54. package/dist/portable-files.js +0 -36
  55. package/dist/preserve.d.ts +0 -21
  56. package/dist/preserve.js +0 -757
  57. package/dist/print.d.ts +0 -7
  58. package/dist/print.js +0 -409
  59. package/dist/reference-clipboard.d.ts +0 -8
  60. package/dist/reference-clipboard.js +0 -201
  61. package/dist/references.d.ts +0 -14
  62. package/dist/references.js +0 -368
  63. package/dist/search.d.ts +0 -15
  64. package/dist/search.js +0 -202
  65. package/dist/selection.d.ts +0 -1
  66. package/dist/selection.js +0 -59
  67. package/dist/source.d.ts +0 -16
  68. package/dist/source.js +0 -57
  69. package/dist/spreadsheet.d.ts +0 -3
  70. package/dist/spreadsheet.js +0 -275
  71. package/dist/table-alignment.d.ts +0 -2
  72. package/dist/table-alignment.js +0 -46
  73. package/dist/tables.d.ts +0 -27
  74. package/dist/tables.js +0 -322
  75. package/dist/tasks.d.ts +0 -3
  76. package/dist/tasks.js +0 -51
  77. package/dist/text-ranges.d.ts +0 -29
  78. package/dist/text-ranges.js +0 -256
  79. package/dist/types.js +0 -8
  80. package/dist/wiki-view.d.ts +0 -21
  81. package/dist/wiki-view.js +0 -78
package/dist/print.d.ts DELETED
@@ -1,7 +0,0 @@
1
- import type { Fragment, Schema } from '@milkdown/kit/prose/model';
2
- import { type DocumentContext, type ImageAdapter, type FileAdapter, type PrintableDocument } from './types.js';
3
- type PrintableContent = Pick<PrintableDocument, 'html' | 'styles' | 'assets' | 'warnings'>;
4
- export declare function printableText(text: string): PrintableContent;
5
- export declare function hasAuthoredImagesInLiterals(content: Fragment, parse: (source: string) => unknown): boolean;
6
- export declare function printableMarkdown(content: Fragment, schema: Schema, adapter: ImageAdapter | undefined, context: DocumentContext, files?: FileAdapter, signal?: AbortSignal): Promise<PrintableContent>;
7
- export {};
package/dist/print.js DELETED
@@ -1,409 +0,0 @@
1
- import { clipboardContent } from './clipboard.js';
2
- import { shareableFragment } from './comments.js';
3
- import { fileReference } from './linked-syntax.js';
4
- import { sourceFrontmatter } from './literals.js';
5
- import { diagramImage, renderDiagram } from './mermaid.js';
6
- import { portableFile, portableFileImage } from './portable-files.js';
7
- import { withFileSignal } from './files.js';
8
- import { InkKitError, } from './types.js';
9
- const styles = `
10
- :root { color-scheme: light; font: 11pt/1.5 Arial, sans-serif; }
11
- html, body { margin: 0; padding: 0; height: auto; overflow: visible; background: white; color: #222; }
12
- .inkkit-print-document { padding: 1rem; overflow-wrap: anywhere; }
13
- h1, h2, h3, h4, h5, h6 { line-height: 1.25; break-after: avoid; }
14
- p, ul, ol, blockquote, pre, table, figure { margin-block: 0 1em; }
15
- li > p { margin-bottom: .35em; }
16
- li > ul, li > ol { margin-bottom: .35em; }
17
- a { color: inherit; text-decoration: underline; }
18
- mark { color: inherit; background: #fff0a8; print-color-adjust: exact; }
19
- code, pre { font-family: ui-monospace, Menlo, monospace; }
20
- pre { white-space: pre-wrap; overflow-wrap: anywhere; overflow: visible; padding: .65em; border: 1px solid #ddd; font-size: .9em; }
21
- .inkkit-print-literal { padding: 0; border: 0; font-size: 1em; tab-size: 4; }
22
- blockquote { margin-inline: 0; padding-inline-start: 1em; border-inline-start: 3px solid #aaa; }
23
- .inkkit-callout { padding: .65em 1em; border-inline-start: 3px solid #777; }
24
- .inkkit-callout-title { display: block; margin-bottom: .4em; }
25
- .inkkit-callout-body { display: block; }
26
- .inkkit-print-footnote { border-inline-start: 2px solid #aaa; padding-inline-start: 1em; margin-bottom: 1em; }
27
- sup { font-size: .75em; }
28
- .inkkit-print-task-marker { font-family: ui-monospace, Menlo, monospace; }
29
- table { width: 100%; border-collapse: collapse; table-layout: fixed; font-size: .95em; }
30
- th, td { border: 1px solid #aaa; padding: .4em .6em; vertical-align: top; overflow-wrap: anywhere; }
31
- th { font-weight: bold; }
32
- th p, td p { margin: 0; }
33
- thead { display: table-header-group; }
34
- tfoot { display: table-footer-group; }
35
- tr { break-inside: avoid; }
36
- img { max-width: 100%; height: auto; }
37
- figure { margin-inline: 0; }
38
- .inkkit-print-diagram img { display: block; }
39
- figure, img { break-inside: avoid; }
40
- hr { border: 0; border-top: 1px solid #aaa; }
41
- @page { margin: 18mm; }
42
- @media print {
43
- .inkkit-print-document { padding: 0; }
44
- img { max-height: 90vh; object-fit: contain; }
45
- }
46
- `.trim();
47
- function documentOutput(content, assets = [], warnings = []) {
48
- const page = document.implementation.createHTMLDocument('');
49
- page.head.textContent = '';
50
- const charset = page.createElement('meta');
51
- charset.setAttribute('charset', 'utf-8');
52
- const style = page.createElement('style');
53
- style.textContent = styles;
54
- page.head.append(charset, style);
55
- const main = page.createElement('main');
56
- main.className = 'inkkit-print-document';
57
- while (content.firstChild)
58
- main.appendChild(content.firstChild);
59
- page.body.append(main);
60
- return {
61
- html: '<!DOCTYPE html>\n' + page.documentElement.outerHTML,
62
- styles,
63
- assets,
64
- warnings,
65
- };
66
- }
67
- export function printableText(text) {
68
- const container = document.createElement('div');
69
- const pre = document.createElement('pre');
70
- pre.className = 'inkkit-print-literal';
71
- pre.textContent = text;
72
- container.append(pre);
73
- return documentOutput(container);
74
- }
75
- export function hasAuthoredImagesInLiterals(content, parse) {
76
- const hasImage = (value) => {
77
- if (!value || typeof value !== 'object')
78
- return false;
79
- const node = value;
80
- if (node.type === 'image')
81
- return true;
82
- if (['html', 'code', 'inlineCode', 'imageReference'].includes(String(node.type)))
83
- return false;
84
- return Array.isArray(node.children) && node.children.some(hasImage);
85
- };
86
- let found = false;
87
- shareableFragment(content).descendants((node) => {
88
- if (found)
89
- return false;
90
- if (node.type.name !== 'literal_markdown')
91
- return true;
92
- const source = node.textContent.replace(/^\uFEFF/, '');
93
- const body = source.slice(sourceFrontmatter(source)?.length ?? 0);
94
- if (body && hasImage(parse(body)))
95
- found = true;
96
- return false;
97
- });
98
- return found;
99
- }
100
- function matchesSignature(bytes, mimeType) {
101
- const ascii = (start, end) => String.fromCharCode(...bytes.subarray(start, end));
102
- switch (mimeType) {
103
- case 'image/png':
104
- return (bytes.length >= 24 &&
105
- [137, 80, 78, 71, 13, 10, 26, 10].every((byte, index) => bytes[index] === byte) &&
106
- ascii(12, 16) === 'IHDR');
107
- case 'image/jpeg':
108
- return (bytes.length >= 4 &&
109
- bytes[0] === 255 &&
110
- bytes[1] === 216 &&
111
- bytes[2] === 255);
112
- case 'image/gif':
113
- return bytes.length >= 10 && /^(GIF87a|GIF89a)$/.test(ascii(0, 6));
114
- case 'image/webp':
115
- return (bytes.length >= 12 && ascii(0, 4) === 'RIFF' && ascii(8, 12) === 'WEBP');
116
- case 'image/avif':
117
- return (bytes.length >= 16 &&
118
- ascii(4, 8) === 'ftyp' &&
119
- /avif|avis/.test(ascii(8, 32)));
120
- case 'image/bmp':
121
- return bytes.length >= 26 && ascii(0, 2) === 'BM';
122
- case 'image/tiff':
123
- return (bytes.length >= 8 &&
124
- (ascii(0, 4) === 'II*\0' || ascii(0, 4) === 'MM\0*'));
125
- default:
126
- return false;
127
- }
128
- }
129
- async function validatedImage(input, signal) {
130
- signal.throwIfAborted();
131
- const image = {
132
- bytes: new Uint8Array(input.bytes),
133
- mimeType: input.mimeType.toLowerCase(),
134
- };
135
- if (!matchesSignature(image.bytes, image.mimeType))
136
- throw new Error('The portable image bytes do not match a supported image format.');
137
- const url = URL.createObjectURL(new Blob([image.bytes], { type: image.mimeType }));
138
- try {
139
- await new Promise((resolve, reject) => {
140
- const decoder = new Image();
141
- const timeout = setTimeout(() => {
142
- decoder.src = '';
143
- finish(new Error('The portable image could not be decoded.'));
144
- }, 10000);
145
- const finish = (error) => {
146
- clearTimeout(timeout);
147
- decoder.onload = decoder.onerror = null;
148
- signal.removeEventListener('abort', cancelled);
149
- if (error)
150
- reject(error);
151
- else
152
- resolve();
153
- };
154
- const cancelled = () => {
155
- decoder.src = '';
156
- finish(new DOMException('Image export cancelled', 'AbortError'));
157
- };
158
- signal.addEventListener('abort', cancelled, { once: true });
159
- decoder.onload = () => finish(decoder.naturalWidth > 0 && decoder.naturalHeight > 0
160
- ? undefined
161
- : new Error('The portable image has no usable dimensions.'));
162
- decoder.onerror = () => finish(new Error('The portable image could not be decoded.'));
163
- decoder.src = url;
164
- });
165
- return image;
166
- }
167
- finally {
168
- URL.revokeObjectURL(url);
169
- }
170
- }
171
- function dataURL(image) {
172
- let binary = '';
173
- for (const byte of image.bytes)
174
- binary += String.fromCharCode(byte);
175
- return `data:${image.mimeType};base64,${btoa(binary)}`;
176
- }
177
- const semanticTags = new Set([
178
- 'DIV',
179
- 'P',
180
- 'SPAN',
181
- 'STRONG',
182
- 'EM',
183
- 'DEL',
184
- 'S',
185
- 'MARK',
186
- 'A',
187
- 'SUP',
188
- 'SUB',
189
- 'PRE',
190
- 'CODE',
191
- 'BLOCKQUOTE',
192
- 'H1',
193
- 'H2',
194
- 'H3',
195
- 'H4',
196
- 'H5',
197
- 'H6',
198
- 'UL',
199
- 'OL',
200
- 'LI',
201
- 'TABLE',
202
- 'THEAD',
203
- 'TBODY',
204
- 'TFOOT',
205
- 'TR',
206
- 'TH',
207
- 'TD',
208
- 'HR',
209
- 'BR',
210
- 'IMG',
211
- 'FIGURE',
212
- 'FIGCAPTION',
213
- ]);
214
- const printClasses = new Set([
215
- 'inkkit-callout',
216
- 'inkkit-callout-title',
217
- 'inkkit-callout-body',
218
- 'inkkit-print-footnote',
219
- 'inkkit-print-task-marker',
220
- 'inkkit-print-diagram',
221
- ]);
222
- function safeLink(value) {
223
- if (/[\u0000-\u001f\u007f\\]/.test(value))
224
- return undefined;
225
- const href = value.trim();
226
- if (!href)
227
- return undefined;
228
- // A colon in the first path component denotes a scheme, including an
229
- // obfuscated one. Relative paths can still contain colons after a slash.
230
- if (/^[^/?#]*:/.test(href) && !/^(https?:|mailto:)/i.test(href))
231
- return undefined;
232
- return href.replaceAll(' ', '%20');
233
- }
234
- function cleanSemantics(container, localIDs) {
235
- for (const element of container.querySelectorAll('*')) {
236
- if (!semanticTags.has(element.tagName)) {
237
- if (/^(SCRIPT|STYLE|LINK|META|IFRAME|OBJECT|EMBED|BUTTON|INPUT|TEXTAREA|SELECT)$/.test(element.tagName))
238
- element.remove();
239
- else
240
- element.replaceWith(...Array.from(element.childNodes));
241
- continue;
242
- }
243
- const classes = Array.from(element.classList).filter((name) => printClasses.has(name));
244
- const href = element.tagName === 'A' ? element.getAttribute('href') : null;
245
- const src = element.tagName === 'IMG' ? element.getAttribute('src') : null;
246
- const alt = element.tagName === 'IMG' ? element.getAttribute('alt') : null;
247
- const width = element.tagName === 'IMG' ? element.getAttribute('width') : null;
248
- const title = element.getAttribute('title');
249
- const id = element.getAttribute('id');
250
- const order = element.tagName === 'OL' ? element.getAttribute('start') : null;
251
- const alignment = element instanceof HTMLElement ? element.style.textAlign : '';
252
- for (const attribute of [...element.attributes])
253
- element.removeAttribute(attribute.name);
254
- if (classes.length)
255
- element.setAttribute('class', classes.join(' '));
256
- const destination = href == null ? undefined : safeLink(href);
257
- if (destination != null)
258
- element.setAttribute('href', destination);
259
- if (src &&
260
- /^data:image\/(png|jpeg|gif|webp|avif|bmp|tiff);base64,[A-Za-z0-9+/=]+$/.test(src))
261
- element.setAttribute('src', src);
262
- if (alt != null)
263
- element.setAttribute('alt', alt);
264
- if (width && /^\d+$/.test(width))
265
- element.setAttribute('width', width);
266
- if (title)
267
- element.setAttribute('title', title);
268
- if (id && localIDs.has(id))
269
- element.setAttribute('id', id);
270
- if (order && /^\d+$/.test(order))
271
- element.setAttribute('start', order);
272
- if (/^(left|center|right)$/.test(alignment) &&
273
- /^(TH|TD)$/.test(element.tagName))
274
- element.setAttribute('style', `text-align: ${alignment}`);
275
- }
276
- const walker = document.createTreeWalker(container, NodeFilter.SHOW_COMMENT);
277
- const comments = [];
278
- while (walker.nextNode())
279
- comments.push(walker.currentNode);
280
- for (const comment of comments)
281
- comment.parentNode?.removeChild(comment);
282
- }
283
- export async function printableMarkdown(content, schema, adapter, context, files, signal = new AbortController().signal) {
284
- signal.throwIfAborted();
285
- content = shareableFragment(content);
286
- const container = document.createElement('div');
287
- container.innerHTML = clipboardContent(content, schema).html;
288
- const references = [];
289
- const tasks = [];
290
- content.descendants((node) => {
291
- if (node.type.name === 'image')
292
- references.push(node);
293
- if (node.type.name === 'list_item')
294
- tasks.push(node.attrs.checked ?? null);
295
- });
296
- for (const [index, item] of [...container.querySelectorAll('li')].entries()) {
297
- if (tasks[index] == null)
298
- continue;
299
- const marker = document.createElement('span');
300
- marker.className = 'inkkit-print-task-marker';
301
- marker.textContent = tasks[index] ? '[x] ' : '[ ] ';
302
- (item.firstElementChild?.tagName === 'P'
303
- ? item.firstElementChild
304
- : item).prepend(marker);
305
- }
306
- const footnotes = new Map();
307
- const localIDs = new Set();
308
- for (const [index, definition] of [
309
- ...container.querySelectorAll('[data-inkkit-footnote-definition]'),
310
- ].entries()) {
311
- const identifier = definition.getAttribute('data-inkkit-footnote-definition');
312
- const id = `inkkit-print-note-${index + 1}`;
313
- localIDs.add(id);
314
- if (!footnotes.has(identifier))
315
- footnotes.set(identifier, id);
316
- definition.setAttribute('id', id);
317
- definition.className = 'inkkit-print-footnote';
318
- }
319
- for (const reference of container.querySelectorAll('[data-inkkit-footnote-reference]')) {
320
- const id = footnotes.get(reference.getAttribute('data-inkkit-footnote-reference'));
321
- if (!id)
322
- continue;
323
- const link = document.createElement('a');
324
- link.setAttribute('href', `#${id}`);
325
- link.textContent = reference.textContent;
326
- reference.replaceChildren(link);
327
- }
328
- const images = new Map();
329
- const warnings = [];
330
- for (const [index, element] of [
331
- ...container.querySelectorAll('img'),
332
- ].entries()) {
333
- const node = references[index];
334
- try {
335
- if (!node)
336
- throw new Error('The authored image is unavailable.');
337
- const reference = fileReference(node);
338
- const file = files
339
- ? await portableFile(node, files, context, signal)
340
- : undefined;
341
- if (file && file.presentation.kind !== 'image') {
342
- const fallback = document.createElement('span');
343
- fallback.textContent = file.description;
344
- element.replaceWith(fallback);
345
- const unavailable = file.presentation.kind === 'missing' ||
346
- file.presentation.kind === 'error';
347
- warnings.push({
348
- code: unavailable ? 'attachment-unavailable' : 'attachment-fallback',
349
- message: unavailable
350
- ? `${file.label} is unavailable; its description is printed.`
351
- : `${file.label} is printed as a ${file.presentation.kind === 'pdf' ? 'PDF' : file.presentation.kind} description.`,
352
- });
353
- continue;
354
- }
355
- if (!file && !adapter)
356
- throw new Error('The authored image is unavailable.');
357
- const image = await validatedImage(file
358
- ? await portableFileImage(file, files, adapter, context, signal)
359
- : await withFileSignal(adapter.exportImage(reference.reference, { ...context }), signal), signal);
360
- signal.throwIfAborted();
361
- images.set(element, image);
362
- element.setAttribute('src', dataURL(image));
363
- element.setAttribute('alt', file?.label || reference.label || '');
364
- if (reference.width != null && reference.width > 0)
365
- element.setAttribute('width', String(Math.min(4096, reference.width)));
366
- }
367
- catch (error) {
368
- signal.throwIfAborted();
369
- throw new InkKitError('image-unavailable', error instanceof Error
370
- ? error.message
371
- : 'The authored image is unavailable.');
372
- }
373
- }
374
- for (const code of container.querySelectorAll('pre[data-language="mermaid"] > code')) {
375
- const source = code.textContent ?? '';
376
- try {
377
- await withFileSignal(renderDiagram(source), signal);
378
- }
379
- catch (error) {
380
- signal.throwIfAborted();
381
- const message = `${error instanceof Error ? error.message : 'This diagram could not be rendered.'} The source is printed below.`;
382
- warnings.push({ code: 'diagram-unavailable', message });
383
- const warning = document.createElement('p');
384
- warning.textContent = message;
385
- code.parentElement.before(warning);
386
- continue;
387
- }
388
- try {
389
- const image = await validatedImage(await withFileSignal(diagramImage(source), signal), signal);
390
- const figure = document.createElement('figure');
391
- figure.className = 'inkkit-print-diagram';
392
- const element = document.createElement('img');
393
- element.setAttribute('src', dataURL(image));
394
- element.setAttribute('alt', 'Mermaid diagram');
395
- figure.append(element);
396
- images.set(element, image);
397
- code.parentElement.replaceWith(figure);
398
- }
399
- catch (error) {
400
- throw new InkKitError('diagram-unavailable', error instanceof Error
401
- ? error.message
402
- : 'The diagram image is unavailable.');
403
- }
404
- }
405
- cleanSemantics(container, localIDs);
406
- const assets = [...container.querySelectorAll('img')].map((element) => images.get(element));
407
- signal.throwIfAborted();
408
- return documentOutput(container, assets, warnings);
409
- }
@@ -1,8 +0,0 @@
1
- import type { Ctx } from '@milkdown/kit/ctx';
2
- import { Fragment, type Node } from '@milkdown/kit/prose/model';
3
- export declare function selectionContent(doc: Node, content: Fragment): Fragment;
4
- export declare function selectionMarkdown(ctx: Ctx, doc: Node, content: Fragment): string;
5
- export declare function referenceMetadata(ctx: Ctx, doc: Node, content: Fragment): string | undefined;
6
- export declare function avoidReferenceCollisions(incoming: Node, destination: Node): Node;
7
- export declare function markdownFromHTML(html: string): string | undefined;
8
- export declare function withReferenceMetadata(html: string, markdown: string): string;
@@ -1,201 +0,0 @@
1
- import { Fragment } from '@milkdown/kit/prose/model';
2
- import { serialize } from './dialect.js';
3
- import { normaliseLabel } from './references.js';
4
- import { shareableFragment } from './comments.js';
5
- function key(node) {
6
- if (node.type.name === 'reference_definition')
7
- return `link:${node.attrs.identifier}`;
8
- if (node.type.name === 'footnote_definition')
9
- return `footnote:${node.attrs.identifier}`;
10
- return undefined;
11
- }
12
- function used(content) {
13
- const result = new Set();
14
- content.descendants((node) => {
15
- if (node.type.name === 'footnote_reference')
16
- result.add(`footnote:${node.attrs.identifier}`);
17
- for (const mark of node.marks)
18
- if (mark.type.name === 'link' && mark.attrs.identifier)
19
- result.add(`link:${mark.attrs.identifier}`);
20
- });
21
- return result;
22
- }
23
- export function selectionContent(doc, content) {
24
- const definitions = new Map();
25
- doc.descendants((node) => {
26
- const id = key(node);
27
- if (id && !definitions.has(id))
28
- definitions.set(id, node);
29
- });
30
- const required = used(content);
31
- for (const id of required) {
32
- const definition = definitions.get(id);
33
- if (definition)
34
- for (const dependency of used(definition.content))
35
- required.add(dependency);
36
- }
37
- const complete = (node) => {
38
- const id = key(node);
39
- if (id && required.has(id) && definitions.has(id))
40
- return definitions.get(id);
41
- if (node.isText)
42
- return node;
43
- const children = [];
44
- node.forEach((child) => children.push(complete(child)));
45
- return node.copy(Fragment.fromArray(children));
46
- };
47
- const selected = [];
48
- content.forEach((node) => selected.push(complete(node)));
49
- content = Fragment.fromArray(selected);
50
- const included = new Set();
51
- content.descendants((node) => {
52
- const id = key(node);
53
- if (id)
54
- included.add(id);
55
- });
56
- const extra = [];
57
- for (const id of required) {
58
- if (included.has(id))
59
- continue;
60
- const definition = definitions.get(id);
61
- if (!definition)
62
- continue;
63
- included.add(id);
64
- extra.push(definition);
65
- for (const dependency of used(definition.content))
66
- required.add(dependency);
67
- }
68
- return content.append(Fragment.fromArray(extra));
69
- }
70
- export function selectionMarkdown(ctx, doc, content) {
71
- return serialize(ctx, doc.type.create(null, selectionContent(doc, content)));
72
- }
73
- export function referenceMetadata(ctx, doc, content) {
74
- doc = doc.copy(shareableFragment(doc.content));
75
- content = shareableFragment(content);
76
- let references = false, index = 0;
77
- const rewrite = (node) => {
78
- if (key(node) ||
79
- node.type.name === 'footnote_reference' ||
80
- node.marks.some((mark) => mark.type.name === 'link' && mark.attrs.identifier))
81
- references = true;
82
- if (node.type.name === 'image')
83
- return node.type.create({ ...node.attrs, src: `inkkit-clipboard-image:${index++}` }, null, node.marks);
84
- if (node.isText)
85
- return node;
86
- const children = [];
87
- node.forEach((child) => children.push(rewrite(child)));
88
- return node.copy(Fragment.fromArray(children));
89
- };
90
- const valid = content.firstChild?.isInline
91
- ? Fragment.from(doc.type.schema.nodes.paragraph.create(null, content))
92
- : content;
93
- const copied = rewrite(doc.type.create(null, selectionContent(doc, valid)));
94
- return references ? serialize(ctx, copied) : undefined;
95
- }
96
- function allLabels(doc) {
97
- const labels = new Map([
98
- ['link', new Set()],
99
- ['footnote', new Set()],
100
- ]);
101
- doc.descendants((node) => {
102
- if (isCode(node))
103
- return false;
104
- const id = key(node);
105
- if (id) {
106
- const separator = id.indexOf(':');
107
- labels.get(id.slice(0, separator)).add(id.slice(separator + 1));
108
- }
109
- if (node.type.name === 'footnote_reference')
110
- labels.get('footnote').add(node.attrs.identifier);
111
- for (const mark of node.marks)
112
- if (mark.type.name === 'link' && mark.attrs.identifier)
113
- labels.get('link').add(mark.attrs.identifier);
114
- if (node.isText) {
115
- for (const match of node.text.matchAll(rawReferences))
116
- labels
117
- .get(match[1].startsWith('^') ? 'footnote' : 'link')
118
- .add(normaliseLabel(match[1].startsWith('^')
119
- ? match[1].slice(1)
120
- : match[2] || match[1]));
121
- }
122
- });
123
- return labels;
124
- }
125
- const rawReferences = /(?<![\\!])\[([^\]]+)\](?:\[([^\]]*)\])?(?!\()/g;
126
- function isCode(node) {
127
- return (node.type.name.startsWith('comment_') ||
128
- node.type.name === 'code_block' ||
129
- node.marks.some((mark) => mark.type.name === 'inlineCode'));
130
- }
131
- // Rename only the incoming document. Definitions belong to the insertion's undo transaction.
132
- export function avoidReferenceCollisions(incoming, destination) {
133
- const occupied = allLabels(destination);
134
- const incomingLabels = allLabels(incoming);
135
- const replacements = new Map();
136
- for (const [kind, labels] of incomingLabels) {
137
- const reserved = new Set([...occupied.get(kind), ...labels]);
138
- for (const identifier of labels) {
139
- if (!occupied.get(kind).has(identifier))
140
- continue;
141
- let suffix = 2;
142
- while (reserved.has(normaliseLabel(`${identifier}-${suffix}`)))
143
- suffix++;
144
- const label = `${identifier}-${suffix}`;
145
- reserved.add(normaliseLabel(label));
146
- replacements.set(`${kind}:${identifier}`, label);
147
- }
148
- }
149
- if (!replacements.size)
150
- return incoming;
151
- const rewrite = (node) => {
152
- if (isCode(node))
153
- return node;
154
- const kind = node.type.name.startsWith('footnote_') ? 'footnote' : 'link';
155
- const label = replacements.get(`${kind}:${node.attrs.identifier}`);
156
- const attrs = label
157
- ? { ...node.attrs, label, identifier: normaliseLabel(label) }
158
- : node.attrs;
159
- const marks = node.marks.map((mark) => {
160
- const replacement = replacements.get(`link:${mark.attrs.identifier}`);
161
- return replacement && mark.type.name === 'link'
162
- ? mark.type.create({
163
- ...mark.attrs,
164
- label: replacement,
165
- identifier: normaliseLabel(replacement),
166
- referenceType: 'full',
167
- })
168
- : mark;
169
- });
170
- if (node.isText) {
171
- const text = node.text.replace(rawReferences, (raw, display, reference) => {
172
- const footnote = display.startsWith('^')
173
- ? display.slice(1)
174
- : undefined;
175
- const replacement = replacements.get(`${footnote ? 'footnote' : 'link'}:${normaliseLabel(footnote ?? (reference || display))}`);
176
- return replacement
177
- ? footnote
178
- ? `[^${replacement}]`
179
- : `[${display}][${replacement}]`
180
- : raw;
181
- });
182
- return node.type.schema.text(text, marks);
183
- }
184
- const children = [];
185
- node.forEach((child) => children.push(rewrite(child)));
186
- return node.type.create(attrs, children, marks);
187
- };
188
- return rewrite(incoming);
189
- }
190
- export function markdownFromHTML(html) {
191
- const template = document.createElement('template');
192
- template.innerHTML = html;
193
- const element = template.content.querySelector('[data-inkkit-markdown]');
194
- return element?.getAttribute('data-inkkit-markdown') ?? undefined;
195
- }
196
- export function withReferenceMetadata(html, markdown) {
197
- const container = document.createElement('div');
198
- container.setAttribute('data-inkkit-markdown', markdown);
199
- container.innerHTML = html;
200
- return container.outerHTML;
201
- }
@@ -1,14 +0,0 @@
1
- import type { Node as ProseNode } from '@milkdown/kit/prose/model';
2
- export declare function normaliseLabel(label: string): string;
3
- export interface LocatedDefinition {
4
- node: ProseNode;
5
- pos: number;
6
- }
7
- export declare const referenceDefinitions: (doc: ProseNode) => Map<string, LocatedDefinition>;
8
- export declare const footnoteDefinitions: (doc: ProseNode) => Map<string, LocatedDefinition>;
9
- export declare const remarkReferencesPlugin: import("@milkdown/kit/utils").$Remark<"inkkitReferences", unknown>;
10
- export declare const referenceLinks: import("@milkdown/kit/utils").$MarkSchema<"link">;
11
- export declare const referenceDefinition: import("@milkdown/kit/utils").$Node;
12
- export declare const footnoteReference: import("@milkdown/kit/utils").$Node;
13
- export declare const footnoteDefinition: import("@milkdown/kit/utils").$Node;
14
- export declare const references: (import("@milkdown/kit/utils").$Ctx<import("@milkdown/kit/utils").GetMarkSchema, "link"> | import("@milkdown/kit/utils").$Mark | import("@milkdown/kit/utils").$Node | import("@milkdown/kit/utils").$Prose)[];