@file-viewer/renderer-text 2.4.0 → 3.0.1
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/README.en.md +11 -4
- package/README.md +11 -4
- package/dist/code.d.ts +3 -5
- package/dist/code.js +176 -35
- package/dist/codeStyle.d.ts +1 -1
- package/dist/codeStyle.js +18 -4
- package/dist/gitBundle.js +10 -1
- package/dist/index.d.ts +3 -0
- package/dist/index.js +2 -0
- package/dist/largeText.js +170 -16
- package/dist/markdown.d.ts +1 -0
- package/dist/markdown.js +40 -40
- package/dist/optionalCapabilities.d.ts +21 -0
- package/dist/optionalCapabilities.js +19 -0
- package/dist/patch.js +9 -15
- package/dist/prettyPrint.d.ts +35 -0
- package/dist/prettyPrint.js +232 -0
- package/dist/sanitizeHtml.d.ts +5 -0
- package/dist/sanitizeHtml.js +47 -0
- package/file-viewer.capability.json +12 -0
- package/package.json +15 -8
package/README.en.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @file-viewer/renderer-text
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Base code, text, and Markdown renderer package for Flyfish File Viewer. Mermaid, side-by-side patch diff, and Git bundle inspection live in `@file-viewer/capability-mermaid` and `@file-viewer/capability-text-tools`; they are excluded from the standard/full default closure.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
|
@@ -13,6 +13,9 @@ const options = {
|
|
|
13
13
|
renderers: textRenderer,
|
|
14
14
|
text: {
|
|
15
15
|
lineNumbers: true,
|
|
16
|
+
wrapLongLines: true,
|
|
17
|
+
prettyPrint: true,
|
|
18
|
+
prettyPrintMaxBytes: 512 * 1024,
|
|
16
19
|
},
|
|
17
20
|
}
|
|
18
21
|
```
|
|
@@ -34,8 +37,12 @@ const options = {
|
|
|
34
37
|
- Code and text preview uses `highlight.js` core with per-language dynamic imports instead of registering every language up front.
|
|
35
38
|
- Code, text, and virtualized Markdown source views show their file type, indexing status, and line-count metadata bar by default. Set `options.text.toolbar: false` to hide this renderer-local bar without hiding the viewer-level download, search, or zoom toolbar.
|
|
36
39
|
- Regular code and text previews can show a line-number gutter with `options.text.lineNumbers: true`. The gutter is excluded from copied source, search matches, and assistive reading. Virtual large-text views keep their existing gutter unless it is explicitly set to `false`.
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
40
|
+
- `options.text.wrapLongLines: true` changes layout only and never inserts source newlines. Regular previews keep one gutter entry per logical line; large files remain bounded in the virtual window while wrapping to the available width.
|
|
41
|
+
- `options.text.prettyPrint: true` lazily loads Prettier and only the parser plugins needed by a supported structured format. It formats a display copy, labels the toolbar as a formatted preview, and provides a switch back to the original source. JSON/JSONC/JSON5, JavaScript/TypeScript, HTML/Vue, CSS, YAML, Markdown, GraphQL, and XML share this path.
|
|
42
|
+
- `prettyPrintMaxBytes` limits only Prettier and defaults to the effective `virtualizeAboveBytes` value (512 KiB when omitted). Oversized, malformed, and unsupported inputs fall back to the original source, which continues through the existing regular or virtual renderer. XML uses a conservative whitespace-preserving mode; mixed content and `xml:space="preserve"` stay on the original source path.
|
|
43
|
+
- The legacy `*-full` script-tag IIFE assets do not bundle Prettier, so `prettyPrint` falls back to the original source there. Use the ESM integration (standard component packages or `@file-viewer/preset-*`) for formatted previews.
|
|
44
|
+
- With the text-tools capability installed, `patch` uses `diff2html` for side-by-side review and `bundle` / `bdl` enables Git bundle inspection.
|
|
45
|
+
- With the Mermaid capability installed, fenced Mermaid blocks render as diagrams. Without it, the source stays visible with the exact CLI enablement command.
|
|
39
46
|
- HTML, XML, Vue, and similar files are escaped and shown as source, never executed.
|
|
40
47
|
- Markdown uses `marked` for a read-only reading surface with dark/light theme support, table scrolling, and a unified zoom provider.
|
|
41
48
|
- Markdown no longer falls back to source because of the general large-text threshold. Set `options.text.markdownVirtualizeAboveBytes` only when an application must bound exceptionally large Markdown files.
|
|
@@ -43,4 +50,4 @@ const options = {
|
|
|
43
50
|
|
|
44
51
|
## Migration Note
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
Standard/full includes base code, text, and Markdown without installing `diff2html`, `pako`, or Mermaid. Optional uploads show `npx file-viewer-cli add text-tools --write` or `add mermaid-markdown --write`; `preset-all` is only for explicit all/debug use.
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# @file-viewer/renderer-text
|
|
2
2
|
|
|
3
|
-
Flyfish File Viewer
|
|
3
|
+
Flyfish File Viewer 的基础代码、文本和 Markdown renderer 包。Mermaid、patch 左右比对和 Git bundle 检查已拆到 `@file-viewer/capability-mermaid` 与 `@file-viewer/capability-text-tools`,不进入 standard/full 默认闭包。
|
|
4
4
|
|
|
5
5
|
## 用法
|
|
6
6
|
|
|
@@ -13,6 +13,9 @@ const options = {
|
|
|
13
13
|
renderers: textRenderer,
|
|
14
14
|
text: {
|
|
15
15
|
lineNumbers: true,
|
|
16
|
+
wrapLongLines: true,
|
|
17
|
+
prettyPrint: true,
|
|
18
|
+
prettyPrintMaxBytes: 512 * 1024,
|
|
16
19
|
},
|
|
17
20
|
}
|
|
18
21
|
```
|
|
@@ -34,8 +37,12 @@ const options = {
|
|
|
34
37
|
- 代码和文本使用 `highlight.js` core + 按语言动态加载,避免一次性注册全部语言。
|
|
35
38
|
- 代码、文本和超大 Markdown 源码视图默认显示文件类型、索引状态和行数元信息栏;传入 `options.text.toolbar: false` 可隐藏该 renderer 内部栏,不影响 Viewer 的下载、搜索、缩放等全局工具栏。
|
|
36
39
|
- 普通代码和文本可通过 `options.text.lineNumbers: true` 显示行号;行号不会进入复制内容、搜索结果或无障碍朗读。超大文本保留原有的虚拟行号栏,可显式传 `false` 隐藏。
|
|
37
|
-
- `
|
|
38
|
-
- `
|
|
40
|
+
- `options.text.wrapLongLines: true` 仅改变布局,不向源码插入换行。普通预览会按逻辑行维护行号,超大文本仍使用有界虚拟窗口并按可用宽度换行。
|
|
41
|
+
- `options.text.prettyPrint: true` 会在支持的结构化文本上按需加载 Prettier 与对应 parser,仅格式化显示副本;工具栏会标明“格式化预览”,并可切回原始源码。JSON/JSONC/JSON5、JavaScript/TypeScript、HTML/Vue、CSS、YAML、Markdown、GraphQL 和 XML 共用同一路径。
|
|
42
|
+
- `prettyPrintMaxBytes` 只限制 Prettier,默认继承 `virtualizeAboveBytes`(未配置时为 512 KiB)。超限、语法错误或不支持的格式直接回退原始源码,之后仍由普通或虚拟文本 renderer 决定展示方式。XML 使用保守的 whitespace-preserving 模式;检测到混合内容或 `xml:space="preserve"` 时直接保留原文。
|
|
43
|
+
- 历史 `*-full` 包的 script 标签 IIFE 资源不打包 Prettier,该路径下 `prettyPrint` 无错误回退到原始源码;需要格式化预览时使用 ESM 集成(标准组件包或 `@file-viewer/preset-*`)。
|
|
44
|
+
- 安装 text-tools capability 后,`patch` 使用 `diff2html` 渲染左右比对视图,`bundle` / `bdl` 才启用 Git bundle 结构检查。
|
|
45
|
+
- 安装 Mermaid capability 后,Markdown 内嵌 Mermaid 图才会渲染;未安装时保留源码并显示精确 CLI 启用命令。
|
|
39
46
|
- HTML / XML / Vue 等文件按源码方式转义展示,不执行脚本。
|
|
40
47
|
- Markdown 使用 `marked` 输出只读阅读面,并保留明暗主题、表格滚动和统一缩放 provider。
|
|
41
48
|
- Markdown 不再因为通用大文本阈值自动退化成源码;如业务必须限制超大 Markdown,可单独设置 `options.text.markdownVirtualizeAboveBytes`。
|
|
@@ -43,4 +50,4 @@ const options = {
|
|
|
43
50
|
|
|
44
51
|
## 迁移说明
|
|
45
52
|
|
|
46
|
-
|
|
53
|
+
standard/full 默认包含基础代码、文本和 Markdown,不安装 `diff2html`、`pako` 或 Mermaid。打开可选格式时会提示运行 `npx file-viewer-cli add text-tools --write` 或 `add mermaid-markdown --write`;`preset-all` 仅用于显式全量/调试。
|
package/dist/code.d.ts
CHANGED
|
@@ -2,10 +2,8 @@ import { type FileRenderContext, type FileViewerRenderedInstance } from '@file-v
|
|
|
2
2
|
/**
|
|
3
3
|
* Framework-neutral text/code renderer.
|
|
4
4
|
*
|
|
5
|
-
* highlight.js core and
|
|
6
|
-
* and XML are
|
|
7
|
-
*
|
|
8
|
-
* @param target 目标
|
|
9
|
-
* @param type 文件扩展名,用于选择 highlight.js 语言
|
|
5
|
+
* highlight.js core, Prettier standalone, and parser definitions are loaded
|
|
6
|
+
* lazily by format. HTML and XML are always mounted as escaped source text and
|
|
7
|
+
* never executed as real DOM.
|
|
10
8
|
*/
|
|
11
9
|
export default function renderText(buffer: ArrayBuffer, target: HTMLDivElement, type?: string, context?: FileRenderContext): Promise<FileViewerRenderedInstance>;
|
package/dist/code.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, decodeFileViewerTextBuffer, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
2
2
|
import { codeStyle } from './codeStyle.js';
|
|
3
3
|
import renderLargeText, { shouldVirtualizeTextBuffer } from './largeText.js';
|
|
4
|
+
import { formatFileViewerTextForDisplay, resolveFileViewerPrettyPrintMaxBytes, supportsFileViewerPrettyPrint } from './prettyPrint.js';
|
|
4
5
|
const languageMap = {
|
|
5
6
|
bash: 'bash',
|
|
6
7
|
c: 'cpp',
|
|
@@ -15,6 +16,8 @@ const languageMap = {
|
|
|
15
16
|
bdl: 'plaintext',
|
|
16
17
|
gv: 'plaintext',
|
|
17
18
|
go: 'go',
|
|
19
|
+
graphql: 'graphql',
|
|
20
|
+
gql: 'graphql',
|
|
18
21
|
h: 'cpp',
|
|
19
22
|
hcl: 'plaintext',
|
|
20
23
|
hpp: 'cpp',
|
|
@@ -60,6 +63,7 @@ const languageLoaders = {
|
|
|
60
63
|
css: () => import('highlight.js/lib/languages/css'),
|
|
61
64
|
diff: () => import('highlight.js/lib/languages/diff'),
|
|
62
65
|
go: () => import('highlight.js/lib/languages/go'),
|
|
66
|
+
graphql: () => import('highlight.js/lib/languages/graphql'),
|
|
63
67
|
http: () => import('highlight.js/lib/languages/http'),
|
|
64
68
|
ini: () => import('highlight.js/lib/languages/ini'),
|
|
65
69
|
java: () => import('highlight.js/lib/languages/java'),
|
|
@@ -81,8 +85,8 @@ const languageLoaders = {
|
|
|
81
85
|
};
|
|
82
86
|
let highlighterPromise = null;
|
|
83
87
|
const registeredLanguages = new Set();
|
|
84
|
-
const createElement = (tagName, className, text) => {
|
|
85
|
-
const element =
|
|
88
|
+
const createElement = (documentRef, tagName, className, text) => {
|
|
89
|
+
const element = documentRef.createElement(tagName);
|
|
86
90
|
if (className) {
|
|
87
91
|
element.className = className;
|
|
88
92
|
}
|
|
@@ -91,8 +95,8 @@ const createElement = (tagName, className, text) => {
|
|
|
91
95
|
}
|
|
92
96
|
return element;
|
|
93
97
|
};
|
|
94
|
-
const createStyle = () => {
|
|
95
|
-
const style =
|
|
98
|
+
const createStyle = (documentRef) => {
|
|
99
|
+
const style = documentRef.createElement('style');
|
|
96
100
|
style.textContent = codeStyle;
|
|
97
101
|
return style;
|
|
98
102
|
};
|
|
@@ -139,21 +143,122 @@ const lineCountOf = (value) => {
|
|
|
139
143
|
const createLineNumberText = (lineCount) => {
|
|
140
144
|
return Array.from({ length: lineCount }, (_, index) => String(index + 1)).join('\n');
|
|
141
145
|
};
|
|
146
|
+
const createWrappedSourceLine = (documentRef, lineNumber) => {
|
|
147
|
+
const row = createElement(documentRef, 'span', 'code-source-line');
|
|
148
|
+
row.dataset.line = String(lineNumber);
|
|
149
|
+
const number = createElement(documentRef, 'span', 'code-source-line-number', String(lineNumber));
|
|
150
|
+
number.setAttribute('aria-hidden', 'true');
|
|
151
|
+
const content = createElement(documentRef, 'span', 'code-source-line-content');
|
|
152
|
+
row.append(number, content);
|
|
153
|
+
return { row, content };
|
|
154
|
+
};
|
|
155
|
+
/**
|
|
156
|
+
* Splits trusted highlight.js markup into logical source-line wrappers while
|
|
157
|
+
* recreating active token spans after every newline. This keeps multiline
|
|
158
|
+
* comments and strings highlighted without coupling visual wrapping to source
|
|
159
|
+
* line numbers.
|
|
160
|
+
*/
|
|
161
|
+
const mountWrappedHighlightedLines = (code, highlightedHtml, expectedLineCount) => {
|
|
162
|
+
const documentRef = code.ownerDocument;
|
|
163
|
+
const staging = createElement(documentRef, 'span');
|
|
164
|
+
staging.innerHTML = highlightedHtml;
|
|
165
|
+
const lines = [createWrappedSourceLine(documentRef, 1)];
|
|
166
|
+
let lineIndex = 0;
|
|
167
|
+
const activeElements = [];
|
|
168
|
+
let activeClones = [];
|
|
169
|
+
const currentContent = () => lines[lineIndex].content;
|
|
170
|
+
const currentParent = () => { var _a; return (_a = activeClones[activeClones.length - 1]) !== null && _a !== void 0 ? _a : currentContent(); };
|
|
171
|
+
const continueOnNextLine = () => {
|
|
172
|
+
lineIndex += 1;
|
|
173
|
+
lines.push(createWrappedSourceLine(documentRef, lineIndex + 1));
|
|
174
|
+
let parent = currentContent();
|
|
175
|
+
activeClones = activeElements.map(element => {
|
|
176
|
+
const clone = element.cloneNode(false);
|
|
177
|
+
parent.append(clone);
|
|
178
|
+
parent = clone;
|
|
179
|
+
return clone;
|
|
180
|
+
});
|
|
181
|
+
};
|
|
182
|
+
const visit = (node) => {
|
|
183
|
+
var _a;
|
|
184
|
+
if (node.nodeType === 3) {
|
|
185
|
+
const parts = ((_a = node.textContent) !== null && _a !== void 0 ? _a : '').split(/\r\n|\r|\n/);
|
|
186
|
+
parts.forEach((part, index) => {
|
|
187
|
+
if (part) {
|
|
188
|
+
currentParent().append(documentRef.createTextNode(part));
|
|
189
|
+
}
|
|
190
|
+
if (index < parts.length - 1) {
|
|
191
|
+
continueOnNextLine();
|
|
192
|
+
}
|
|
193
|
+
});
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
if (node.nodeType !== 1) {
|
|
197
|
+
return;
|
|
198
|
+
}
|
|
199
|
+
const element = node;
|
|
200
|
+
const clone = element.cloneNode(false);
|
|
201
|
+
currentParent().append(clone);
|
|
202
|
+
activeElements.push(element);
|
|
203
|
+
activeClones.push(clone);
|
|
204
|
+
Array.from(element.childNodes).forEach(visit);
|
|
205
|
+
activeElements.pop();
|
|
206
|
+
activeClones.pop();
|
|
207
|
+
};
|
|
208
|
+
Array.from(staging.childNodes).forEach(visit);
|
|
209
|
+
while (lines.length < expectedLineCount) {
|
|
210
|
+
lines.push(createWrappedSourceLine(documentRef, lines.length + 1));
|
|
211
|
+
}
|
|
212
|
+
code.replaceChildren(...lines.map(line => line.row));
|
|
213
|
+
};
|
|
214
|
+
const mountCodeMarkup = (pre, code, highlightedHtml, lineCount, showLineNumbers, wrapLongLines) => {
|
|
215
|
+
code.replaceChildren();
|
|
216
|
+
if (showLineNumbers && wrapLongLines) {
|
|
217
|
+
pre.className = 'code-area code-area--wrapped-line-numbers';
|
|
218
|
+
pre.replaceChildren(code);
|
|
219
|
+
mountWrappedHighlightedLines(code, highlightedHtml, lineCount);
|
|
220
|
+
return;
|
|
221
|
+
}
|
|
222
|
+
pre.className = showLineNumbers ? 'code-area code-area--line-numbers' : 'code-area';
|
|
223
|
+
if (showLineNumbers) {
|
|
224
|
+
const gutter = createElement(pre.ownerDocument, 'span', 'code-line-numbers', createLineNumberText(lineCount));
|
|
225
|
+
gutter.setAttribute('aria-hidden', 'true');
|
|
226
|
+
pre.replaceChildren(gutter, code);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
pre.replaceChildren(code);
|
|
230
|
+
}
|
|
231
|
+
code.innerHTML = highlightedHtml;
|
|
232
|
+
};
|
|
233
|
+
const canPossiblyFitDecodedPrettyPrintLimit = (buffer, maxBytes) => {
|
|
234
|
+
// UTF-16 ASCII is the widest supported source encoding relative to its
|
|
235
|
+
// decoded UTF-8 representation. This fast guard avoids decoding enormous
|
|
236
|
+
// structured files that cannot possibly fit the configured decoded limit.
|
|
237
|
+
return buffer.byteLength <= (maxBytes * 2) + 4;
|
|
238
|
+
};
|
|
142
239
|
/**
|
|
143
240
|
* Framework-neutral text/code renderer.
|
|
144
241
|
*
|
|
145
|
-
* highlight.js core and
|
|
146
|
-
* and XML are
|
|
147
|
-
*
|
|
148
|
-
* @param target 目标
|
|
149
|
-
* @param type 文件扩展名,用于选择 highlight.js 语言
|
|
242
|
+
* highlight.js core, Prettier standalone, and parser definitions are loaded
|
|
243
|
+
* lazily by format. HTML and XML are always mounted as escaped source text and
|
|
244
|
+
* never executed as real DOM.
|
|
150
245
|
*/
|
|
151
246
|
export default async function renderText(buffer, target, type, context) {
|
|
152
|
-
var _a, _b
|
|
247
|
+
var _a, _b;
|
|
153
248
|
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
154
249
|
const extension = type || 'txt';
|
|
155
250
|
const normalizedExtension = extension.trim().toLowerCase();
|
|
156
|
-
|
|
251
|
+
const textOptions = (_a = context === null || context === void 0 ? void 0 : context.options) === null || _a === void 0 ? void 0 : _a.text;
|
|
252
|
+
let sourceText;
|
|
253
|
+
let prettyPrintResult;
|
|
254
|
+
if ((textOptions === null || textOptions === void 0 ? void 0 : textOptions.prettyPrint) === true &&
|
|
255
|
+
supportsFileViewerPrettyPrint(normalizedExtension) &&
|
|
256
|
+
canPossiblyFitDecodedPrettyPrintLimit(buffer, resolveFileViewerPrettyPrintMaxBytes(textOptions))) {
|
|
257
|
+
sourceText = decodeFileViewerTextBuffer(buffer, textOptions.encoding).text;
|
|
258
|
+
prettyPrintResult = await formatFileViewerTextForDisplay(sourceText, normalizedExtension, textOptions, context === null || context === void 0 ? void 0 : context.signal);
|
|
259
|
+
}
|
|
260
|
+
if (!(prettyPrintResult === null || prettyPrintResult === void 0 ? void 0 : prettyPrintResult.formatted) &&
|
|
261
|
+
normalizedExtension !== 'bundle' &&
|
|
157
262
|
normalizedExtension !== 'bdl' &&
|
|
158
263
|
shouldVirtualizeTextBuffer(buffer, context)) {
|
|
159
264
|
return renderLargeText(buffer, target, extension, context);
|
|
@@ -166,58 +271,92 @@ export default async function renderText(buffer, target, type, context) {
|
|
|
166
271
|
const { default: renderGitBundle } = await import('./gitBundle.js');
|
|
167
272
|
return renderGitBundle(buffer, target, extension, context);
|
|
168
273
|
}
|
|
169
|
-
const
|
|
274
|
+
const originalText = sourceText !== null && sourceText !== void 0 ? sourceText : decodeFileViewerTextBuffer(buffer, textOptions === null || textOptions === void 0 ? void 0 : textOptions.encoding).text;
|
|
275
|
+
const formattedText = (prettyPrintResult === null || prettyPrintResult === void 0 ? void 0 : prettyPrintResult.formatted) ? prettyPrintResult.text : null;
|
|
170
276
|
const language = resolveLanguage(extension);
|
|
171
|
-
const
|
|
172
|
-
const
|
|
173
|
-
const
|
|
277
|
+
const showToolbar = (textOptions === null || textOptions === void 0 ? void 0 : textOptions.toolbar) !== false;
|
|
278
|
+
const showLineNumbers = (textOptions === null || textOptions === void 0 ? void 0 : textOptions.lineNumbers) === true;
|
|
279
|
+
const wrapLongLines = (textOptions === null || textOptions === void 0 ? void 0 : textOptions.wrapLongLines) === true;
|
|
280
|
+
const documentRef = target.ownerDocument;
|
|
174
281
|
let disposed = false;
|
|
175
282
|
let zoom = 1;
|
|
283
|
+
let showingFormatted = formattedText !== null;
|
|
284
|
+
let renderGeneration = 0;
|
|
176
285
|
const zoomEmitter = createZoomChangeEmitter();
|
|
177
|
-
const root = createElement('div', 'code-viewer');
|
|
286
|
+
const root = createElement(documentRef, 'div', wrapLongLines ? 'code-viewer code-viewer--wrap-lines' : 'code-viewer');
|
|
178
287
|
root.dataset.viewerZoomProvider = 'code';
|
|
179
288
|
root.dataset.textToolbar = String(showToolbar);
|
|
180
289
|
root.dataset.lineNumbers = String(showLineNumbers);
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
const
|
|
184
|
-
const
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
290
|
+
root.dataset.wrapLongLines = String(wrapLongLines);
|
|
291
|
+
root.dataset.prettyPrint = (_b = prettyPrintResult === null || prettyPrintResult === void 0 ? void 0 : prettyPrintResult.reason) !== null && _b !== void 0 ? _b : 'disabled';
|
|
292
|
+
const toolbar = createElement(documentRef, 'div', 'code-toolbar');
|
|
293
|
+
const extensionLabel = createElement(documentRef, 'span', '', extension.toUpperCase());
|
|
294
|
+
const toolbarMeta = createElement(documentRef, 'div', 'code-toolbar-meta');
|
|
295
|
+
const representationStatus = createElement(documentRef, 'span', 'code-format-status');
|
|
296
|
+
const representationToggle = createElement(documentRef, 'button', 'code-format-toggle');
|
|
297
|
+
representationToggle.type = 'button';
|
|
298
|
+
const lineSummary = createElement(documentRef, 'strong');
|
|
299
|
+
toolbarMeta.append(representationStatus, representationToggle, lineSummary);
|
|
300
|
+
toolbar.append(extensionLabel, toolbarMeta);
|
|
301
|
+
const pre = createElement(documentRef, 'pre', 'code-area');
|
|
302
|
+
const code = createElement(documentRef, 'code', `hljs language-${language}`);
|
|
193
303
|
pre.append(code);
|
|
194
304
|
if (showToolbar) {
|
|
195
305
|
root.append(toolbar);
|
|
196
306
|
}
|
|
197
307
|
root.append(pre);
|
|
198
308
|
root.style.setProperty('--code-font-size', `${13 * zoom}px`);
|
|
199
|
-
target.replaceChildren(createStyle(), root);
|
|
200
|
-
const
|
|
309
|
+
target.replaceChildren(createStyle(documentRef), root);
|
|
310
|
+
const currentText = () => showingFormatted && formattedText !== null ? formattedText : originalText;
|
|
311
|
+
const syncRepresentationControls = (lineCount) => {
|
|
312
|
+
const formatted = showingFormatted && formattedText !== null;
|
|
313
|
+
root.dataset.textRepresentation = formatted ? 'formatted' : 'source';
|
|
314
|
+
lineSummary.textContent = `${lineCount} lines`;
|
|
315
|
+
representationStatus.hidden = !formatted;
|
|
316
|
+
representationStatus.textContent = formatted ? t('text.code.formattedPreview') : '';
|
|
317
|
+
representationToggle.hidden = formattedText === null;
|
|
318
|
+
representationToggle.textContent = formatted
|
|
319
|
+
? t('text.code.showOriginal')
|
|
320
|
+
: t('text.code.showFormatted');
|
|
321
|
+
representationToggle.setAttribute('aria-pressed', String(formatted));
|
|
322
|
+
};
|
|
323
|
+
const renderCurrentRepresentation = async () => {
|
|
324
|
+
const generation = renderGeneration + 1;
|
|
325
|
+
renderGeneration = generation;
|
|
326
|
+
const text = currentText();
|
|
327
|
+
const lineCount = lineCountOf(text);
|
|
328
|
+
syncRepresentationControls(lineCount);
|
|
201
329
|
if (language === 'plaintext') {
|
|
330
|
+
mountCodeMarkup(pre, code, escapeHtml(text), lineCount, showLineNumbers, wrapLongLines);
|
|
202
331
|
return;
|
|
203
332
|
}
|
|
333
|
+
code.textContent = t('text.code.loadingHighlight');
|
|
204
334
|
try {
|
|
205
335
|
const hljs = await loadHighlighter();
|
|
206
336
|
const hasLanguage = await registerLanguageOnce(hljs, language);
|
|
207
|
-
if (disposed) {
|
|
337
|
+
if (disposed || generation !== renderGeneration) {
|
|
208
338
|
return;
|
|
209
339
|
}
|
|
210
|
-
|
|
340
|
+
const highlighted = hasLanguage
|
|
211
341
|
? hljs.highlight(text, { language, ignoreIllegals: true }).value
|
|
212
342
|
: escapeHtml(text);
|
|
343
|
+
mountCodeMarkup(pre, code, highlighted, lineCount, showLineNumbers, wrapLongLines);
|
|
213
344
|
}
|
|
214
345
|
catch {
|
|
215
|
-
if (!disposed) {
|
|
216
|
-
code
|
|
346
|
+
if (!disposed && generation === renderGeneration) {
|
|
347
|
+
mountCodeMarkup(pre, code, escapeHtml(text), lineCount, showLineNumbers, wrapLongLines);
|
|
217
348
|
}
|
|
218
349
|
}
|
|
219
350
|
};
|
|
220
|
-
|
|
351
|
+
const toggleRepresentation = () => {
|
|
352
|
+
if (formattedText === null) {
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
showingFormatted = !showingFormatted;
|
|
356
|
+
void renderCurrentRepresentation();
|
|
357
|
+
};
|
|
358
|
+
representationToggle.addEventListener('click', toggleRepresentation);
|
|
359
|
+
await renderCurrentRepresentation();
|
|
221
360
|
const getZoomState = () => ({
|
|
222
361
|
scale: zoom,
|
|
223
362
|
label: `${Math.round(zoom * 100)}%`,
|
|
@@ -245,6 +384,8 @@ export default async function renderText(buffer, target, type, context) {
|
|
|
245
384
|
$el: target,
|
|
246
385
|
unmount() {
|
|
247
386
|
disposed = true;
|
|
387
|
+
renderGeneration += 1;
|
|
388
|
+
representationToggle.removeEventListener('click', toggleRepresentation);
|
|
248
389
|
unregisterFileViewerZoomProvider(root);
|
|
249
390
|
target.replaceChildren();
|
|
250
391
|
}
|
package/dist/codeStyle.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export declare const codeStyle = "\n.code-viewer{min-height:100%;--code-bg:#f6f8fa;--code-toolbar-bg:rgba(255,255,255,.92);--code-border:rgba(31,35,40,.12);--code-text:#24292f;--code-muted:#57606a;--code-keyword:#cf222e;--code-title:#8250df;--code-string:#0a3069;--code-number:#0550ae;--code-comment:#6e7781;--code-attr:#953800;--code-built-in:#116329;background:var(--code-bg);color:var(--code-text);box-sizing:border-box}\n.code-toolbar{position:sticky;top:0;z-index:
|
|
1
|
+
export declare const codeStyle = "\n.code-viewer{min-height:100%;--code-bg:#f6f8fa;--code-toolbar-bg:rgba(255,255,255,.92);--code-border:rgba(31,35,40,.12);--code-text:#24292f;--code-muted:#57606a;--code-keyword:#cf222e;--code-title:#8250df;--code-string:#0a3069;--code-number:#0550ae;--code-comment:#6e7781;--code-attr:#953800;--code-built-in:#116329;--code-accent:#0969da;--code-accent-border:rgba(9,105,218,.28);--code-accent-soft:rgba(9,105,218,.1);background:var(--code-bg);color:var(--code-text);box-sizing:border-box}\n.code-toolbar{position:sticky;top:0;z-index:2;display:flex;height:42px;align-items:center;justify-content:space-between;gap:16px;padding:0 16px;border-bottom:1px solid var(--code-border);background:var(--code-toolbar-bg);backdrop-filter:blur(12px);box-sizing:border-box}\n.code-toolbar span,.code-toolbar strong{color:var(--code-muted);font-size:12px;font-weight:700;letter-spacing:0}\n.code-toolbar-meta{display:inline-flex;min-width:0;align-items:center;justify-content:flex-end;gap:10px;white-space:nowrap}\n.code-toolbar-meta>span{overflow:hidden;text-overflow:ellipsis}\n.code-format-status{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--code-accent-border);border-radius:999px;background:var(--code-accent-soft);color:var(--code-accent)!important;font-size:11px!important}\n.code-format-toggle{min-height:26px;padding:0 9px;border:1px solid var(--code-border);border-radius:6px;background:var(--code-bg);color:var(--code-text);font:600 11px/1.2 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;cursor:pointer}\n.code-format-toggle:hover{border-color:var(--code-accent);color:var(--code-accent)}\n.code-format-toggle:focus-visible{outline:2px solid var(--code-accent);outline-offset:2px}\n.code-area{display:block;min-width:min-content;margin:0;padding:18px 20px 28px;overflow:auto;background:transparent;box-sizing:border-box}\n.code-area--line-numbers{display:grid;grid-template-columns:max-content max-content;padding:18px 0 28px}\n.code-line-numbers{position:sticky;left:0;z-index:1;display:block;min-width:4ch;padding:0 12px 0 16px;border-right:1px solid var(--code-border);background:var(--code-bg);color:var(--code-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:var(--code-font-size,13px);line-height:1.7;text-align:right;white-space:pre;user-select:none;box-sizing:border-box}\n.code-area.code-area--line-numbers code{padding:0 20px}\n.code-area code{display:block;padding:0;overflow:visible;background:transparent;color:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:var(--code-font-size,13px);line-height:1.7;tab-size:2;white-space:pre}\n.code-viewer--wrap-lines .code-area{width:100%;min-width:0;overflow-x:hidden}\n.code-viewer--wrap-lines .code-area code{min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}\n.code-area--wrapped-line-numbers{display:block;padding:18px 0 28px}\n.code-area--wrapped-line-numbers code{width:100%;padding:0;white-space:normal!important}\n.code-source-line{display:grid;width:100%;min-width:0;grid-template-columns:max-content minmax(0,1fr);align-items:stretch;min-height:1.7em}\n.code-source-line-number{position:sticky;left:0;z-index:1;display:block;min-width:4ch;padding:0 12px 0 16px;border-right:1px solid var(--code-border);background:var(--code-bg);color:var(--code-muted);font:inherit;line-height:inherit;text-align:right;white-space:pre;user-select:none;box-sizing:border-box}\n.code-source-line-content{display:block;min-width:0;padding:0 20px;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;box-sizing:border-box}\n.code-source-line-content:empty::after{content:' '}\n.code-area .hljs-comment,.code-area .hljs-quote{color:var(--code-comment)}\n.code-area .hljs-keyword,.code-area .hljs-selector-tag,.code-area .hljs-subst{color:var(--code-keyword)}\n.code-area .hljs-string,.code-area .hljs-doctag,.code-area .hljs-regexp{color:var(--code-string)}\n.code-area .hljs-title,.code-area .hljs-section,.code-area .hljs-selector-id{color:var(--code-title);font-weight:700}\n.code-area .hljs-number,.code-area .hljs-literal,.code-area .hljs-variable,.code-area .hljs-template-variable{color:var(--code-number)}\n.code-area .hljs-attr,.code-area .hljs-attribute,.code-area .hljs-name,.code-area .hljs-selector-class{color:var(--code-attr)}\n.code-area .hljs-built_in,.code-area .hljs-type,.code-area .hljs-class .hljs-title{color:var(--code-built-in)}\n[data-viewer-theme='dark'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787;--code-accent:#58a6ff;--code-accent-border:rgba(88,166,255,.32);--code-accent-soft:rgba(56,139,253,.15)}\n@media (prefers-color-scheme:dark){[data-viewer-theme='system'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787;--code-accent:#58a6ff;--code-accent-border:rgba(88,166,255,.32);--code-accent-soft:rgba(56,139,253,.15)}}\n";
|
package/dist/codeStyle.js
CHANGED
|
@@ -1,12 +1,26 @@
|
|
|
1
1
|
export const codeStyle = `
|
|
2
|
-
.code-viewer{min-height:100%;--code-bg:#f6f8fa;--code-toolbar-bg:rgba(255,255,255,.92);--code-border:rgba(31,35,40,.12);--code-text:#24292f;--code-muted:#57606a;--code-keyword:#cf222e;--code-title:#8250df;--code-string:#0a3069;--code-number:#0550ae;--code-comment:#6e7781;--code-attr:#953800;--code-built-in:#116329;background:var(--code-bg);color:var(--code-text);box-sizing:border-box}
|
|
3
|
-
.code-toolbar{position:sticky;top:0;z-index:
|
|
2
|
+
.code-viewer{min-height:100%;--code-bg:#f6f8fa;--code-toolbar-bg:rgba(255,255,255,.92);--code-border:rgba(31,35,40,.12);--code-text:#24292f;--code-muted:#57606a;--code-keyword:#cf222e;--code-title:#8250df;--code-string:#0a3069;--code-number:#0550ae;--code-comment:#6e7781;--code-attr:#953800;--code-built-in:#116329;--code-accent:#0969da;--code-accent-border:rgba(9,105,218,.28);--code-accent-soft:rgba(9,105,218,.1);background:var(--code-bg);color:var(--code-text);box-sizing:border-box}
|
|
3
|
+
.code-toolbar{position:sticky;top:0;z-index:2;display:flex;height:42px;align-items:center;justify-content:space-between;gap:16px;padding:0 16px;border-bottom:1px solid var(--code-border);background:var(--code-toolbar-bg);backdrop-filter:blur(12px);box-sizing:border-box}
|
|
4
4
|
.code-toolbar span,.code-toolbar strong{color:var(--code-muted);font-size:12px;font-weight:700;letter-spacing:0}
|
|
5
|
+
.code-toolbar-meta{display:inline-flex;min-width:0;align-items:center;justify-content:flex-end;gap:10px;white-space:nowrap}
|
|
6
|
+
.code-toolbar-meta>span{overflow:hidden;text-overflow:ellipsis}
|
|
7
|
+
.code-format-status{display:inline-flex;align-items:center;min-height:22px;padding:0 8px;border:1px solid var(--code-accent-border);border-radius:999px;background:var(--code-accent-soft);color:var(--code-accent)!important;font-size:11px!important}
|
|
8
|
+
.code-format-toggle{min-height:26px;padding:0 9px;border:1px solid var(--code-border);border-radius:6px;background:var(--code-bg);color:var(--code-text);font:600 11px/1.2 ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,'Segoe UI',sans-serif;cursor:pointer}
|
|
9
|
+
.code-format-toggle:hover{border-color:var(--code-accent);color:var(--code-accent)}
|
|
10
|
+
.code-format-toggle:focus-visible{outline:2px solid var(--code-accent);outline-offset:2px}
|
|
5
11
|
.code-area{display:block;min-width:min-content;margin:0;padding:18px 20px 28px;overflow:auto;background:transparent;box-sizing:border-box}
|
|
6
12
|
.code-area--line-numbers{display:grid;grid-template-columns:max-content max-content;padding:18px 0 28px}
|
|
7
13
|
.code-line-numbers{position:sticky;left:0;z-index:1;display:block;min-width:4ch;padding:0 12px 0 16px;border-right:1px solid var(--code-border);background:var(--code-bg);color:var(--code-muted);font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:var(--code-font-size,13px);line-height:1.7;text-align:right;white-space:pre;user-select:none;box-sizing:border-box}
|
|
8
14
|
.code-area.code-area--line-numbers code{padding:0 20px}
|
|
9
15
|
.code-area code{display:block;padding:0;overflow:visible;background:transparent;color:inherit;font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,'Liberation Mono',monospace;font-size:var(--code-font-size,13px);line-height:1.7;tab-size:2;white-space:pre}
|
|
16
|
+
.code-viewer--wrap-lines .code-area{width:100%;min-width:0;overflow-x:hidden}
|
|
17
|
+
.code-viewer--wrap-lines .code-area code{min-width:0;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word}
|
|
18
|
+
.code-area--wrapped-line-numbers{display:block;padding:18px 0 28px}
|
|
19
|
+
.code-area--wrapped-line-numbers code{width:100%;padding:0;white-space:normal!important}
|
|
20
|
+
.code-source-line{display:grid;width:100%;min-width:0;grid-template-columns:max-content minmax(0,1fr);align-items:stretch;min-height:1.7em}
|
|
21
|
+
.code-source-line-number{position:sticky;left:0;z-index:1;display:block;min-width:4ch;padding:0 12px 0 16px;border-right:1px solid var(--code-border);background:var(--code-bg);color:var(--code-muted);font:inherit;line-height:inherit;text-align:right;white-space:pre;user-select:none;box-sizing:border-box}
|
|
22
|
+
.code-source-line-content{display:block;min-width:0;padding:0 20px;white-space:pre-wrap;overflow-wrap:anywhere;word-break:break-word;box-sizing:border-box}
|
|
23
|
+
.code-source-line-content:empty::after{content:' '}
|
|
10
24
|
.code-area .hljs-comment,.code-area .hljs-quote{color:var(--code-comment)}
|
|
11
25
|
.code-area .hljs-keyword,.code-area .hljs-selector-tag,.code-area .hljs-subst{color:var(--code-keyword)}
|
|
12
26
|
.code-area .hljs-string,.code-area .hljs-doctag,.code-area .hljs-regexp{color:var(--code-string)}
|
|
@@ -14,6 +28,6 @@ export const codeStyle = `
|
|
|
14
28
|
.code-area .hljs-number,.code-area .hljs-literal,.code-area .hljs-variable,.code-area .hljs-template-variable{color:var(--code-number)}
|
|
15
29
|
.code-area .hljs-attr,.code-area .hljs-attribute,.code-area .hljs-name,.code-area .hljs-selector-class{color:var(--code-attr)}
|
|
16
30
|
.code-area .hljs-built_in,.code-area .hljs-type,.code-area .hljs-class .hljs-title{color:var(--code-built-in)}
|
|
17
|
-
[data-viewer-theme='dark'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787}
|
|
18
|
-
@media (prefers-color-scheme:dark){[data-viewer-theme='system'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787}}
|
|
31
|
+
[data-viewer-theme='dark'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787;--code-accent:#58a6ff;--code-accent-border:rgba(88,166,255,.32);--code-accent-soft:rgba(56,139,253,.15)}
|
|
32
|
+
@media (prefers-color-scheme:dark){[data-viewer-theme='system'] .code-viewer{--code-bg:#0d1117;--code-toolbar-bg:rgba(13,17,23,.92);--code-border:rgba(139,148,158,.24);--code-text:#e6edf3;--code-muted:#8b949e;--code-keyword:#ff7b72;--code-title:#d2a8ff;--code-string:#a5d6ff;--code-number:#79c0ff;--code-comment:#8b949e;--code-attr:#ffa657;--code-built-in:#7ee787;--code-accent:#58a6ff;--code-accent-border:rgba(88,166,255,.32);--code-accent-soft:rgba(56,139,253,.15)}}
|
|
19
33
|
`;
|
package/dist/gitBundle.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { createFileViewerTranslator, createFileViewerZoomChangeEmitter as createZoomChangeEmitter, registerFileViewerZoomProvider, unregisterFileViewerZoomProvider } from '@file-viewer/core';
|
|
2
|
-
import {
|
|
2
|
+
import { getFileViewerPakoLoader } from './optionalCapabilities.js';
|
|
3
|
+
let Inflate = null;
|
|
3
4
|
const textDecoder = new TextDecoder('utf-8');
|
|
4
5
|
const asciiDecoder = new TextDecoder('latin1');
|
|
5
6
|
const bundleStyle = `
|
|
@@ -135,6 +136,8 @@ const readOfsDeltaBase = (bytes, start) => {
|
|
|
135
136
|
return { value, offset };
|
|
136
137
|
};
|
|
137
138
|
const inflateObject = (bytes, start) => {
|
|
139
|
+
if (!Inflate)
|
|
140
|
+
throw new Error('Git bundle support is opt-in. Run `npx file-viewer-cli add text-tools --write`, then `npx file-viewer-cli install --yes`.');
|
|
138
141
|
const inflator = new Inflate();
|
|
139
142
|
let offset = start;
|
|
140
143
|
while (!inflator.ended && offset < bytes.length) {
|
|
@@ -476,6 +479,12 @@ const renderMeta = (documentRef, panel, model, t) => {
|
|
|
476
479
|
}
|
|
477
480
|
};
|
|
478
481
|
export default async function renderGitBundle(buffer, target, type = 'bundle', context) {
|
|
482
|
+
const loadPako = getFileViewerPakoLoader();
|
|
483
|
+
if (!loadPako) {
|
|
484
|
+
throw new Error('Git bundle support is opt-in. Run `npx file-viewer-cli add text-tools --write`, then `npx file-viewer-cli install --yes`.');
|
|
485
|
+
}
|
|
486
|
+
;
|
|
487
|
+
({ Inflate } = await loadPako());
|
|
479
488
|
const documentRef = target.ownerDocument || document;
|
|
480
489
|
const t = createFileViewerTranslator(context === null || context === void 0 ? void 0 : context.options);
|
|
481
490
|
const model = await parseBundleModel(buffer, t);
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
1
|
import { type FileRenderHandler, type FileViewerRenderedInstance, type FileViewerRendererPlugin, type RendererDefinition } from '@file-viewer/core';
|
|
2
|
+
export { getFileViewerMermaidLoader, getFileViewerDiffToHtml, getFileViewerPakoLoader, registerFileViewerDiffToHtml, registerFileViewerMermaidLoader, registerFileViewerPakoLoader, } from './optionalCapabilities.js';
|
|
3
|
+
export type { FileViewerMermaidLoader, FileViewerMermaidModule, FileViewerDiffToHtml, FileViewerPakoModule, } from './optionalCapabilities.js';
|
|
4
|
+
export { sanitizeFileViewerRichHtml } from './sanitizeHtml.js';
|
|
2
5
|
export declare const textRendererDefinitions: RendererDefinition[];
|
|
3
6
|
export declare const renderFileViewerCode: FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>;
|
|
4
7
|
export declare const renderFileViewerMarkdown: FileRenderHandler<FileViewerRenderedInstance, HTMLDivElement>;
|
package/dist/index.js
CHANGED
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { DEFAULT_RENDERER_DEFINITIONS, } from '@file-viewer/core';
|
|
2
|
+
export { getFileViewerMermaidLoader, getFileViewerDiffToHtml, getFileViewerPakoLoader, registerFileViewerDiffToHtml, registerFileViewerMermaidLoader, registerFileViewerPakoLoader, } from './optionalCapabilities.js';
|
|
3
|
+
export { sanitizeFileViewerRichHtml } from './sanitizeHtml.js';
|
|
2
4
|
const textRendererIds = ['code', 'markdown'];
|
|
3
5
|
const textDefinitions = DEFAULT_RENDERER_DEFINITIONS.filter(definition => textRendererIds.includes(definition.id));
|
|
4
6
|
if (textDefinitions.length !== textRendererIds.length) {
|