somark-js 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 (85) hide show
  1. package/LICENSE +156 -0
  2. package/README.md +32 -0
  3. package/README_CN.md +31 -0
  4. package/dist/chunk-RWOUZTFQ.mjs +236 -0
  5. package/dist/cli.mjs +1503 -0
  6. package/dist/config-GOZJZCRT.mjs +26 -0
  7. package/dist/index.cjs +1304 -0
  8. package/dist/index.d.cts +258 -0
  9. package/dist/index.d.ts +258 -0
  10. package/dist/index.mjs +1245 -0
  11. package/package.json +66 -0
  12. package/vendor/somarkdown-viewer/LICENSE +21 -0
  13. package/vendor/somarkdown-viewer/README.md +63 -0
  14. package/vendor/somarkdown-viewer/README_CN.md +63 -0
  15. package/vendor/somarkdown-viewer/index.html +112 -0
  16. package/vendor/somarkdown-viewer/lib/bi-direction-jump.js +161 -0
  17. package/vendor/somarkdown-viewer/lib/deps/highlight.js.default.min.css +11 -0
  18. package/vendor/somarkdown-viewer/lib/deps/katex.min.css +6 -0
  19. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_AMS-Regular.ttf +0 -0
  20. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_AMS-Regular.woff +0 -0
  21. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_AMS-Regular.woff2 +0 -0
  22. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Bold.ttf +0 -0
  23. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Bold.woff +0 -0
  24. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Bold.woff2 +0 -0
  25. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Regular.ttf +0 -0
  26. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Regular.woff +0 -0
  27. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Caligraphic-Regular.woff2 +0 -0
  28. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Bold.ttf +0 -0
  29. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Bold.woff +0 -0
  30. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Bold.woff2 +0 -0
  31. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Regular.ttf +0 -0
  32. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Regular.woff +0 -0
  33. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Fraktur-Regular.woff2 +0 -0
  34. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Bold.ttf +0 -0
  35. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Bold.woff +0 -0
  36. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Bold.woff2 +0 -0
  37. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-BoldItalic.ttf +0 -0
  38. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-BoldItalic.woff +0 -0
  39. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-BoldItalic.woff2 +0 -0
  40. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Italic.ttf +0 -0
  41. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Italic.woff +0 -0
  42. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Italic.woff2 +0 -0
  43. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Regular.ttf +0 -0
  44. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Regular.woff +0 -0
  45. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Main-Regular.woff2 +0 -0
  46. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-BoldItalic.ttf +0 -0
  47. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-BoldItalic.woff +0 -0
  48. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-BoldItalic.woff2 +0 -0
  49. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-Italic.ttf +0 -0
  50. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-Italic.woff +0 -0
  51. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Math-Italic.woff2 +0 -0
  52. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Bold.ttf +0 -0
  53. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Bold.woff +0 -0
  54. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Bold.woff2 +0 -0
  55. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Italic.ttf +0 -0
  56. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Italic.woff +0 -0
  57. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Italic.woff2 +0 -0
  58. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Regular.ttf +0 -0
  59. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Regular.woff +0 -0
  60. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_SansSerif-Regular.woff2 +0 -0
  61. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Script-Regular.ttf +0 -0
  62. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Script-Regular.woff +0 -0
  63. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Script-Regular.woff2 +0 -0
  64. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size1-Regular.ttf +0 -0
  65. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size1-Regular.woff +0 -0
  66. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size1-Regular.woff2 +0 -0
  67. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size2-Regular.ttf +0 -0
  68. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size2-Regular.woff +0 -0
  69. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size2-Regular.woff2 +0 -0
  70. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size3-Regular.ttf +0 -0
  71. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size3-Regular.woff +0 -0
  72. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size3-Regular.woff2 +0 -0
  73. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size4-Regular.ttf +0 -0
  74. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size4-Regular.woff +0 -0
  75. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Size4-Regular.woff2 +0 -0
  76. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Typewriter-Regular.ttf +0 -0
  77. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Typewriter-Regular.woff +0 -0
  78. package/vendor/somarkdown-viewer/lib/deps/katex_fonts/KaTeX_Typewriter-Regular.woff2 +0 -0
  79. package/vendor/somarkdown-viewer/lib/i18n.js +81 -0
  80. package/vendor/somarkdown-viewer/lib/index.js +299 -0
  81. package/vendor/somarkdown-viewer/lib/somarkdown/VERSION +1 -0
  82. package/vendor/somarkdown-viewer/lib/somarkdown/somarkdown.css +591 -0
  83. package/vendor/somarkdown-viewer/lib/somarkdown/somarkdown.umd.min.js +59 -0
  84. package/vendor/somarkdown-viewer/lib/sync-scroll.js +147 -0
  85. package/vendor/somarkdown-viewer/style/index.css +527 -0
@@ -0,0 +1,81 @@
1
+ const messages = {
2
+ "zh-CN": {
3
+ "panel.source": "源码",
4
+ "panel.preview": "预览",
5
+ "settings.title": "设置",
6
+ "settings.lineNumbers": "行号映射",
7
+ "settings.colorChemistry": "化学式着色",
8
+ "settings.imageUnderstanding": "图片理解",
9
+ "settings.tocMaxLevel": "目录最大层级",
10
+ "settings.language": "界面语言",
11
+ "settings.about": "关于",
12
+ "settings.aboutText": "SoMarkDown 的目标是为专业场景提供强大灵活的 Markdown 渲染能力,同时为 LLM 提供简洁、无歧义、易解析的 Markdown 标准。",
13
+ "line.count": "{count} 行",
14
+ "errors.loadFile": "文件加载失败:{path}"
15
+ },
16
+ en: {
17
+ "panel.source": "Source",
18
+ "panel.preview": "Preview",
19
+ "settings.title": "Setting",
20
+ "settings.lineNumbers": "Line Number Mapping",
21
+ "settings.colorChemistry": "Color Chemistry",
22
+ "settings.imageUnderstanding": "Image Understanding",
23
+ "settings.tocMaxLevel": "TOC Max Level",
24
+ "settings.language": "Language",
25
+ "settings.about": "About",
26
+ "settings.aboutText": "SoMarkDown delivers a powerful and flexible Markdown rendering solution for professional users while providing LLMs with a concise, unambiguous, and parsable Markdown standard.",
27
+ "line.count": "{count} Lines",
28
+ "errors.loadFile": "Failed to load file: {path}"
29
+ }
30
+ };
31
+
32
+ class I18nManager {
33
+ constructor() {
34
+ this.language = this.detectLanguage();
35
+ this.changeHandlers = [];
36
+ }
37
+
38
+ detectLanguage() {
39
+ const lang = (navigator.language || "").toLowerCase();
40
+ if (lang.startsWith("zh")) {
41
+ return "zh-CN";
42
+ }
43
+ return "en";
44
+ }
45
+
46
+ onChange(handler) {
47
+ this.changeHandlers.push(handler);
48
+ }
49
+
50
+ setLanguage(language) {
51
+ if (!messages[language]) {
52
+ return;
53
+ }
54
+ this.language = language;
55
+ document.documentElement.lang = language === "zh-CN" ? "zh-CN" : "en";
56
+ this.translatePage();
57
+ this.changeHandlers.forEach((handler) => handler(language));
58
+ }
59
+
60
+ t(key, replacements = {}) {
61
+ const dict = messages[this.language] || messages.en;
62
+ let text = dict[key] || messages.en[key] || key;
63
+ Object.entries(replacements).forEach(([name, value]) => {
64
+ text = text.replace(`{${name}}`, String(value));
65
+ });
66
+ return text;
67
+ }
68
+
69
+ translatePage() {
70
+ const elements = document.querySelectorAll("[data-i18n]");
71
+ elements.forEach((element) => {
72
+ const key = element.getAttribute("data-i18n");
73
+ if (!key) {
74
+ return;
75
+ }
76
+ element.textContent = this.t(key);
77
+ });
78
+ }
79
+ }
80
+
81
+ export { I18nManager };
@@ -0,0 +1,299 @@
1
+ import { I18nManager } from "./i18n.js";
2
+ import { ScrollSync } from "./sync-scroll.js";
3
+ import { BiDirectionJump } from "./bi-direction-jump.js";
4
+
5
+ class SoMarkDownViewerApp {
6
+ constructor() {
7
+ this.elements = {
8
+ appContainer: document.getElementById("app-container"),
9
+ filePath: document.getElementById("file-path"),
10
+ source: document.getElementById("markdown-source"),
11
+ preview: document.getElementById("markdown-preview"),
12
+ previewViewport: document.getElementById("preview-viewport"),
13
+ lineNumbersInner: document.getElementById("line-numbers-inner"),
14
+ lineCountText: document.getElementById("line-count-text"),
15
+ settingPanel: document.getElementById("setting-panel"),
16
+ settingBackdrop: document.getElementById("setting-backdrop"),
17
+ openSettingBtn: document.getElementById("setting-open-btn"),
18
+ closeSettingBtn: document.getElementById("setting-close-btn"),
19
+ openFileBtn: document.getElementById("open-file-btn"),
20
+ localFileInput: document.getElementById("local-file-input"),
21
+ colorChemistryCheckbox: document.getElementById("color-chemistry-checkbox"),
22
+ imageUnderstandingCheckbox: document.getElementById("image-understanding-checkbox"),
23
+ tocLevelSlider: document.getElementById("toc-level-slider"),
24
+ tocLevelValue: document.getElementById("toc-level-value"),
25
+ languageSelect: document.getElementById("language-select")
26
+ };
27
+
28
+ this.i18n = new I18nManager();
29
+ this.scrollSync = new ScrollSync({
30
+ editor: this.elements.source,
31
+ previewViewport: this.elements.previewViewport,
32
+ preview: this.elements.preview
33
+ });
34
+ this.biDirectionJump = new BiDirectionJump({
35
+ editor: this.elements.source,
36
+ preview: this.elements.preview
37
+ });
38
+
39
+ this.settings = {
40
+ colorChemistry: true,
41
+ imageUnderstanding: true,
42
+ tocLevel: 3,
43
+ language: this.i18n.language
44
+ };
45
+
46
+ this.renderer = null;
47
+ this.currentPath = "docs/example.md";
48
+ this.renderPending = false;
49
+ }
50
+
51
+ async start() {
52
+ this.initSettingsUI();
53
+ this.initI18n();
54
+ this.initSourceEvents();
55
+ this.initFilePickerEvents();
56
+ this.initSettingPanelEvents();
57
+ this.scrollSync.start();
58
+ this.biDirectionJump.start();
59
+ await this.loadInitialContent();
60
+ this.syncSettingsUI();
61
+ this.updateLineNumbers();
62
+ this.renderMarkdown();
63
+ }
64
+
65
+ initI18n() {
66
+ this.i18n.onChange(() => {
67
+ this.updateLineNumbers();
68
+ if (this.renderer === null) {
69
+ this.renderMarkdown();
70
+ }
71
+ });
72
+ this.i18n.setLanguage(this.settings.language);
73
+ }
74
+
75
+ initSettingsUI() {
76
+ this.elements.colorChemistryCheckbox.checked = this.settings.colorChemistry;
77
+ this.elements.imageUnderstandingCheckbox.checked = this.settings.imageUnderstanding;
78
+ this.elements.tocLevelSlider.value = String(this.settings.tocLevel);
79
+ this.elements.tocLevelValue.textContent = String(this.settings.tocLevel);
80
+ this.elements.languageSelect.value = this.settings.language;
81
+ }
82
+
83
+ syncSettingsUI() {
84
+ this.elements.filePath.textContent = this.currentPath;
85
+ this.elements.tocLevelValue.textContent = String(this.settings.tocLevel);
86
+ this.elements.languageSelect.value = this.settings.language;
87
+ }
88
+
89
+ initSourceEvents() {
90
+ this.elements.source.addEventListener("input", () => {
91
+ this.updateLineNumbers();
92
+ this.renderMarkdown();
93
+ });
94
+ this.elements.source.addEventListener("keydown", (event) => {
95
+ this.handleSourceKeyDown(event);
96
+ });
97
+ this.elements.source.addEventListener("scroll", () => {
98
+ this.syncLineNumberScroll();
99
+ });
100
+ }
101
+
102
+ initFilePickerEvents() {
103
+ this.elements.openFileBtn.addEventListener("click", () => this.openFilePicker());
104
+ this.elements.localFileInput.addEventListener("change", () => {
105
+ this.handleLocalFileSelect();
106
+ });
107
+ }
108
+
109
+ openFilePicker() {
110
+ this.elements.localFileInput.click();
111
+ }
112
+
113
+ canPreviewFile(fileName) {
114
+ return /\.(md|smd|txt)$/i.test(fileName);
115
+ }
116
+
117
+ async handleLocalFileSelect() {
118
+ const selectedFile = this.elements.localFileInput.files?.[0];
119
+ if (!selectedFile) {
120
+ return;
121
+ }
122
+ if (!this.canPreviewFile(selectedFile.name)) {
123
+ this.elements.localFileInput.value = "";
124
+ return;
125
+ }
126
+ try {
127
+ const fileContent = await selectedFile.text();
128
+ this.currentPath = selectedFile.name;
129
+ this.elements.source.value = fileContent;
130
+ this.syncSettingsUI();
131
+ this.updateLineNumbers();
132
+ this.renderMarkdown();
133
+ } finally {
134
+ this.elements.localFileInput.value = "";
135
+ }
136
+ }
137
+
138
+ handleSourceKeyDown(event) {
139
+ if (event.key !== "Tab") {
140
+ return;
141
+ }
142
+
143
+ event.preventDefault();
144
+ const textarea = this.elements.source;
145
+ const start = textarea.selectionStart;
146
+ const end = textarea.selectionEnd;
147
+ const tabText = " ";
148
+
149
+ textarea.value = `${textarea.value.slice(0, start)}${tabText}${textarea.value.slice(end)}`;
150
+ const cursor = start + tabText.length;
151
+ textarea.setSelectionRange(cursor, cursor);
152
+ this.updateLineNumbers();
153
+ this.renderMarkdown();
154
+ }
155
+
156
+ initSettingPanelEvents() {
157
+ this.elements.openSettingBtn.addEventListener("click", () => this.openSettingPanel());
158
+ this.elements.closeSettingBtn.addEventListener("click", () => this.closeSettingPanel());
159
+ this.elements.settingBackdrop.addEventListener("click", () => this.closeSettingPanel());
160
+ document.addEventListener("keydown", (event) => {
161
+ if (event.key === "Escape") {
162
+ this.closeSettingPanel();
163
+ }
164
+ });
165
+
166
+ this.elements.colorChemistryCheckbox.addEventListener("change", () => {
167
+ this.settings.colorChemistry = this.elements.colorChemistryCheckbox.checked;
168
+ this.renderMarkdown();
169
+ });
170
+
171
+ this.elements.imageUnderstandingCheckbox.addEventListener("change", () => {
172
+ this.settings.imageUnderstanding = this.elements.imageUnderstandingCheckbox.checked;
173
+ this.renderMarkdown();
174
+ });
175
+
176
+ this.elements.tocLevelSlider.addEventListener("input", () => {
177
+ this.settings.tocLevel = Number.parseInt(this.elements.tocLevelSlider.value, 10) || 3;
178
+ this.elements.tocLevelValue.textContent = String(this.settings.tocLevel);
179
+ this.renderMarkdown();
180
+ });
181
+
182
+ this.elements.languageSelect.addEventListener("change", () => {
183
+ this.settings.language = this.elements.languageSelect.value;
184
+ this.i18n.setLanguage(this.settings.language);
185
+ });
186
+ }
187
+
188
+ openSettingPanel() {
189
+ this.elements.appContainer.classList.add("settings-open");
190
+ this.elements.settingPanel.classList.add("open");
191
+ }
192
+
193
+ closeSettingPanel() {
194
+ this.elements.appContainer.classList.remove("settings-open");
195
+ this.elements.settingPanel.classList.remove("open");
196
+ }
197
+
198
+ resolveMarkdownPath() {
199
+ const params = new URLSearchParams(window.location.search);
200
+ const rawPath = params.get("file");
201
+ if (!rawPath) {
202
+ return "docs/example.md";
203
+ }
204
+ return rawPath
205
+ .replace(/^[a-z]+:\/\/[^/]+/i, "")
206
+ .replace(/^\/+/, "");
207
+ }
208
+
209
+ async loadInitialContent() {
210
+ this.currentPath = this.resolveMarkdownPath();
211
+ this.syncSettingsUI();
212
+ const targetUrl = new URL(this.currentPath, window.location.origin);
213
+ try {
214
+ const response = await fetch(targetUrl.toString());
215
+ if (!response.ok) {
216
+ throw new Error(String(response.status));
217
+ }
218
+ const text = await response.text();
219
+ this.elements.source.value = text;
220
+ } catch (error) {
221
+ this.elements.source.value = `# ${this.i18n.t("errors.loadFile", { path: this.currentPath })}\n`;
222
+ }
223
+ }
224
+
225
+ updateLineNumbers() {
226
+ const sourceText = this.elements.source.value;
227
+ const lineCount = sourceText.length === 0 ? 1 : sourceText.split("\n").length;
228
+ const lineNumberHtml = Array.from({ length: lineCount }, (_, index) => `<div>${index + 1}</div>`).join("");
229
+ this.elements.lineNumbersInner.innerHTML = lineNumberHtml;
230
+ this.elements.lineCountText.textContent = this.i18n.t("line.count", { count: lineCount });
231
+ this.syncLineNumberScroll();
232
+ }
233
+
234
+ syncLineNumberScroll() {
235
+ this.elements.lineNumbersInner.style.transform = `translateY(${-this.elements.source.scrollTop}px)`;
236
+ }
237
+
238
+ createRenderer() {
239
+ const SoMarkDown = window.SoMarkDown;
240
+ if (!SoMarkDown) {
241
+ return null;
242
+ }
243
+ const includeLevel = Array.from({ length: this.settings.tocLevel }, (_, index) => index + 1);
244
+ return new SoMarkDown({
245
+ html: true,
246
+ typographer: true,
247
+ imgDescEnabled: this.settings.imageUnderstanding,
248
+ lineNumbers: {
249
+ enable: true,
250
+ nested: true
251
+ },
252
+ smiles: {
253
+ disableColors: !this.settings.colorChemistry
254
+ },
255
+ toc: {
256
+ includeLevel
257
+ }
258
+ });
259
+ }
260
+
261
+ ensurePreviewLinksOpenInNewPage() {
262
+ const links = this.elements.preview.querySelectorAll("a[href]");
263
+ links.forEach((link) => {
264
+ const href = link.getAttribute("href") || "";
265
+ if (href.startsWith("#")) {
266
+ return;
267
+ }
268
+ link.setAttribute("target", "_blank");
269
+ link.setAttribute("rel", "noopener noreferrer");
270
+ });
271
+ }
272
+
273
+ renderMarkdown() {
274
+ if (this.renderPending) {
275
+ return;
276
+ }
277
+ this.renderPending = true;
278
+ window.requestAnimationFrame(() => {
279
+ this.renderPending = false;
280
+ this.renderer = this.createRenderer();
281
+ if (!this.renderer) {
282
+ this.elements.preview.innerHTML = "<p>SoMarkDown not loaded.</p>";
283
+ return;
284
+ }
285
+ try {
286
+ this.elements.preview.className = "somarkdown-container theme-dark";
287
+ this.elements.preview.innerHTML = this.renderer.render(this.elements.source.value);
288
+ this.ensurePreviewLinksOpenInNewPage();
289
+ } catch (error) {
290
+ this.elements.preview.innerHTML = `<p>${String(error)}</p>`;
291
+ }
292
+ this.scrollSync.refreshMap();
293
+ this.biDirectionJump.refreshMap();
294
+ });
295
+ }
296
+ }
297
+
298
+ const app = new SoMarkDownViewerApp();
299
+ app.start();