supamde 0.0.0-stage → 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 (59) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +1225 -2
  3. package/dist/commands/block.d.ts +20 -0
  4. package/dist/commands/history.d.ts +6 -0
  5. package/dist/commands/indent.d.ts +18 -0
  6. package/dist/commands/inline.d.ts +9 -0
  7. package/dist/commands/keymap.d.ts +8 -0
  8. package/dist/commands/link-image.d.ts +13 -0
  9. package/dist/commands/list.d.ts +20 -0
  10. package/dist/commands/prefixes.d.ts +29 -0
  11. package/dist/commands/queries.d.ts +25 -0
  12. package/dist/commands/table.d.ts +7 -0
  13. package/dist/commands/types.d.ts +17 -0
  14. package/dist/editor/extensions.d.ts +14 -0
  15. package/dist/editor/highlight.d.ts +11 -0
  16. package/dist/editor/link-click.d.ts +53 -0
  17. package/dist/editor/link-hover-cursor.d.ts +44 -0
  18. package/dist/editor/math.d.ts +8 -0
  19. package/dist/editor/setup.d.ts +26 -0
  20. package/dist/editor/theme.d.ts +7 -0
  21. package/dist/editor/tokens.d.ts +16 -0
  22. package/dist/editor/value.d.ts +10 -0
  23. package/dist/features/autosave.d.ts +31 -0
  24. package/dist/features/image-upload.d.ts +73 -0
  25. package/dist/features/storage.d.ts +30 -0
  26. package/dist/features/upload-dom.d.ts +20 -0
  27. package/dist/features/upload-placeholder.d.ts +35 -0
  28. package/dist/features/word-count.d.ts +5 -0
  29. package/dist/i18n/de.d.ts +3 -0
  30. package/dist/i18n/en.d.ts +3 -0
  31. package/dist/i18n/facet.d.ts +9 -0
  32. package/dist/i18n/translator.d.ts +17 -0
  33. package/dist/i18n/types.d.ts +82 -0
  34. package/dist/index.d.ts +133 -0
  35. package/dist/livepreview/index.d.ts +22 -0
  36. package/dist/livepreview/plugin.d.ts +3 -0
  37. package/dist/livepreview/ranges.d.ts +62 -0
  38. package/dist/markdown/katex-marked.d.ts +20 -0
  39. package/dist/markdown/parse.d.ts +27 -0
  40. package/dist/markdown/sanitize.d.ts +6 -0
  41. package/dist/options.d.ts +80 -0
  42. package/dist/supamde.css +2 -0
  43. package/dist/supamde.mjs +3556 -0
  44. package/dist/supamde.mjs.map +1 -0
  45. package/dist/ui/actions.d.ts +51 -0
  46. package/dist/ui/fullscreen.d.ts +16 -0
  47. package/dist/ui/icons.d.ts +4 -0
  48. package/dist/ui/inject-styles.d.ts +13 -0
  49. package/dist/ui/preview.d.ts +27 -0
  50. package/dist/ui/shortcut-label.d.ts +24 -0
  51. package/dist/ui/statusbar.d.ts +28 -0
  52. package/dist/ui/toolbar-config.d.ts +36 -0
  53. package/dist/ui/toolbar.d.ts +16 -0
  54. package/dist/ui/update-listener.d.ts +15 -0
  55. package/dist/util/text-format.d.ts +11 -0
  56. package/dist/utils/html.d.ts +2 -0
  57. package/dist/utils/text.d.ts +41 -0
  58. package/dist/version.d.ts +2 -0
  59. package/package.json +96 -4
@@ -0,0 +1,51 @@
1
+ import type { EditorState } from '@codemirror/state';
2
+ import type { SupaCommand } from '../commands/types';
3
+ import type { EditorMode } from '../livepreview';
4
+ /** Plattformabhängiges Anzeige-Kürzel (unverändert). */
5
+ type Shortcut = string | {
6
+ default: string;
7
+ mac: string;
8
+ };
9
+ /** Strukturelles Minimal-Interface der SupaMDE-Instanz für view-Aktionen. */
10
+ export interface SupaLike {
11
+ toggleSideBySide(): void;
12
+ toggleFullScreen(): void;
13
+ isSideBySideActive(): boolean;
14
+ isFullscreenActive(): boolean;
15
+ togglePreviewFullScreen(): void;
16
+ isPreviewFullScreenActive(): boolean;
17
+ toggleEditorMode(): void;
18
+ getEditorMode(): EditorMode;
19
+ /** Startet den Upload für die übergebenen Dateien (M5). */
20
+ uploadImages(files: FileList | File[]): void;
21
+ /** Öffnet die Dateiauswahl (M5). */
22
+ openBrowseFileWindow(): void;
23
+ }
24
+ /** Ein Built-in-Toolbar-Eintrag: entweder CM6-Command oder Instanz-Aktion. */
25
+ export type ToolbarAction = {
26
+ kind: 'command';
27
+ command: SupaCommand;
28
+ query?: (state: EditorState) => boolean;
29
+ icon: string;
30
+ /**
31
+ * Anzeige-Kürzel für den Toolbar-Button-Title. Normalfall: einheitlicher
32
+ * String für alle Plattformen. Für Fälle, in denen macOS eine abweichende
33
+ * Bindung hat (z.B. redo via CM6-`historyKeymap`: `Mod-y` non-Mac,
34
+ * `Mod-Shift-z` auf Mac), ein `{ default, mac }`-Objekt verwenden.
35
+ */
36
+ shortcut?: Shortcut;
37
+ } | {
38
+ kind: 'view';
39
+ run: (editor: SupaLike) => void;
40
+ active?: (editor: SupaLike) => boolean;
41
+ icon: string;
42
+ shortcut?: Shortcut;
43
+ };
44
+ /**
45
+ * Registry: Built-in-Name → ToolbarAction. Die Anzeigetitel stehen NICHT hier,
46
+ * sondern als `toolbar.${name}` in den Locales (`src/i18n/`).
47
+ */
48
+ export declare const BUILTIN_ACTIONS: Record<string, ToolbarAction>;
49
+ /** Liefert die Action zu einem Built-in-Namen, oder undefined. */
50
+ export declare function getAction(name: string): ToolbarAction | undefined;
51
+ export {};
@@ -0,0 +1,16 @@
1
+ export interface FullscreenOptions {
2
+ onToggleFullScreen?: (active: boolean) => void;
3
+ }
4
+ export interface Fullscreen {
5
+ toggle(): void;
6
+ /** Schaltet gezielt auf `next`. Idempotent — gleicher Wert ändert nichts. */
7
+ set(next: boolean): void;
8
+ isActive(): boolean;
9
+ destroy(): void;
10
+ }
11
+ /**
12
+ * Fullscreen-Toggle: reines CSS über die Klasse `supamde-fullscreen` auf dem
13
+ * Container. Sperrt zusätzlich body-Scroll und lässt Escape den Modus
14
+ * verlassen. Unabhängig von Side-by-Side (keine Zwangskopplung).
15
+ */
16
+ export declare function createFullscreen(container: HTMLElement, opts?: FullscreenOptions): Fullscreen;
@@ -0,0 +1,4 @@
1
+ /** Ob ein Icon-Name bekannt ist. */
2
+ export declare function hasIcon(name: string): boolean;
3
+ /** Liefert ein fertiges Lucide-SVGElement für `name`; wirft bei unbekanntem Namen. */
4
+ export declare function renderIcon(name: string): SVGElement;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Fügt die SupaMDE-Styles EINMALIG als `<style>`-Tag in den Head ein.
3
+ *
4
+ * Im Library-Build extrahiert Vite `import './x.css'` in eine separate Datei
5
+ * (`dist/supamde.css`), die ein blosses `import SupaMDE from 'supamde'` NICHT
6
+ * mitlädt — die Toolbar käme ungestylt an. Deshalb liegt das CSS zusätzlich
7
+ * per `?inline` als String im Bundle und wird hier zur Laufzeit gesetzt.
8
+ *
9
+ * Das Tag landet als ERSTES Kind im Head, damit Host-Stylesheets bei gleicher
10
+ * Spezifität gewinnen (spätere Regel schlägt frühere) und Overrides ohne
11
+ * `!important` möglich bleiben.
12
+ */
13
+ export declare function injectStyles(doc?: Document): void;
@@ -0,0 +1,27 @@
1
+ import type { EditorView } from '@codemirror/view';
2
+ import type { EditorState } from '@codemirror/state';
3
+ export interface SideBySideOptions {
4
+ /** Markdown→HTML-Funktion (aus markdown/parse.ts, mit Optionen gebunden). */
5
+ render: (text: string) => string;
6
+ /** Zusätzliche CSS-Klassen aufs Panel. */
7
+ previewClass?: string | string[];
8
+ /** Bidirektionaler Scroll-Sync (Default true). */
9
+ syncScroll?: boolean;
10
+ }
11
+ export interface SideBySide {
12
+ dom: HTMLElement;
13
+ /** Schaltet gezielt auf `next`. Idempotent — gleicher Wert ändert nichts. */
14
+ set(next: boolean): void;
15
+ toggle(): void;
16
+ isActive(): boolean;
17
+ update(state: EditorState): void;
18
+ destroy(): void;
19
+ }
20
+ /**
21
+ * Side-by-Side-Vorschau: baut ein Panel neben `view.dom`. Das Layout-Toggle
22
+ * (Flexbox 50/50) übernimmt CSS über die Klasse `supamde-sided` auf dem
23
+ * Container (in index.ts gesetzt); dieses Modul verwaltet Panel-Inhalt,
24
+ * Sichtbarkeit und Scroll-Sync. Live-Update erfolgt über `update()`, das der
25
+ * zentrale updateListener-Sink ruft.
26
+ */
27
+ export declare function createSideBySide(view: EditorView, opts: SideBySideOptions): SideBySide;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Plattformabhängiges Shortcut-Kürzel: `default` gilt für alle Plattformen außer Mac,
3
+ * `mac` überschreibt die Anzeige (und ggf. Bindung) auf macOS. Nötig für Fälle wie
4
+ * redo, wo CM6s `historyKeymap` auf Mac `Mod-Shift-z` statt `Mod-y` bindet.
5
+ */
6
+ export interface PlatformShortcut {
7
+ default: string;
8
+ mac: string;
9
+ }
10
+ /**
11
+ * Formatiert einen CM6-Shortcut-String lesbar für die UI.
12
+ *
13
+ * Eingabeformat: CM6-kompatible Strings wie 'Mod-b', 'Shift-Mod-h', 'Mod-Alt-c', etc.
14
+ * Segmente sind mit `-` getrennt; alle außer dem letzten sind Modifier.
15
+ *
16
+ * Alternativ akzeptiert die Funktion ein plattformabhängiges Kürzel-Objekt
17
+ * `{ default, mac }` — auf Mac wird dann `mac` formatiert, sonst `default`.
18
+ *
19
+ * @param shortcut Der zu formatierende Shortcut-String (z.B. 'Mod-b') oder ein
20
+ * plattformabhängiges Kürzel-Objekt (z.B. `{ default: 'Mod-y', mac: 'Mod-Shift-z' }`)
21
+ * @param isMac Optionales Flag, um Plattform zu überschreiben (Default: auto-erkannt)
22
+ * @returns Formatierter Shortcut (z.B. '⌘B' auf Mac, 'Ctrl+B' sonst)
23
+ */
24
+ export declare function formatShortcut(shortcut: string | PlatformShortcut, isMac?: boolean): string;
@@ -0,0 +1,28 @@
1
+ import type { EditorState } from '@codemirror/state';
2
+ import { type Translator } from '../i18n/translator';
3
+ /** Ein Custom-Statusbar-Item (easyMDE-kompatibel). */
4
+ export interface CustomStatusItem {
5
+ className: string;
6
+ defaultValue?: string;
7
+ onUpdate?(el: HTMLElement): void;
8
+ onActivity?(el: HTMLElement): void;
9
+ }
10
+ /** Die `status`-Option: false, oder Liste aus Built-in-Namen/Custom-Items. */
11
+ export type StatusOption = false | Array<string | CustomStatusItem>;
12
+ /** Default-Statusbar-Items. */
13
+ export declare const DEFAULT_STATUS: string[];
14
+ /** Ein gerendertes Statusbar-Widget. */
15
+ export interface Statusbar {
16
+ dom: HTMLElement;
17
+ update(state: EditorState, opts: {
18
+ docChanged: boolean;
19
+ selectionSet: boolean;
20
+ }): void;
21
+ setItem(name: string, content: string): void;
22
+ destroy(): void;
23
+ }
24
+ /**
25
+ * Erzeugt die Statusbar aus der `status`-Option. `null` bei `false`.
26
+ * `translator` liefert die Texte der Built-ins; ohne Angabe englisch.
27
+ */
28
+ export declare function createStatusbar(option: StatusOption | undefined, translator?: Translator): Statusbar | null;
@@ -0,0 +1,36 @@
1
+ import { type ToolbarAction } from './actions';
2
+ /** Ein Custom-Toolbar-Button (easyMDE-kompatibel): eigenes action(editor). */
3
+ export interface CustomToolbarButton {
4
+ name: string;
5
+ action: (editor: unknown) => void;
6
+ className?: string;
7
+ title?: string;
8
+ }
9
+ /** Die `toolbar`-Option: false, oder Liste aus Built-in-Namen/Custom-Buttons. */
10
+ export type ToolbarOption = false | Array<string | CustomToolbarButton>;
11
+ /**
12
+ * Default-Toolbar. `'|'` ist ein Separator.
13
+ *
14
+ * Ansicht: der Default zeigt den kombinierten `'preview-fullscreen'`-Button
15
+ * (Vorschau + Vollbild in einem Schritt). Die Einzel-Buttons `'side-by-side'`
16
+ * und `'fullscreen'` bleiben registriert und lassen sich über die
17
+ * `toolbar`-Option weiterhin einzeln einsetzen.
18
+ */
19
+ export declare const DEFAULT_TOOLBAR: string[];
20
+ /** Aufgelöster Toolbar-Eintrag. */
21
+ export type ResolvedToolbarItem = {
22
+ kind: 'separator';
23
+ } | {
24
+ kind: 'builtin';
25
+ name: string;
26
+ action: ToolbarAction;
27
+ } | {
28
+ kind: 'custom';
29
+ button: CustomToolbarButton;
30
+ };
31
+ /**
32
+ * Normalisiert die `toolbar`-Option zu einer aufgelösten Item-Liste.
33
+ * `false` → null (keine Toolbar). `undefined` → DEFAULT_TOOLBAR.
34
+ * Unbekannte Built-in-Strings werden mit Warnung übersprungen.
35
+ */
36
+ export declare function resolveToolbar(option: ToolbarOption | undefined): ResolvedToolbarItem[] | null;
@@ -0,0 +1,16 @@
1
+ import type { EditorView } from '@codemirror/view';
2
+ import type { EditorState } from '@codemirror/state';
3
+ import { type ToolbarOption } from './toolbar-config';
4
+ import { type Translator } from '../i18n/translator';
5
+ /** Ein gerendertes Toolbar-Widget mit reaktivem Aktiv-Zustand. */
6
+ export interface Toolbar {
7
+ dom: HTMLElement;
8
+ update(state: EditorState): void;
9
+ destroy(): void;
10
+ }
11
+ /**
12
+ * Erzeugt die Toolbar aus der `toolbar`-Option. `null` bei `false`.
13
+ * `editor` ist die SupaMDE-Instanz, die Custom-Buttons als action-Argument bekommen.
14
+ * `translator` liefert die Titel der Built-in-Buttons; ohne Angabe englisch.
15
+ */
16
+ export declare function createToolbar(view: EditorView, option: ToolbarOption | undefined, editor: unknown, translator?: Translator): Toolbar | null;
@@ -0,0 +1,15 @@
1
+ import type { Extension, EditorState } from '@codemirror/state';
2
+ /** Empfänger für Editor-Updates (Toolbar-Aktiv-Zustand, Statusbar …). */
3
+ export interface UpdateSink {
4
+ onUpdate(update: {
5
+ state: EditorState;
6
+ docChanged: boolean;
7
+ selectionSet: boolean;
8
+ }): void;
9
+ }
10
+ /**
11
+ * Der EINE zentrale updateListener: bei jedem relevanten ViewUpdate wird
12
+ * `sink.onUpdate` mit dem neuen State und den Flags gerufen. Entkoppelt UI ↔
13
+ * Editor an einer Stelle (CM6-Design §5, „roter Faden").
14
+ */
15
+ export declare function updateListenerExtension(sink: UpdateSink): Extension;
@@ -0,0 +1,11 @@
1
+ /**
2
+ * Ersetzt ALLE Vorkommen von `{schlüssel}`. Benannte Platzhalter statt easyMDEs
3
+ * `#image_name#`, und bewusst alle Vorkommen: ein Text darf `{name}` mehrfach
4
+ * verwenden.
5
+ *
6
+ * Eingesetzte Werte werden NICHT erneut durchsucht — enthielte ein Wert selbst
7
+ * `{…}`, hinge das Ergebnis sonst von der Schlüsselreihenfolge ab.
8
+ */
9
+ export declare function formatText(template: string, values: Record<string, string>): string;
10
+ /** Bytes als lesbare Größe — nur für die Anzeige, keine exakte Rechnung. */
11
+ export declare function formatBytes(bytes: number): string;
@@ -0,0 +1,2 @@
1
+ /** Escaped die fünf HTML-kritischen Zeichen für sichere Text-in-HTML-Einbettung. */
2
+ export declare function escapeHtml(s: string): string;
@@ -0,0 +1,41 @@
1
+ import type { EditorState, Line } from '@codemirror/state';
2
+ import type { EditorView } from '@codemirror/view';
3
+ import type { DocChange } from '../commands/types';
4
+ /**
5
+ * Dispatcht zeilenweise Präfix-Änderungen und mappt die bestehende Selektion mit
6
+ * Rechts-Bias (`assoc: 1`) durch die Änderungen. Ohne diesen Bias lässt CM6 den
7
+ * Cursor an einer Einfügegrenze VOR dem eingefügten Marker stehen — auf einer
8
+ * leeren Zeile (Cursor == Zeilenanfang == Einfüge-`from`) bliebe er dadurch auf
9
+ * Spalte 1 statt hinter dem frisch gesetzten Marker.
10
+ */
11
+ export declare function dispatchLineChanges(view: EditorView, changes: DocChange[]): void;
12
+ /** Der volle Zeilenbereich, den die Hauptselektion berührt. */
13
+ export interface LineRange {
14
+ /** Doc-Offset am Anfang der ersten berührten Zeile. */
15
+ from: number;
16
+ /** Doc-Offset am Ende der letzten berührten Zeile. */
17
+ to: number;
18
+ /** 1-basierte Nummer der ersten Zeile. */
19
+ firstLine: number;
20
+ /** 1-basierte Nummer der letzten Zeile. */
21
+ lastLine: number;
22
+ }
23
+ /** Ermittelt den vollständigen Zeilenbereich der Hauptselektion. */
24
+ export declare function selectedLineRange(state: EditorState): LineRange;
25
+ /**
26
+ * Wendet `build` auf jede von der Hauptselektion berührte Zeile an und dispatcht
27
+ * die gesammelten Änderungen mit Selektionserhalt (siehe `dispatchLineChanges`).
28
+ * `build` liefert `null` für Zeilen ohne Änderung. Bleibt jede Zeile unverändert,
29
+ * wird nicht dispatcht — kein leerer Undo-Schritt. Liefert, ob dispatcht wurde.
30
+ */
31
+ export declare function mapSelectedLines(view: EditorView, build: (line: Line) => DocChange | null): boolean;
32
+ /**
33
+ * Toggelt ein Zeilen-Präfix über den Selektions-Zeilenbereich: tragen ALLE
34
+ * Zeilen das Präfix, wird es entfernt, sonst überall hinzugefügt.
35
+ */
36
+ export declare function toggleLinePrefix(view: EditorView, prefix: string): boolean;
37
+ /**
38
+ * Umschließt die Hauptselektion mit `before`/`after`. Bei leerer Selektion
39
+ * wird ein Marker-Paar eingefügt und der Cursor dazwischen platziert.
40
+ */
41
+ export declare function wrapSelection(view: EditorView, before: string, after: string): boolean;
@@ -0,0 +1,2 @@
1
+ /** Aktuelle SupaMDE-Version (wird beim Release synchron zur package.json gehalten). */
2
+ export declare const VERSION = "0.1.0";
package/package.json CHANGED
@@ -1,6 +1,98 @@
1
1
  {
2
2
  "name": "supamde",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
6
- }
3
+ "version": "0.1.0",
4
+ "description": "A modern, embeddable Markdown editor built on CodeMirror 6 — a modernized rewrite of easyMDE.",
5
+ "type": "module",
6
+ "license": "MIT",
7
+ "author": "Sven Deginther",
8
+ "repository": {
9
+ "type": "git",
10
+ "url": "git+https://github.com/svenho/SupaMDE.git"
11
+ },
12
+ "homepage": "https://github.com/svenho/SupaMDE#readme",
13
+ "bugs": {
14
+ "url": "https://github.com/svenho/SupaMDE/issues"
15
+ },
16
+ "engines": {
17
+ "node": "^22.13.0 || >=24"
18
+ },
19
+ "module": "./dist/supamde.mjs",
20
+ "types": "./dist/index.d.ts",
21
+ "exports": {
22
+ ".": {
23
+ "types": "./dist/index.d.ts",
24
+ "import": "./dist/supamde.mjs"
25
+ },
26
+ "./style.css": "./dist/supamde.css",
27
+ "./dist/supamde.css": "./dist/supamde.css"
28
+ },
29
+ "files": [
30
+ "dist/**/*"
31
+ ],
32
+ "keywords": [
33
+ "markdown",
34
+ "editor",
35
+ "codemirror",
36
+ "codemirror6",
37
+ "wysiwyg",
38
+ "easymde"
39
+ ],
40
+ "scripts": {
41
+ "dev": "vite",
42
+ "build:demo": "vite build --config vite.config.demo.ts",
43
+ "build": "vite build && tsc --project tsconfig.build.json --emitDeclarationOnly",
44
+ "typecheck": "tsc --project tsconfig.test.json --noEmit",
45
+ "test": "vitest --project unit",
46
+ "test:run": "vitest run --project unit",
47
+ "test:browser": "vitest run --project browser",
48
+ "test:all": "vitest run",
49
+ "lint": "eslint .",
50
+ "format": "prettier --write .",
51
+ "prepare": "npm run build",
52
+ "prepublishOnly": "npm run lint && npm run typecheck && npm run test:all"
53
+ },
54
+ "devDependencies": {
55
+ "@codemirror/commands": "^6.10.4",
56
+ "@codemirror/lang-markdown": "^6.5.1",
57
+ "@codemirror/language": "^6.12.4",
58
+ "@codemirror/state": "^6.7.1",
59
+ "@codemirror/view": "^6.43.6",
60
+ "@eslint/js": "^10.0.1",
61
+ "@lezer/common": "^1.2.3",
62
+ "@lezer/highlight": "^1.2.3",
63
+ "@lezer/markdown": "^1.7.2",
64
+ "@types/node": "^22.20.1",
65
+ "@vitest/browser": "5.0.3",
66
+ "@vitest/browser-playwright": "5.0.3",
67
+ "@vitest/coverage-v8": "5.0.3",
68
+ "eslint": "^10.7.0",
69
+ "jsdom": "^29.1.1",
70
+ "katex": "^0.19.0",
71
+ "lucide": "^1.25.0",
72
+ "playwright": "^1.63.0",
73
+ "prettier": "^3.9.5",
74
+ "typescript": "^5.9.3",
75
+ "typescript-eslint": "^8.64.0",
76
+ "vite": "^8.1.5",
77
+ "vitest": "5.0.3"
78
+ },
79
+ "peerDependencies": {
80
+ "@codemirror/commands": "^6.10.4",
81
+ "@codemirror/lang-markdown": "^6.5.1",
82
+ "@codemirror/language": "^6.12.4",
83
+ "@codemirror/state": "^6.7.1",
84
+ "@codemirror/view": "^6.43.6",
85
+ "@lezer/common": "^1.2.3",
86
+ "@lezer/highlight": "^1.2.3",
87
+ "@lezer/markdown": "^1.7.2",
88
+ "katex": "^0.18.0 || ^0.19.0"
89
+ },
90
+ "peerDependenciesMeta": {
91
+ "katex": {
92
+ "optional": true
93
+ }
94
+ },
95
+ "dependencies": {
96
+ "marked": "^18.0.7"
97
+ }
98
+ }