@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/mermaid.js DELETED
@@ -1,321 +0,0 @@
1
- import { editorLabels } from './labels.js';
2
- import DOMPurify from 'dompurify';
3
- import { Plugin, PluginKey } from '@milkdown/kit/prose/state';
4
- import { Decoration, DecorationSet } from '@milkdown/kit/prose/view';
5
- import { $prose } from '@milkdown/kit/utils';
6
- import { InkKitError } from './types.js';
7
- export function isMermaid(node) {
8
- return node.type.name === 'code_block' && node.attrs.language === 'mermaid';
9
- }
10
- const refusal = 'HTML, styles, actions, resources and diagram configuration are disabled. The source is retained.';
11
- // CSS functions that can load an image or display another element. Mermaid's
12
- // own styles use none of them apart from url() for in-document markers.
13
- const cssResource = /url\s*\(\s*[^#\s]|(?:image-set|cross-fade|image|element|src)\s*\(/i;
14
- export function validateDiagram(source) {
15
- if (source.length > 30000)
16
- throw new Error('The diagram exceeds the 30,000 character rendering limit.');
17
- if (!/^\s*(?:%%[^\n]*\n\s*)*(?:flowchart|graph|sequenceDiagram|classDiagram|stateDiagram(?:-v2)?|erDiagram|pie)\b/.test(source))
18
- throw new Error('This diagram type is not supported. The source is retained.');
19
- // Mermaid can load image bytes before sanitising its result, so resource and
20
- // configuration syntax is refused anywhere in the source, labels included.
21
- // Statements are checked separately, in Mermaid's parse result.
22
- if (/%%\{|^\s*---|<\s*[a-z!/?]|&(?:#\w+|[a-z]+);|@\{|\$\$|(?:https?|data|file|javascript|vbscript|blob):|\/\/|url\s*\(|image-set\s*\(|cross-fade\s*\(|@import|\\/im.test(source))
23
- throw new Error(refusal);
24
- }
25
- const entries = (value) => value instanceof Map ? [...value.values()] : Array.isArray(value) ? value : [];
26
- const filled = (value) => value instanceof Map
27
- ? value.size > 0
28
- : Array.isArray(value)
29
- ? value.length > 0
30
- : typeof value === 'object' && value !== null
31
- ? Object.keys(value).length > 0
32
- : Boolean(value);
33
- // In strict mode a flowchart records a click handler only as this class.
34
- const clickable = (classes) => (Array.isArray(classes) ? classes : String(classes ?? '').split(/\s+/))
35
- .map(String)
36
- .includes('clickable');
37
- function statementIn(node, kinds, seen = new Set()) {
38
- if (typeof node !== 'object' || node === null || seen.has(node))
39
- return false;
40
- seen.add(node);
41
- if (kinds.includes(String(node.stmt)))
42
- return true;
43
- return Object.values(node).some((value) => statementIn(value, kinds, seen));
44
- }
45
- // Refuses styles, class definitions, link styles, links, click handlers,
46
- // tooltips, icons and images wherever the grammar accepted them. The names are
47
- // those of the pinned Mermaid's diagram databases; if one is missing, the
48
- // diagram is refused rather than passed unchecked.
49
- function refuseDirectives({ type, db }) {
50
- const store = db;
51
- const field = (name) => {
52
- if (!(name in store))
53
- throw new Error('The diagram could not be checked. The source is retained.');
54
- return store[name];
55
- };
56
- const read = (name) => {
57
- const accessor = field(name);
58
- if (typeof accessor !== 'function')
59
- throw new Error('The diagram could not be checked. The source is retained.');
60
- return accessor.call(db);
61
- };
62
- let found;
63
- switch (type) {
64
- case 'flowchart-v2': {
65
- const edges = read('getEdges');
66
- found =
67
- filled(read('getClasses')) ||
68
- filled(field('tooltips')) ||
69
- filled(edges.defaultStyle) ||
70
- edges.defaultInterpolate !== undefined ||
71
- entries(read('getVertices')).some((vertex) => filled(vertex.styles) ||
72
- Boolean(vertex.link || vertex.haveCallback || vertex.icon || vertex.img) ||
73
- clickable(vertex.classes)) ||
74
- entries(edges).some((edge) => filled(edge.style) ||
75
- edge.interpolate !== undefined ||
76
- clickable(edge.classes)) ||
77
- entries(read('getSubGraphs')).some((graph) => clickable(graph.classes));
78
- break;
79
- }
80
- case 'stateDiagram':
81
- found =
82
- statementIn(field('rootDoc'), ['style', 'classDef', 'click']) ||
83
- filled(read('getClasses')) ||
84
- filled(read('getLinks')) ||
85
- entries(read('getStates')).some((state) => filled(state.styles) || filled(state.textStyles));
86
- break;
87
- case 'classDiagram':
88
- found =
89
- filled(field('styleClasses')) ||
90
- entries(read('getClasses')).some((node) => filled(node.styles) ||
91
- Boolean(node.link || node.haveCallback || node.tooltip) ||
92
- clickable(node.cssClasses));
93
- break;
94
- case 'er':
95
- found =
96
- filled(read('getClasses')) ||
97
- entries(read('getEntities')).some((entity) => filled(entity.cssStyles)) ||
98
- entries(read('getSubGraphs')).some((graph) => filled(graph.cssStyles));
99
- break;
100
- case 'sequence':
101
- found = entries(read('getActors')).some((actor) => filled(actor.links) || filled(actor.properties));
102
- break;
103
- case 'pie':
104
- found = false;
105
- break;
106
- default:
107
- throw new Error('This diagram type is not supported. The source is retained.');
108
- }
109
- if (found)
110
- throw new Error(refusal);
111
- }
112
- let sequence = 0;
113
- let queue = Promise.resolve();
114
- const cache = new Map();
115
- export function safeDiagramSVG(svg) {
116
- const clean = DOMPurify.sanitize(svg, {
117
- USE_PROFILES: { svg: true, svgFilters: true },
118
- FORBID_TAGS: ['foreignObject', 'image', 'a', 'script', 'animate', 'set'],
119
- FORBID_ATTR: ['href', 'xlink:href'],
120
- });
121
- const template = document.createElement('template');
122
- template.innerHTML = clean;
123
- const root = template.content.querySelector('svg');
124
- if (!root)
125
- throw new Error('The renderer did not produce a diagram.');
126
- for (const element of [root, ...root.querySelectorAll('*')]) {
127
- for (const attribute of [...element.attributes]) {
128
- if (/^on/i.test(attribute.name) ||
129
- /(?:https?|data|file|javascript|blob):|@import|\\/i.test(attribute.value) ||
130
- cssResource.test(attribute.value))
131
- element.removeAttribute(attribute.name);
132
- }
133
- if (element.tagName.toLowerCase() === 'style' &&
134
- (/@import|(?:https?|data|file):|\\/i.test(element.textContent ?? '') ||
135
- cssResource.test(element.textContent ?? '')))
136
- element.remove();
137
- }
138
- root.setAttribute('xmlns', 'http://www.w3.org/2000/svg');
139
- return root.outerHTML;
140
- }
141
- export function renderDiagram(source) {
142
- try {
143
- validateDiagram(source);
144
- }
145
- catch (error) {
146
- return Promise.reject(error);
147
- }
148
- const previous = cache.get(source);
149
- if (previous)
150
- return previous;
151
- const rendered = queue.then(async () => {
152
- const { default: mermaid } = await import('mermaid');
153
- mermaid.initialize({
154
- startOnLoad: false,
155
- securityLevel: 'strict',
156
- htmlLabels: false,
157
- suppressErrorRendering: true,
158
- fontFamily: 'Arial, sans-serif',
159
- altFontFamily: 'Arial, sans-serif',
160
- layout: 'dagre',
161
- look: 'classic',
162
- theme: 'default',
163
- maxTextSize: 30000,
164
- maxEdges: 500,
165
- flowchart: { htmlLabels: false },
166
- sequence: {
167
- actorFontFamily: 'Arial, sans-serif',
168
- noteFontFamily: 'Arial, sans-serif',
169
- messageFontFamily: 'Arial, sans-serif',
170
- },
171
- secure: [
172
- 'securityLevel',
173
- 'htmlLabels',
174
- 'theme',
175
- 'themeCSS',
176
- 'themeVariables',
177
- 'fontFamily',
178
- 'dompurifyConfig',
179
- 'flowchart',
180
- 'startOnLoad',
181
- 'maxTextSize',
182
- 'maxEdges',
183
- 'secure',
184
- 'altFontFamily',
185
- 'layout',
186
- 'look',
187
- 'sequence',
188
- 'class',
189
- 'state',
190
- 'er',
191
- 'pie',
192
- 'suppressErrorRendering',
193
- ],
194
- });
195
- // getDiagramFromText is the pinned Mermaid's own parser, which render runs
196
- // again on the same text; the public parse does not return the diagram. It
197
- // skips render's configuration step, so the two parse alike only because
198
- // the source check refuses %%{ directives and front matter.
199
- refuseDirectives(await mermaid.mermaidAPI.getDiagramFromText(source));
200
- // Mermaid measures text while laying out, so the holder must be attached
201
- // and rendered. Such a holder can load CSS resources before sanitising,
202
- // which is why the source and the parse result are checked first.
203
- const holder = document.createElement('div');
204
- holder.style.cssText =
205
- 'position:fixed;left:-100000px;top:0;width:1200px;pointer-events:none';
206
- holder.setAttribute('aria-hidden', 'true');
207
- document.body.append(holder);
208
- try {
209
- const result = await mermaid.render(`inkkitDiagram${++sequence}`, source, holder);
210
- return safeDiagramSVG(result.svg);
211
- }
212
- finally {
213
- holder.remove();
214
- }
215
- });
216
- queue = rendered.catch(() => undefined);
217
- cache.set(source, rendered);
218
- void rendered.catch(() => {
219
- if (cache.get(source) === rendered)
220
- cache.delete(source);
221
- });
222
- if (cache.size > 64)
223
- cache.delete(cache.keys().next().value);
224
- return rendered;
225
- }
226
- export async function diagramImage(source) {
227
- const svg = await renderDiagram(source);
228
- const parsed = new DOMParser().parseFromString(svg, 'image/svg+xml').documentElement;
229
- const bounds = (parsed.getAttribute('viewBox') ?? '')
230
- .split(/[\s,]+/)
231
- .map(Number);
232
- const width = bounds[2] || Number.parseFloat(parsed.getAttribute('width') ?? '');
233
- const height = bounds[3] || Number.parseFloat(parsed.getAttribute('height') ?? '');
234
- if (!(width > 0 && height > 0 && Number.isFinite(width + height)))
235
- throw new Error('The rendered diagram has no usable dimensions.');
236
- const scale = Math.min(2, 4096 / width, 4096 / height);
237
- const canvas = document.createElement('canvas');
238
- canvas.width = Math.max(1, Math.ceil(width * scale));
239
- canvas.height = Math.max(1, Math.ceil(height * scale));
240
- const context = canvas.getContext('2d');
241
- if (!context)
242
- throw new Error('Portable diagram output is unavailable.');
243
- parsed.setAttribute('width', String(width));
244
- parsed.setAttribute('height', String(height));
245
- const image = new Image();
246
- const url = URL.createObjectURL(new Blob([new XMLSerializer().serializeToString(parsed)], {
247
- type: 'image/svg+xml',
248
- }));
249
- try {
250
- await new Promise((resolve, reject) => {
251
- image.onload = () => resolve();
252
- image.onerror = () => reject(new Error('The diagram image could not be rendered.'));
253
- image.src = url;
254
- });
255
- context.fillStyle = '#ffffff';
256
- context.fillRect(0, 0, canvas.width, canvas.height);
257
- context.drawImage(image, 0, 0, canvas.width, canvas.height);
258
- const data = canvas.toDataURL('image/png').split(',')[1];
259
- if (!data)
260
- throw new Error('The diagram image could not be exported.');
261
- return {
262
- bytes: Uint8Array.from(atob(data), (character) => character.charCodeAt(0)),
263
- mimeType: 'image/png',
264
- filename: 'diagram.png',
265
- };
266
- }
267
- finally {
268
- URL.revokeObjectURL(url);
269
- }
270
- }
271
- export function mermaidPreview(onError) {
272
- return $prose((ctx) => new Plugin({
273
- key: new PluginKey('mermaidPreview'),
274
- props: {
275
- decorations(state) {
276
- const widgets = [];
277
- state.doc.descendants((node, pos) => {
278
- if (!isMermaid(node))
279
- return true;
280
- const source = node.textContent;
281
- widgets.push(Decoration.widget(pos + node.nodeSize, () => {
282
- const preview = document.createElement('div');
283
- preview.className = 'inkkit-mermaid-preview';
284
- preview.contentEditable = 'false';
285
- preview.textContent = editorLabels(ctx).diagramRendering;
286
- preview.setAttribute('role', 'status');
287
- preview.setAttribute('aria-live', 'polite');
288
- let active = true;
289
- preview.cancel =
290
- () => {
291
- active = false;
292
- };
293
- void renderDiagram(source).then((svg) => {
294
- if (active) {
295
- preview.innerHTML = svg;
296
- preview.dataset.state = 'ready';
297
- }
298
- }, (error) => {
299
- if (!active)
300
- return;
301
- const message = error instanceof Error
302
- ? error.message
303
- : 'The diagram could not be rendered.';
304
- preview.textContent = `${editorLabels(ctx).diagramUnavailable} ${message}`;
305
- preview.dataset.state = 'error';
306
- onError(new InkKitError('diagram-unavailable', message));
307
- });
308
- return preview;
309
- }, {
310
- key: `mermaid:${source}`,
311
- side: -1,
312
- ignoreSelection: true,
313
- destroy: (node) => node.cancel?.(),
314
- }));
315
- return false;
316
- });
317
- return DecorationSet.create(state.doc, widgets);
318
- },
319
- },
320
- }));
321
- }
package/dist/outline.d.ts DELETED
@@ -1,22 +0,0 @@
1
- import type { Ctx } from '@milkdown/kit/ctx';
2
- import type { Node as ProseNode } from '@milkdown/kit/prose/model';
3
- import type { EditorView } from '@milkdown/kit/prose/view';
4
- export interface Heading {
5
- readonly id: string;
6
- readonly level: number;
7
- readonly text: string;
8
- readonly documentId: string;
9
- readonly generation: number;
10
- readonly revision: number;
11
- }
12
- export interface OutlineContext {
13
- documentId: string;
14
- generation: number;
15
- revision: number;
16
- epoch: number;
17
- mode: 'source' | 'formatted';
18
- }
19
- export declare function collectFormattedHeadings(doc: ProseNode, context: OutlineContext): readonly Heading[];
20
- export declare function collectSourceHeadings(ctx: Ctx, source: string, context: OutlineContext): readonly Heading[];
21
- export declare function sourceHeadingPosition(ctx: Ctx, source: string, requested: Heading, context: OutlineContext): number;
22
- export declare function navigateFormattedHeading(view: EditorView, requested: Heading, context: OutlineContext): boolean;
package/dist/outline.js DELETED
@@ -1,79 +0,0 @@
1
- import { parserCtx, remarkCtx } from '@milkdown/kit/core';
2
- import { TextSelection } from '@milkdown/kit/prose/state';
3
- import { clipboardText } from './clipboard.js';
4
- import { revealCalloutAncestors } from './callouts.js';
5
- import { InkKitError } from './types.js';
6
- function formattedLocations(doc) {
7
- const headings = [];
8
- doc.descendants((node, position) => {
9
- if (node.type.name === 'heading')
10
- headings.push({ node, position });
11
- });
12
- return headings;
13
- }
14
- function sourceLocations(ctx, source) {
15
- const processor = ctx.get(remarkCtx);
16
- const tree = processor.runSync(processor.parse(source), {
17
- value: source,
18
- });
19
- const positions = [];
20
- const bom = source.startsWith('\uFEFF') ? 1 : 0;
21
- const visit = (node) => {
22
- if (node.type === 'heading' && node.position?.start.offset != null)
23
- positions.push({
24
- position: node.position.start.offset + bom,
25
- level: node.depth,
26
- });
27
- node.children?.forEach(visit);
28
- };
29
- visit(tree);
30
- const parsed = formattedLocations(ctx.get(parserCtx)(source));
31
- if (positions.length !== parsed.length ||
32
- positions.some((item, index) => item.level !== parsed[index].node.attrs.level))
33
- throw new InkKitError('preservation', 'The current Markdown headings cannot be located safely');
34
- return parsed.map((heading, index) => ({
35
- ...heading,
36
- position: positions[index].position,
37
- }));
38
- }
39
- function entry(heading, context) {
40
- return Object.freeze({
41
- id: `heading:${context.epoch}:${context.mode}:${context.generation}:${context.revision}:${heading.position}`,
42
- level: Number(heading.node.attrs.level),
43
- text: clipboardText(heading.node.content),
44
- documentId: context.documentId,
45
- generation: context.generation,
46
- revision: context.revision,
47
- });
48
- }
49
- export function collectFormattedHeadings(doc, context) {
50
- return Object.freeze(formattedLocations(doc).map((item) => entry(item, context)));
51
- }
52
- export function collectSourceHeadings(ctx, source, context) {
53
- return Object.freeze(sourceLocations(ctx, source).map((item) => entry(item, context)));
54
- }
55
- function currentLocation(locations, requested, context) {
56
- for (const location of locations) {
57
- const current = entry(location, context);
58
- if (current.id === requested.id &&
59
- current.documentId === requested.documentId &&
60
- current.generation === requested.generation &&
61
- current.revision === requested.revision &&
62
- current.level === requested.level &&
63
- current.text === requested.text)
64
- return location.position;
65
- }
66
- throw new InkKitError('stale-document', 'The heading is no longer current');
67
- }
68
- export function sourceHeadingPosition(ctx, source, requested, context) {
69
- return currentLocation(sourceLocations(ctx, source), requested, context);
70
- }
71
- export function navigateFormattedHeading(view, requested, context) {
72
- const position = currentLocation(formattedLocations(view.state.doc), requested, context);
73
- revealCalloutAncestors(view, position + 1);
74
- view.dispatch(view.state.tr
75
- .setSelection(TextSelection.create(view.state.doc, position + 1))
76
- .scrollIntoView());
77
- view.focus();
78
- return true;
79
- }
@@ -1,23 +0,0 @@
1
- export declare function isRichElement(element: Element): boolean;
2
- /** Whether normalisation enters the element, so its content may be rewritten. */
3
- export declare function isRewrittenElement(element: Element): boolean;
4
- /**
5
- * Whether the element's own inline style makes a browser keep the whitespace
6
- * of its content, as copied editor code does with `white-space: pre`. The
7
- * declarations are parsed, so case, spacing, comments, quoted text and
8
- * `!important` do not matter. Style sheets are not consulted.
9
- */
10
- export declare function keepsWhitespace(element: Element): boolean;
11
- /**
12
- * Rewrites common web-page elements to ones the importer already understands.
13
- * Elements that will stay literal source are not entered, so their content is
14
- * preserved exactly.
15
- */
16
- export declare function normalizeClipboardHTML(root: Node): void;
17
- /**
18
- * Collapses source whitespace the way a browser renders it: runs become one
19
- * space, and none remains at the edges of a block or beside a line break.
20
- * `pre`, `code`, elements that stay literal source and elements whose style
21
- * keeps whitespace are not entered.
22
- */
23
- export declare function collapseClipboardWhitespace(root: Node): void;