omni-viewer-core 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.
- package/LICENSE +21 -0
- package/README.md +80 -0
- package/THIRD_PARTY_NOTICES.md +49 -0
- package/dist/assets/audio-engine/audio_engine.mjs +2 -0
- package/dist/assets/audio-engine/audio_engine.wasm +0 -0
- package/dist/assets/pdfjs/pdf.worker.min.mjs +21 -0
- package/dist/host/index.d.ts +133 -0
- package/dist/host/index.js +10 -0
- package/dist/i18n/catalog.en.d.ts +1 -0
- package/dist/i18n/catalog.en.js +411 -0
- package/dist/i18n/catalog.ko.d.ts +1 -0
- package/dist/i18n/catalog.ko.js +68 -0
- package/dist/i18n/index.d.ts +18 -0
- package/dist/i18n/index.js +41 -0
- package/dist/licenses/emscripten.txt +101 -0
- package/dist/licenses/kissfft.txt +28 -0
- package/dist/licenses/pdfjs-dist.txt +177 -0
- package/dist/parsers/a2l/index.d.ts +1 -0
- package/dist/parsers/a2l/index.js +1 -0
- package/dist/parsers/archive/index.d.ts +22 -0
- package/dist/parsers/archive/index.js +46 -0
- package/dist/parsers/archive/model.d.ts +29 -0
- package/dist/parsers/archive/model.js +1 -0
- package/dist/parsers/archive/worker.d.ts +21 -0
- package/dist/parsers/archive/worker.js +1 -0
- package/dist/parsers/arxml/index.d.ts +1 -0
- package/dist/parsers/arxml/index.js +1 -0
- package/dist/parsers/asc/index.d.ts +1 -0
- package/dist/parsers/asc/index.js +1 -0
- package/dist/parsers/audio/index.d.ts +9 -0
- package/dist/parsers/audio/index.js +46 -0
- package/dist/parsers/automotive/index.d.ts +33 -0
- package/dist/parsers/automotive/index.js +973 -0
- package/dist/parsers/blf/index.d.ts +1 -0
- package/dist/parsers/blf/index.js +1 -0
- package/dist/parsers/csv/delimiter.d.ts +31 -0
- package/dist/parsers/csv/delimiter.js +151 -0
- package/dist/parsers/csv/index.d.ts +30 -0
- package/dist/parsers/csv/index.js +108 -0
- package/dist/parsers/csv/parseText.d.ts +20 -0
- package/dist/parsers/csv/parseText.js +108 -0
- package/dist/parsers/csv/sort.d.ts +26 -0
- package/dist/parsers/csv/sort.js +224 -0
- package/dist/parsers/csv/statistics.d.ts +49 -0
- package/dist/parsers/csv/statistics.js +150 -0
- package/dist/parsers/dbc/index.d.ts +56 -0
- package/dist/parsers/dbc/index.js +94 -0
- package/dist/parsers/doc-binary/index.d.ts +35 -0
- package/dist/parsers/doc-binary/index.js +267 -0
- package/dist/parsers/doc-binary/vscode-parser.d.ts +142 -0
- package/dist/parsers/doc-binary/vscode-parser.js +3747 -0
- package/dist/parsers/excel/index.d.ts +17 -0
- package/dist/parsers/excel/index.js +406 -0
- package/dist/parsers/excel/model.d.ts +80 -0
- package/dist/parsers/excel/model.js +48 -0
- package/dist/parsers/excel/serialize.d.ts +3 -0
- package/dist/parsers/excel/serialize.js +78 -0
- package/dist/parsers/hdf5/index.d.ts +75 -0
- package/dist/parsers/hdf5/index.js +658 -0
- package/dist/parsers/hdf5/node.d.ts +21 -0
- package/dist/parsers/hdf5/node.js +95 -0
- package/dist/parsers/json/index.d.ts +15 -0
- package/dist/parsers/json/index.js +102 -0
- package/dist/parsers/json/model.d.ts +42 -0
- package/dist/parsers/json/model.js +140 -0
- package/dist/parsers/json/parse.d.ts +22 -0
- package/dist/parsers/json/parse.js +279 -0
- package/dist/parsers/json/tokenizer.d.ts +17 -0
- package/dist/parsers/json/tokenizer.js +175 -0
- package/dist/parsers/jsonl/index.d.ts +14 -0
- package/dist/parsers/jsonl/index.js +18 -0
- package/dist/parsers/jsonl/model.d.ts +23 -0
- package/dist/parsers/jsonl/model.js +1 -0
- package/dist/parsers/jsonl/parse.d.ts +7 -0
- package/dist/parsers/jsonl/parse.js +34 -0
- package/dist/parsers/markdown/index.d.ts +37 -0
- package/dist/parsers/markdown/index.js +59 -0
- package/dist/parsers/mat/index.d.ts +31 -0
- package/dist/parsers/mat/index.js +426 -0
- package/dist/parsers/mermaid/index.d.ts +5 -0
- package/dist/parsers/mermaid/index.js +3 -0
- package/dist/parsers/mf4/index.d.ts +1 -0
- package/dist/parsers/mf4/index.js +1 -0
- package/dist/parsers/parquet/index.d.ts +21 -0
- package/dist/parsers/parquet/index.js +68 -0
- package/dist/parsers/pcap/index.d.ts +1 -0
- package/dist/parsers/pcap/index.js +1 -0
- package/dist/parsers/pcapng/index.d.ts +1 -0
- package/dist/parsers/pcapng/index.js +1 -0
- package/dist/parsers/plantuml/index.d.ts +5 -0
- package/dist/parsers/plantuml/index.js +4 -0
- package/dist/parsers/ppt-binary/index.d.ts +5 -0
- package/dist/parsers/ppt-binary/index.js +62 -0
- package/dist/parsers/ppt-binary/pptBinaryBuildContext.d.ts +12 -0
- package/dist/parsers/ppt-binary/pptBinaryBuildContext.js +40 -0
- package/dist/parsers/ppt-binary/pptBinaryContainer.d.ts +4 -0
- package/dist/parsers/ppt-binary/pptBinaryContainer.js +174 -0
- package/dist/parsers/ppt-binary/pptBinaryTypes.d.ts +125 -0
- package/dist/parsers/ppt-binary/pptBinaryTypes.js +1 -0
- package/dist/parsers/ppt-binary/pptSlideLayouts.d.ts +9 -0
- package/dist/parsers/ppt-binary/pptSlideLayouts.js +510 -0
- package/dist/parsers/ppt-binary/vscode-parser.d.ts +116 -0
- package/dist/parsers/ppt-binary/vscode-parser.js +2853 -0
- package/dist/parsers/ppt-binary/vscode.d.ts +4 -0
- package/dist/parsers/ppt-binary/vscode.js +12 -0
- package/dist/parsers/pptx/index.d.ts +15 -0
- package/dist/parsers/pptx/index.js +88 -0
- package/dist/parsers/pptx/vscode-parser.d.ts +167 -0
- package/dist/parsers/pptx/vscode-parser.js +1503 -0
- package/dist/parsers/pptx/vscode.d.ts +4 -0
- package/dist/parsers/pptx/vscode.js +18 -0
- package/dist/parsers/pptx/zip-reader.d.ts +3 -0
- package/dist/parsers/pptx/zip-reader.js +20 -0
- package/dist/parsers/proto/index.d.ts +90 -0
- package/dist/parsers/proto/index.js +197 -0
- package/dist/parsers/psd/index.d.ts +16 -0
- package/dist/parsers/psd/index.js +10 -0
- package/dist/parsers/shapefile/dbf.d.ts +23 -0
- package/dist/parsers/shapefile/dbf.js +112 -0
- package/dist/parsers/shapefile/index.d.ts +44 -0
- package/dist/parsers/shapefile/index.js +119 -0
- package/dist/parsers/shapefile/reproject.d.ts +10 -0
- package/dist/parsers/shapefile/reproject.js +41 -0
- package/dist/parsers/slide-model.d.ts +106 -0
- package/dist/parsers/slide-model.js +1 -0
- package/dist/parsers/toml/index.d.ts +15 -0
- package/dist/parsers/toml/index.js +18 -0
- package/dist/parsers/toml/model.d.ts +15 -0
- package/dist/parsers/toml/model.js +1 -0
- package/dist/parsers/toml/parse.d.ts +16 -0
- package/dist/parsers/toml/parse.js +266 -0
- package/dist/parsers/types.d.ts +103 -0
- package/dist/parsers/types.js +106 -0
- package/dist/parsers/video/index.d.ts +6 -0
- package/dist/parsers/video/index.js +2 -0
- package/dist/parsers/yaml/index.d.ts +16 -0
- package/dist/parsers/yaml/index.js +58 -0
- package/dist/parsers/yaml/model.d.ts +22 -0
- package/dist/parsers/yaml/model.js +1 -0
- package/dist/parsers/yaml/self-loading.d.ts +3 -0
- package/dist/parsers/yaml/self-loading.js +19 -0
- package/dist/parsers/zip-scan.d.ts +8 -0
- package/dist/parsers/zip-scan.js +80 -0
- package/dist/registry/container.d.ts +17 -0
- package/dist/registry/container.js +49 -0
- package/dist/registry/index.d.ts +133 -0
- package/dist/registry/index.js +348 -0
- package/dist/registry/probe.d.ts +3 -0
- package/dist/registry/probe.js +177 -0
- package/dist/registry/sniff.d.ts +17 -0
- package/dist/registry/sniff.js +57 -0
- package/dist/styles/archive.css +10 -0
- package/dist/styles/audio.css +66 -0
- package/dist/styles/automotive.css +1 -0
- package/dist/styles/csv.css +262 -0
- package/dist/styles/excel.css +212 -0
- package/dist/styles/fallback.css +48 -0
- package/dist/styles/hdf5.css +3 -0
- package/dist/styles/hwp.css +12 -0
- package/dist/styles/image.css +115 -0
- package/dist/styles/json.css +342 -0
- package/dist/styles/jsonl.css +1 -0
- package/dist/styles/markdown.css +10 -0
- package/dist/styles/mat.css +2 -0
- package/dist/styles/mermaid.css +1 -0
- package/dist/styles/parquet.css +2 -0
- package/dist/styles/pdf.css +551 -0
- package/dist/styles/plantuml.css +1 -0
- package/dist/styles/ppt.css +1 -0
- package/dist/styles/proto.css +2 -0
- package/dist/styles/psd.css +1 -0
- package/dist/styles/shapefile.css +25 -0
- package/dist/styles/toml.css +1 -0
- package/dist/styles/video.css +74 -0
- package/dist/styles/word.css +685 -0
- package/dist/styles/yaml.css +1 -0
- package/dist/viewers/a2l/index.d.ts +15 -0
- package/dist/viewers/a2l/index.js +5 -0
- package/dist/viewers/archive/archive-preview-decoder.d.ts +4 -0
- package/dist/viewers/archive/archive-preview-decoder.js +223 -0
- package/dist/viewers/archive/controller.d.ts +24 -0
- package/dist/viewers/archive/controller.js +18 -0
- package/dist/viewers/archive/index.d.ts +25 -0
- package/dist/viewers/archive/index.js +230 -0
- package/dist/viewers/archive/preview.d.ts +2 -0
- package/dist/viewers/archive/preview.js +2 -0
- package/dist/viewers/archive/styles.d.ts +1 -0
- package/dist/viewers/archive/styles.js +11 -0
- package/dist/viewers/arxml/index.d.ts +15 -0
- package/dist/viewers/arxml/index.js +5 -0
- package/dist/viewers/asc/index.d.ts +15 -0
- package/dist/viewers/asc/index.js +5 -0
- package/dist/viewers/audio/controller.d.ts +33 -0
- package/dist/viewers/audio/controller.js +49 -0
- package/dist/viewers/audio/engine.d.ts +44 -0
- package/dist/viewers/audio/engine.js +108 -0
- package/dist/viewers/audio/index.d.ts +92 -0
- package/dist/viewers/audio/index.js +448 -0
- package/dist/viewers/audio/self-loading.d.ts +7 -0
- package/dist/viewers/audio/self-loading.js +42 -0
- package/dist/viewers/audio/styles.d.ts +1 -0
- package/dist/viewers/audio/styles.js +73 -0
- package/dist/viewers/automotive/index.d.ts +8 -0
- package/dist/viewers/automotive/index.js +152 -0
- package/dist/viewers/automotive/styles.d.ts +1 -0
- package/dist/viewers/automotive/styles.js +1 -0
- package/dist/viewers/avro/index.d.ts +15 -0
- package/dist/viewers/avro/index.js +5 -0
- package/dist/viewers/bag/index.d.ts +15 -0
- package/dist/viewers/bag/index.js +5 -0
- package/dist/viewers/blf/index.d.ts +15 -0
- package/dist/viewers/blf/index.js +5 -0
- package/dist/viewers/csv/controller.d.ts +126 -0
- package/dist/viewers/csv/controller.js +598 -0
- package/dist/viewers/csv/index.d.ts +48 -0
- package/dist/viewers/csv/index.js +846 -0
- package/dist/viewers/csv/styles.d.ts +1 -0
- package/dist/viewers/csv/styles.js +267 -0
- package/dist/viewers/db3/index.d.ts +15 -0
- package/dist/viewers/db3/index.js +5 -0
- package/dist/viewers/dbc/index.d.ts +15 -0
- package/dist/viewers/dbc/index.js +5 -0
- package/dist/viewers/diagram.d.ts +14 -0
- package/dist/viewers/diagram.js +95 -0
- package/dist/viewers/excel/controller.d.ts +108 -0
- package/dist/viewers/excel/controller.js +548 -0
- package/dist/viewers/excel/grid.d.ts +28 -0
- package/dist/viewers/excel/grid.js +99 -0
- package/dist/viewers/excel/index.d.ts +37 -0
- package/dist/viewers/excel/index.js +620 -0
- package/dist/viewers/excel/self-loading.d.ts +6 -0
- package/dist/viewers/excel/self-loading.js +13 -0
- package/dist/viewers/excel/styles.d.ts +1 -0
- package/dist/viewers/excel/styles.js +216 -0
- package/dist/viewers/fallback/index.d.ts +17 -0
- package/dist/viewers/fallback/index.js +130 -0
- package/dist/viewers/fallback/styles.d.ts +1 -0
- package/dist/viewers/fallback/styles.js +49 -0
- package/dist/viewers/hdf5/index.d.ts +19 -0
- package/dist/viewers/hdf5/index.js +170 -0
- package/dist/viewers/hdf5/styles.d.ts +1 -0
- package/dist/viewers/hdf5/styles.js +4 -0
- package/dist/viewers/hwp/controller.d.ts +19 -0
- package/dist/viewers/hwp/controller.js +22 -0
- package/dist/viewers/hwp/index.d.ts +39 -0
- package/dist/viewers/hwp/index.js +271 -0
- package/dist/viewers/hwp/self-loading.d.ts +2 -0
- package/dist/viewers/hwp/self-loading.js +6 -0
- package/dist/viewers/hwp/styles.d.ts +1 -0
- package/dist/viewers/hwp/styles.js +13 -0
- package/dist/viewers/image/controller.d.ts +210 -0
- package/dist/viewers/image/controller.js +336 -0
- package/dist/viewers/image/decode.d.ts +54 -0
- package/dist/viewers/image/decode.js +150 -0
- package/dist/viewers/image/index.d.ts +38 -0
- package/dist/viewers/image/index.js +749 -0
- package/dist/viewers/image/limits.d.ts +18 -0
- package/dist/viewers/image/limits.js +20 -0
- package/dist/viewers/image/styles.d.ts +1 -0
- package/dist/viewers/image/styles.js +119 -0
- package/dist/viewers/json/controller.d.ts +89 -0
- package/dist/viewers/json/controller.js +411 -0
- package/dist/viewers/json/index.d.ts +25 -0
- package/dist/viewers/json/index.js +503 -0
- package/dist/viewers/json/styles.d.ts +1 -0
- package/dist/viewers/json/styles.js +346 -0
- package/dist/viewers/json/transforms.d.ts +27 -0
- package/dist/viewers/json/transforms.js +253 -0
- package/dist/viewers/jsonl/controller.d.ts +48 -0
- package/dist/viewers/jsonl/controller.js +136 -0
- package/dist/viewers/jsonl/index.d.ts +22 -0
- package/dist/viewers/jsonl/index.js +184 -0
- package/dist/viewers/jsonl/styles.d.ts +1 -0
- package/dist/viewers/jsonl/styles.js +1 -0
- package/dist/viewers/markdown/controller.d.ts +50 -0
- package/dist/viewers/markdown/controller.js +62 -0
- package/dist/viewers/markdown/index.d.ts +64 -0
- package/dist/viewers/markdown/index.js +425 -0
- package/dist/viewers/markdown/math.d.ts +21 -0
- package/dist/viewers/markdown/math.js +100 -0
- package/dist/viewers/markdown/self-loading.d.ts +5 -0
- package/dist/viewers/markdown/self-loading.js +48 -0
- package/dist/viewers/markdown/styles.d.ts +1 -0
- package/dist/viewers/markdown/styles.js +11 -0
- package/dist/viewers/mat/index.d.ts +19 -0
- package/dist/viewers/mat/index.js +113 -0
- package/dist/viewers/mat/styles.d.ts +1 -0
- package/dist/viewers/mat/styles.js +3 -0
- package/dist/viewers/media.d.ts +9 -0
- package/dist/viewers/media.js +77 -0
- package/dist/viewers/mermaid/index.d.ts +17 -0
- package/dist/viewers/mermaid/index.js +6 -0
- package/dist/viewers/mermaid/self-loading.d.ts +2 -0
- package/dist/viewers/mermaid/self-loading.js +2 -0
- package/dist/viewers/mf4/index.d.ts +15 -0
- package/dist/viewers/mf4/index.js +5 -0
- package/dist/viewers/parquet/controller.d.ts +37 -0
- package/dist/viewers/parquet/controller.js +26 -0
- package/dist/viewers/parquet/index.d.ts +23 -0
- package/dist/viewers/parquet/index.js +134 -0
- package/dist/viewers/parquet/styles.d.ts +1 -0
- package/dist/viewers/parquet/styles.js +3 -0
- package/dist/viewers/pcap/index.d.ts +15 -0
- package/dist/viewers/pcap/index.js +5 -0
- package/dist/viewers/pcapng/index.d.ts +15 -0
- package/dist/viewers/pcapng/index.js +5 -0
- package/dist/viewers/pdf/controller.d.ts +120 -0
- package/dist/viewers/pdf/controller.js +191 -0
- package/dist/viewers/pdf/editing.d.ts +26 -0
- package/dist/viewers/pdf/editing.js +265 -0
- package/dist/viewers/pdf/index.d.ts +88 -0
- package/dist/viewers/pdf/index.js +1400 -0
- package/dist/viewers/pdf/self-loading.d.ts +6 -0
- package/dist/viewers/pdf/self-loading.js +14 -0
- package/dist/viewers/pdf/styles.d.ts +1 -0
- package/dist/viewers/pdf/styles.js +555 -0
- package/dist/viewers/plantuml/index.d.ts +17 -0
- package/dist/viewers/plantuml/index.js +6 -0
- package/dist/viewers/plantuml/self-loading.d.ts +2 -0
- package/dist/viewers/plantuml/self-loading.js +2 -0
- package/dist/viewers/ppt/chart.d.ts +8 -0
- package/dist/viewers/ppt/chart.js +83 -0
- package/dist/viewers/ppt/controller.d.ts +34 -0
- package/dist/viewers/ppt/controller.js +27 -0
- package/dist/viewers/ppt/index.d.ts +33 -0
- package/dist/viewers/ppt/index.js +101 -0
- package/dist/viewers/ppt/render.d.ts +5 -0
- package/dist/viewers/ppt/render.js +144 -0
- package/dist/viewers/ppt/self-loading.d.ts +9 -0
- package/dist/viewers/ppt/self-loading.js +4 -0
- package/dist/viewers/ppt/styles.d.ts +1 -0
- package/dist/viewers/ppt/styles.js +1 -0
- package/dist/viewers/proto/index.d.ts +17 -0
- package/dist/viewers/proto/index.js +170 -0
- package/dist/viewers/proto/styles.d.ts +1 -0
- package/dist/viewers/proto/styles.js +2 -0
- package/dist/viewers/psd/index.d.ts +27 -0
- package/dist/viewers/psd/index.js +39 -0
- package/dist/viewers/psd/self-loading.d.ts +10 -0
- package/dist/viewers/psd/self-loading.js +20 -0
- package/dist/viewers/psd/styles.d.ts +1 -0
- package/dist/viewers/psd/styles.js +1 -0
- package/dist/viewers/reqif/index.d.ts +15 -0
- package/dist/viewers/reqif/index.js +5 -0
- package/dist/viewers/shapefile/index.d.ts +35 -0
- package/dist/viewers/shapefile/index.js +336 -0
- package/dist/viewers/shapefile/self-loading.d.ts +7 -0
- package/dist/viewers/shapefile/self-loading.js +32 -0
- package/dist/viewers/shapefile/styles.d.ts +1 -0
- package/dist/viewers/shapefile/styles.js +28 -0
- package/dist/viewers/stp/index.d.ts +15 -0
- package/dist/viewers/stp/index.js +5 -0
- package/dist/viewers/structured-styles.d.ts +1 -0
- package/dist/viewers/structured-styles.js +1 -0
- package/dist/viewers/structured.d.ts +36 -0
- package/dist/viewers/structured.js +138 -0
- package/dist/viewers/toml/controller.d.ts +38 -0
- package/dist/viewers/toml/controller.js +61 -0
- package/dist/viewers/toml/index.d.ts +18 -0
- package/dist/viewers/toml/index.js +34 -0
- package/dist/viewers/types.d.ts +36 -0
- package/dist/viewers/types.js +9 -0
- package/dist/viewers/video/controller.d.ts +29 -0
- package/dist/viewers/video/controller.js +54 -0
- package/dist/viewers/video/index.d.ts +18 -0
- package/dist/viewers/video/index.js +305 -0
- package/dist/viewers/video/styles.d.ts +1 -0
- package/dist/viewers/video/styles.js +79 -0
- package/dist/viewers/word/controller.d.ts +19 -0
- package/dist/viewers/word/controller.js +22 -0
- package/dist/viewers/word/docx-preprocess.d.ts +63 -0
- package/dist/viewers/word/docx-preprocess.js +136 -0
- package/dist/viewers/word/index.d.ts +32 -0
- package/dist/viewers/word/index.js +187 -0
- package/dist/viewers/word/normalize-docx.d.ts +2 -0
- package/dist/viewers/word/normalize-docx.js +50 -0
- package/dist/viewers/word/paginate.d.ts +1 -0
- package/dist/viewers/word/paginate.js +1035 -0
- package/dist/viewers/word/self-loading.d.ts +2 -0
- package/dist/viewers/word/self-loading.js +7 -0
- package/dist/viewers/word/styles.d.ts +1 -0
- package/dist/viewers/word/styles.js +686 -0
- package/dist/viewers/yaml/controller.d.ts +42 -0
- package/dist/viewers/yaml/controller.js +41 -0
- package/dist/viewers/yaml/index.d.ts +21 -0
- package/dist/viewers/yaml/index.js +20 -0
- package/package.json +375 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { parseJsonl } from '../../parsers/jsonl/index.js';
|
|
2
|
+
const concat = (a, b) => {
|
|
3
|
+
const result = new Uint8Array(a.length + b.length);
|
|
4
|
+
result.set(a);
|
|
5
|
+
result.set(b, a.length);
|
|
6
|
+
return result;
|
|
7
|
+
};
|
|
8
|
+
/** Only newline-terminated records are visible during preview; the trailing
|
|
9
|
+
* bytes are the JNL3 continuation buffer and become a record only at done. */
|
|
10
|
+
const finalized = (data, done) => {
|
|
11
|
+
if (done)
|
|
12
|
+
return data;
|
|
13
|
+
for (let i = data.length - 1; i >= 0; i--)
|
|
14
|
+
if (data[i] === 0x0a)
|
|
15
|
+
return data.slice(0, i + 1);
|
|
16
|
+
return new Uint8Array();
|
|
17
|
+
};
|
|
18
|
+
export function createJsonlController(input) {
|
|
19
|
+
const paged = typeof input !== 'string' && 'initialData' in input ? input : null;
|
|
20
|
+
let bytes = paged ? paged.initialData : typeof input === 'string' ? new TextEncoder().encode(input) : input;
|
|
21
|
+
let nextId = 1;
|
|
22
|
+
const parsedInitial = parseJsonl(finalized(bytes, !paged?.loadMore)).result;
|
|
23
|
+
let entries = parsedInitial.status === 'failed' ? [] : parsedInitial.document.entries.map(entry => ({ ...entry, id: `source:${entry.line}` }));
|
|
24
|
+
const state = {
|
|
25
|
+
status: parsedInitial.status,
|
|
26
|
+
loadState: paged?.loadMore ? 'preview' : 'complete', entries, search: '', selected: new Set(), dirty: false,
|
|
27
|
+
diagnostics: parsedInitial.diagnostics, visibleCount: 5_000
|
|
28
|
+
};
|
|
29
|
+
const listeners = new Set();
|
|
30
|
+
const notify = () => listeners.forEach(listener => listener(state));
|
|
31
|
+
let selectionAnchor = null;
|
|
32
|
+
const editable = () => state.loadState === 'complete';
|
|
33
|
+
const renumber = () => entries.forEach((entry, index) => { entry.line = index + 1; });
|
|
34
|
+
const lineEnding = () => entries.find(e => e.lineEnding)?.lineEnding === '\r\n' ? '\r\n' : '\n';
|
|
35
|
+
const parseEntry = (raw, id, line) => {
|
|
36
|
+
const result = parseJsonl(raw).result;
|
|
37
|
+
const entry = result.status === 'failed' ? undefined : result.document.entries[0];
|
|
38
|
+
return entry ? { ...entry, id, line, lineEnding: lineEnding() } : { id, line, raw, lineEnding: lineEnding(), value: null, diagnostics: [] };
|
|
39
|
+
};
|
|
40
|
+
const reparseBytes = (done) => {
|
|
41
|
+
const result = parseJsonl(finalized(bytes, done)).result;
|
|
42
|
+
if (result.status === 'failed') {
|
|
43
|
+
state.status = 'failed';
|
|
44
|
+
state.diagnostics = result.diagnostics;
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
const existing = new Map(entries.filter(e => e.id.startsWith('source:')).map(e => [`source:${e.line}`, e.id]));
|
|
48
|
+
entries = result.document.entries.map(entry => ({ ...entry, id: existing.get(`source:${entry.line}`) ?? `source:${entry.line}` }));
|
|
49
|
+
state.entries = entries;
|
|
50
|
+
state.status = result.status;
|
|
51
|
+
state.diagnostics = result.diagnostics;
|
|
52
|
+
};
|
|
53
|
+
const loadMore = async () => {
|
|
54
|
+
if (!paged?.loadMore || state.loadState !== 'preview')
|
|
55
|
+
return;
|
|
56
|
+
state.loadState = 'loading';
|
|
57
|
+
notify();
|
|
58
|
+
try {
|
|
59
|
+
const page = await paged.loadMore();
|
|
60
|
+
bytes = concat(bytes, page.data);
|
|
61
|
+
reparseBytes(page.done);
|
|
62
|
+
state.loadState = page.done ? 'complete' : 'preview';
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
state.diagnostics = [...state.diagnostics, { severity: 'error', code: 'jsonl.load-failed', messageKey: 'diag.jsonl.load-failed' }];
|
|
66
|
+
state.loadState = 'preview';
|
|
67
|
+
}
|
|
68
|
+
notify();
|
|
69
|
+
};
|
|
70
|
+
const loadAll = async () => { while (state.loadState === 'preview')
|
|
71
|
+
await loadMore(); };
|
|
72
|
+
return {
|
|
73
|
+
state,
|
|
74
|
+
subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); },
|
|
75
|
+
serialize: () => entries.map((entry, i) => entry.raw + (i === entries.length - 1 ? entry.lineEnding : entry.lineEnding || lineEnding())).join(''),
|
|
76
|
+
canSave: () => editable() && entries.every(entry => !entry.raw.trim() || !entry.diagnostics.some(diagnostic => diagnostic.code === 'invalid-jsonl-line')),
|
|
77
|
+
dispatch(action) {
|
|
78
|
+
if (action.type === 'load-more')
|
|
79
|
+
return loadMore();
|
|
80
|
+
if (action.type === 'load-all')
|
|
81
|
+
return loadAll();
|
|
82
|
+
if (action.type === 'set-search')
|
|
83
|
+
state.search = action.search;
|
|
84
|
+
else if (action.type === 'select') {
|
|
85
|
+
const selected = action.additive ? new Set(state.selected) : new Set();
|
|
86
|
+
if (action.range && selectionAnchor) {
|
|
87
|
+
const a = entries.findIndex(e => e.id === selectionAnchor), b = entries.findIndex(e => e.id === action.id);
|
|
88
|
+
if (a >= 0 && b >= 0)
|
|
89
|
+
for (let i = Math.min(a, b); i <= Math.max(a, b); i++)
|
|
90
|
+
selected.add(entries[i].id);
|
|
91
|
+
}
|
|
92
|
+
else {
|
|
93
|
+
selected.has(action.id) && action.additive ? selected.delete(action.id) : selected.add(action.id);
|
|
94
|
+
selectionAnchor = action.id;
|
|
95
|
+
}
|
|
96
|
+
state.selected = selected;
|
|
97
|
+
}
|
|
98
|
+
else if (action.type === 'edit' && editable()) {
|
|
99
|
+
const index = entries.findIndex(e => e.id === action.id);
|
|
100
|
+
if (index >= 0) {
|
|
101
|
+
const old = entries[index];
|
|
102
|
+
entries[index] = parseEntry(action.raw, old.id, old.line);
|
|
103
|
+
state.entries = entries;
|
|
104
|
+
state.dirty = true;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
else if (action.type === 'insert' && editable()) {
|
|
108
|
+
const id = `inserted:${nextId++}`;
|
|
109
|
+
entries.push(parseEntry(action.raw ?? '{}', id, entries.length + 1));
|
|
110
|
+
state.entries = entries;
|
|
111
|
+
state.dirty = true;
|
|
112
|
+
}
|
|
113
|
+
else if (action.type === 'delete-selected' && editable()) {
|
|
114
|
+
entries = entries.filter(e => !state.selected.has(e.id));
|
|
115
|
+
renumber();
|
|
116
|
+
state.entries = entries;
|
|
117
|
+
state.selected = new Set();
|
|
118
|
+
state.dirty = true;
|
|
119
|
+
}
|
|
120
|
+
else if (action.type === 'move' && editable()) {
|
|
121
|
+
const from = entries.findIndex(e => e.id === action.from);
|
|
122
|
+
const to = entries.findIndex(e => e.id === action.to);
|
|
123
|
+
if (from >= 0 && to >= 0) {
|
|
124
|
+
const item = entries.splice(from, 1)[0];
|
|
125
|
+
if (item) {
|
|
126
|
+
entries.splice(to, 0, item);
|
|
127
|
+
renumber();
|
|
128
|
+
state.entries = entries;
|
|
129
|
+
state.dirty = true;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
notify();
|
|
134
|
+
}
|
|
135
|
+
};
|
|
136
|
+
}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ClipboardService, FileSaveService, FileWritebackService, HostContext } from '../../host/index.js';
|
|
2
|
+
import type { JsonlPagedInput } from '../../parsers/jsonl/index.js';
|
|
3
|
+
import type { MountOptions, ViewerHandle, ViewerInput } from '../types.js';
|
|
4
|
+
export * from './controller.js';
|
|
5
|
+
export { jsonlViewerCss } from './styles.js';
|
|
6
|
+
export declare const JSONL_VIEWER_META: {
|
|
7
|
+
id: string;
|
|
8
|
+
displayNameKey: string;
|
|
9
|
+
extensions: string[];
|
|
10
|
+
priority: number;
|
|
11
|
+
requiredServices: readonly [];
|
|
12
|
+
optionalServices: readonly ["clipboard", "save", "writeback"];
|
|
13
|
+
inputOwnership: "borrows";
|
|
14
|
+
};
|
|
15
|
+
export interface JsonlMountOptions extends MountOptions {
|
|
16
|
+
pagedInput?: JsonlPagedInput;
|
|
17
|
+
}
|
|
18
|
+
export declare function mountJsonlViewer(input: ViewerInput, container: HTMLElement, ctx: HostContext & {
|
|
19
|
+
clipboard?: ClipboardService;
|
|
20
|
+
save?: FileSaveService;
|
|
21
|
+
writeback?: FileWritebackService;
|
|
22
|
+
}, options?: JsonlMountOptions): Promise<ViewerHandle>;
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
import { asciiLower } from '../../parsers/csv/index.js';
|
|
2
|
+
import { VIEWER_ROOT_CLASS } from '../types.js';
|
|
3
|
+
import { createJsonlController } from './controller.js';
|
|
4
|
+
import { jsonlViewerCss } from './styles.js';
|
|
5
|
+
export * from './controller.js';
|
|
6
|
+
export { jsonlViewerCss } from './styles.js';
|
|
7
|
+
export const JSONL_VIEWER_META = { id: 'jsonl', displayNameKey: 'jsonl.title', extensions: ['jsonl', 'ndjson', 'jsonlines'], priority: 10, requiredServices: [], optionalServices: ['clipboard', 'save', 'writeback'], inputOwnership: 'borrows' };
|
|
8
|
+
export async function mountJsonlViewer(input, container, ctx, options = {}) {
|
|
9
|
+
let root;
|
|
10
|
+
if ((options.styleIsolation ?? 'shadow') === 'shadow' && typeof container.attachShadow === 'function') {
|
|
11
|
+
root = container.shadowRoot ?? container.attachShadow({ mode: 'open' });
|
|
12
|
+
const style = document.createElement('style');
|
|
13
|
+
style.textContent = jsonlViewerCss;
|
|
14
|
+
root.append(style);
|
|
15
|
+
}
|
|
16
|
+
else {
|
|
17
|
+
container.classList.add(VIEWER_ROOT_CLASS, 'omni-viewer--jsonl');
|
|
18
|
+
root = container;
|
|
19
|
+
}
|
|
20
|
+
const controller = createJsonlController(options.pagedInput ?? input.data);
|
|
21
|
+
const el = (tag, text) => { const n = document.createElement(tag); if (text !== undefined)
|
|
22
|
+
n.textContent = text; return n; };
|
|
23
|
+
const frame = el('div');
|
|
24
|
+
frame.className = 'omni-jsonl';
|
|
25
|
+
frame.tabIndex = 0;
|
|
26
|
+
root.append(frame);
|
|
27
|
+
let editing = null, detail = null, dragged = null, disposed = false;
|
|
28
|
+
const visible = { count: 5_000 };
|
|
29
|
+
const save = async () => { if (!controller.canSave())
|
|
30
|
+
return; const data = new TextEncoder().encode(controller.serialize()); if (ctx.writeback)
|
|
31
|
+
await ctx.writeback.write(data);
|
|
32
|
+
else if (ctx.save)
|
|
33
|
+
await ctx.save.saveFile(input.fileName, data, 'application/x-ndjson'); };
|
|
34
|
+
const selectedEntry = () => controller.state.entries.find(entry => controller.state.selected.has(entry.id));
|
|
35
|
+
const keydown = (event) => { if (event.target.matches('input,textarea'))
|
|
36
|
+
return; if (event.key === 'Escape') {
|
|
37
|
+
editing = detail = null;
|
|
38
|
+
controller.state.selected.forEach(() => undefined);
|
|
39
|
+
render();
|
|
40
|
+
}
|
|
41
|
+
else if ((event.key === 'Delete' || event.key === 'Backspace') && controller.state.loadState === 'complete') {
|
|
42
|
+
event.preventDefault();
|
|
43
|
+
controller.dispatch({ type: 'delete-selected' });
|
|
44
|
+
}
|
|
45
|
+
else if (event.key === 'Enter') {
|
|
46
|
+
const entry = selectedEntry();
|
|
47
|
+
if (entry) {
|
|
48
|
+
editing = entry.id;
|
|
49
|
+
render();
|
|
50
|
+
}
|
|
51
|
+
} };
|
|
52
|
+
frame.addEventListener('keydown', keydown);
|
|
53
|
+
const unsubscribe = controller.subscribe(() => { if (!disposed)
|
|
54
|
+
render(); });
|
|
55
|
+
function syntax(parent, raw) {
|
|
56
|
+
const pattern = /("(?:\\.|[^"\\])*"(?=\s*:))|("(?:\\.|[^"\\])*")|\b(true|false|null)\b|-?\b\d+(?:\.\d+)?(?:e[+-]?\d+)?\b/gi;
|
|
57
|
+
let offset = 0;
|
|
58
|
+
for (const match of raw.matchAll(pattern)) {
|
|
59
|
+
const index = match.index;
|
|
60
|
+
parent.append(document.createTextNode(raw.slice(offset, index)));
|
|
61
|
+
const token = el('span', match[0]);
|
|
62
|
+
token.className = match[1] ? 'omni-jsonl__key' : match[2] ? 'omni-jsonl__string' : /true|false|null/i.test(match[0]) ? 'omni-jsonl__literal' : 'omni-jsonl__number';
|
|
63
|
+
parent.append(token);
|
|
64
|
+
offset = index + match[0].length;
|
|
65
|
+
}
|
|
66
|
+
parent.append(document.createTextNode(raw.slice(offset)));
|
|
67
|
+
}
|
|
68
|
+
function render() {
|
|
69
|
+
frame.replaceChildren();
|
|
70
|
+
const state = controller.state;
|
|
71
|
+
const bar = el('div');
|
|
72
|
+
bar.className = 'omni-jsonl__bar';
|
|
73
|
+
const search = el('input');
|
|
74
|
+
search.type = 'search';
|
|
75
|
+
search.placeholder = ctx.i18n.t('structured.search');
|
|
76
|
+
search.value = state.search;
|
|
77
|
+
search.addEventListener('input', () => controller.dispatch({ type: 'set-search', search: search.value }));
|
|
78
|
+
const add = el('button', ctx.i18n.t('jsonl.add'));
|
|
79
|
+
add.disabled = state.loadState !== 'complete';
|
|
80
|
+
add.addEventListener('click', () => controller.dispatch({ type: 'insert' }));
|
|
81
|
+
const remove = el('button', ctx.i18n.t('jsonl.delete'));
|
|
82
|
+
remove.disabled = state.loadState !== 'complete' || !state.selected.size;
|
|
83
|
+
remove.addEventListener('click', () => controller.dispatch({ type: 'delete-selected' }));
|
|
84
|
+
const more = el('button', ctx.i18n.t('jsonl.loadMore'));
|
|
85
|
+
more.disabled = state.loadState !== 'preview';
|
|
86
|
+
more.addEventListener('click', () => void controller.dispatch({ type: 'load-more' }));
|
|
87
|
+
const all = el('button', ctx.i18n.t('jsonl.loadAll'));
|
|
88
|
+
all.disabled = state.loadState !== 'preview';
|
|
89
|
+
all.addEventListener('click', () => void controller.dispatch({ type: 'load-all' }));
|
|
90
|
+
const saveButton = el('button', ctx.i18n.t('jsonl.save'));
|
|
91
|
+
saveButton.disabled = !controller.canSave() || (!ctx.writeback && !ctx.save);
|
|
92
|
+
saveButton.title = controller.canSave() ? '' : ctx.i18n.t('jsonl.invalidSave');
|
|
93
|
+
saveButton.addEventListener('click', () => void save());
|
|
94
|
+
bar.append(search, add, remove, more, all, saveButton);
|
|
95
|
+
frame.append(bar);
|
|
96
|
+
if (state.loadState !== 'complete') {
|
|
97
|
+
const banner = el('div', ctx.i18n.t('jsonl.preview'));
|
|
98
|
+
banner.className = 'omni-jsonl__banner';
|
|
99
|
+
frame.append(banner);
|
|
100
|
+
}
|
|
101
|
+
const rows = el('div');
|
|
102
|
+
rows.className = 'omni-jsonl__rows';
|
|
103
|
+
const query = asciiLower(state.search);
|
|
104
|
+
const filtered = state.entries.filter(entry => !query || asciiLower(`${entry.raw} ${pretty(entry)}`).includes(query));
|
|
105
|
+
for (const entry of filtered.slice(0, visible.count))
|
|
106
|
+
rows.append(renderRow(entry));
|
|
107
|
+
if (filtered.length > visible.count) {
|
|
108
|
+
const batch = el('button', ctx.i18n.t('jsonl.showMore'));
|
|
109
|
+
batch.addEventListener('click', () => { visible.count += 5_000; render(); });
|
|
110
|
+
rows.append(batch);
|
|
111
|
+
}
|
|
112
|
+
frame.append(rows);
|
|
113
|
+
}
|
|
114
|
+
function renderRow(entry) {
|
|
115
|
+
const row = el('div');
|
|
116
|
+
row.className = `omni-jsonl__row${entry.value ? '' : ' omni-jsonl__invalid'}`;
|
|
117
|
+
row.tabIndex = 0;
|
|
118
|
+
row.draggable = controller.state.loadState === 'complete';
|
|
119
|
+
row.dataset.id = entry.id;
|
|
120
|
+
row.setAttribute('aria-selected', String(controller.state.selected.has(entry.id)));
|
|
121
|
+
row.setAttribute('aria-label', ctx.i18n.t(entry.value ? 'jsonl.rowValid' : 'jsonl.rowInvalid', { line: entry.line }));
|
|
122
|
+
const line = el('span', String(entry.line));
|
|
123
|
+
const code = el('code');
|
|
124
|
+
syntax(code, entry.raw);
|
|
125
|
+
row.append(line, code);
|
|
126
|
+
const actions = el('span');
|
|
127
|
+
actions.className = 'omni-jsonl__actions';
|
|
128
|
+
const copy = el('button', ctx.i18n.t('structured.copyValue'));
|
|
129
|
+
copy.disabled = !ctx.clipboard;
|
|
130
|
+
copy.addEventListener('click', event => { event.stopPropagation(); void ctx.clipboard?.writeText(entry.raw); });
|
|
131
|
+
const edit = el('button', ctx.i18n.t('jsonl.edit'));
|
|
132
|
+
edit.disabled = controller.state.loadState !== 'complete';
|
|
133
|
+
edit.addEventListener('click', event => { event.stopPropagation(); editing = entry.id; render(); });
|
|
134
|
+
actions.append(copy, edit);
|
|
135
|
+
row.append(actions);
|
|
136
|
+
row.addEventListener('click', event => { controller.dispatch({ type: 'select', id: entry.id, additive: event.metaKey || event.ctrlKey, range: event.shiftKey }); detail = entry.id; });
|
|
137
|
+
row.addEventListener('focus', () => { detail = entry.id; renderDetail(row, entry); });
|
|
138
|
+
row.addEventListener('mouseenter', () => renderDetail(row, entry));
|
|
139
|
+
row.addEventListener('dragstart', () => { dragged = entry.id; });
|
|
140
|
+
row.addEventListener('dragover', event => event.preventDefault());
|
|
141
|
+
row.addEventListener('drop', event => { event.preventDefault(); if (dragged && dragged !== entry.id)
|
|
142
|
+
controller.dispatch({ type: 'move', from: dragged, to: entry.id }); dragged = null; });
|
|
143
|
+
if (editing === entry.id) {
|
|
144
|
+
const box = el('div');
|
|
145
|
+
box.className = 'omni-jsonl__editor';
|
|
146
|
+
const textarea = el('textarea');
|
|
147
|
+
textarea.value = entry.raw;
|
|
148
|
+
const error = el('div');
|
|
149
|
+
const apply = el('button', ctx.i18n.t('jsonl.apply'));
|
|
150
|
+
const cancel = el('button', ctx.i18n.t('jsonl.cancel'));
|
|
151
|
+
const validate = () => { try {
|
|
152
|
+
JSON.parse(textarea.value);
|
|
153
|
+
error.textContent = '';
|
|
154
|
+
apply.disabled = false;
|
|
155
|
+
}
|
|
156
|
+
catch (reason) {
|
|
157
|
+
error.textContent = String(reason);
|
|
158
|
+
apply.disabled = true;
|
|
159
|
+
} };
|
|
160
|
+
textarea.addEventListener('input', validate);
|
|
161
|
+
apply.addEventListener('click', () => { controller.dispatch({ type: 'edit', id: entry.id, raw: textarea.value }); editing = null; });
|
|
162
|
+
cancel.addEventListener('click', () => { editing = null; render(); });
|
|
163
|
+
validate();
|
|
164
|
+
box.append(textarea, error, apply, cancel);
|
|
165
|
+
row.append(box);
|
|
166
|
+
}
|
|
167
|
+
if (detail === entry.id)
|
|
168
|
+
renderDetail(row, entry);
|
|
169
|
+
return row;
|
|
170
|
+
}
|
|
171
|
+
function renderDetail(row, entry) { row.querySelector('.omni-jsonl__detail')?.remove(); const panel = el('pre', pretty(entry)); panel.className = 'omni-jsonl__detail'; row.append(panel); }
|
|
172
|
+
function pretty(entry) { if (!entry.raw.trim())
|
|
173
|
+
return ''; try {
|
|
174
|
+
return JSON.stringify(JSON.parse(entry.raw), null, 2);
|
|
175
|
+
}
|
|
176
|
+
catch {
|
|
177
|
+
return entry.raw;
|
|
178
|
+
} }
|
|
179
|
+
render();
|
|
180
|
+
return { dispose() { disposed = true; unsubscribe(); frame.removeEventListener('keydown', keydown); frame.remove(); if (root instanceof ShadowRoot)
|
|
181
|
+
root.replaceChildren();
|
|
182
|
+
else
|
|
183
|
+
container.classList.remove(VIEWER_ROOT_CLASS, 'omni-viewer--jsonl'); } };
|
|
184
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const jsonlViewerCss = ":host,.omni-viewer--jsonl{display:block;height:100%;color:var(--omni-fg,#ddd);background:var(--omni-bg,#1e1e1e);font:13px var(--omni-font,system-ui)}.omni-jsonl{height:100%;display:flex;flex-direction:column}.omni-jsonl__bar{display:flex;gap:5px;padding:6px;border-bottom:1px solid var(--omni-border,#444)}.omni-jsonl input,.omni-jsonl button,.omni-jsonl textarea{font:inherit;background:var(--omni-button-bg,#333);color:inherit;border:1px solid var(--omni-border,#555);padding:3px 7px}.omni-jsonl__banner{padding:6px;color:var(--omni-fg-muted,#999)}.omni-jsonl__rows{overflow:auto;font-family:var(--omni-font-mono,monospace)}.omni-jsonl__row{position:relative;display:grid;grid-template-columns:4em minmax(0,1fr) auto;gap:8px;padding:5px 8px;cursor:pointer}.omni-jsonl__row[aria-selected=true]{background:var(--omni-selection,#264f78)}.omni-jsonl__invalid{color:var(--omni-error,#f48771)}.omni-jsonl__actions{display:flex;gap:4px}.omni-jsonl__detail,.omni-jsonl__editor{grid-column:2/-1;white-space:pre-wrap;background:var(--omni-input-bg,#171717);padding:10px;z-index:2}.omni-jsonl__editor textarea{display:block;box-sizing:border-box;width:100%;min-height:8em}.omni-jsonl__key{color:#9cdcfe}.omni-jsonl__string{color:#ce9178}.omni-jsonl__number{color:#b5cea8}.omni-jsonl__literal{color:#569cd6}";
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const jsonlViewerCss = `:host,.omni-viewer--jsonl{display:block;height:100%;color:var(--omni-fg,#ddd);background:var(--omni-bg,#1e1e1e);font:13px var(--omni-font,system-ui)}.omni-jsonl{height:100%;display:flex;flex-direction:column}.omni-jsonl__bar{display:flex;gap:5px;padding:6px;border-bottom:1px solid var(--omni-border,#444)}.omni-jsonl input,.omni-jsonl button,.omni-jsonl textarea{font:inherit;background:var(--omni-button-bg,#333);color:inherit;border:1px solid var(--omni-border,#555);padding:3px 7px}.omni-jsonl__banner{padding:6px;color:var(--omni-fg-muted,#999)}.omni-jsonl__rows{overflow:auto;font-family:var(--omni-font-mono,monospace)}.omni-jsonl__row{position:relative;display:grid;grid-template-columns:4em minmax(0,1fr) auto;gap:8px;padding:5px 8px;cursor:pointer}.omni-jsonl__row[aria-selected=true]{background:var(--omni-selection,#264f78)}.omni-jsonl__invalid{color:var(--omni-error,#f48771)}.omni-jsonl__actions{display:flex;gap:4px}.omni-jsonl__detail,.omni-jsonl__editor{grid-column:2/-1;white-space:pre-wrap;background:var(--omni-input-bg,#171717);padding:10px;z-index:2}.omni-jsonl__editor textarea{display:block;box-sizing:border-box;width:100%;min-height:8em}.omni-jsonl__key{color:#9cdcfe}.omni-jsonl__string{color:#ce9178}.omni-jsonl__number{color:#b5cea8}.omni-jsonl__literal{color:#569cd6}`;
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import type { MarkdownHeading } from '../../parsers/markdown/index.js';
|
|
2
|
+
export type MarkdownViewMode = 'preview' | 'split' | 'source';
|
|
3
|
+
export type MarkdownAction = {
|
|
4
|
+
type: 'set-mode';
|
|
5
|
+
mode: MarkdownViewMode;
|
|
6
|
+
} | {
|
|
7
|
+
type: 'set-search';
|
|
8
|
+
query: string;
|
|
9
|
+
} | {
|
|
10
|
+
type: 'next-match';
|
|
11
|
+
} | {
|
|
12
|
+
type: 'select-heading';
|
|
13
|
+
id: string;
|
|
14
|
+
} | {
|
|
15
|
+
type: 'edit-source';
|
|
16
|
+
source: string;
|
|
17
|
+
} | {
|
|
18
|
+
type: 'undo';
|
|
19
|
+
} | {
|
|
20
|
+
type: 'redo';
|
|
21
|
+
} | {
|
|
22
|
+
type: 'mark-saved';
|
|
23
|
+
} | {
|
|
24
|
+
type: 'copy-code';
|
|
25
|
+
code: string;
|
|
26
|
+
};
|
|
27
|
+
export interface MarkdownMatch {
|
|
28
|
+
start: number;
|
|
29
|
+
end: number;
|
|
30
|
+
}
|
|
31
|
+
export interface MarkdownViewState {
|
|
32
|
+
mode: MarkdownViewMode;
|
|
33
|
+
query: string;
|
|
34
|
+
matchIndex: number;
|
|
35
|
+
selectedHeading?: string;
|
|
36
|
+
source: string;
|
|
37
|
+
savedSource: string;
|
|
38
|
+
dirty: boolean;
|
|
39
|
+
canUndo: boolean;
|
|
40
|
+
canRedo: boolean;
|
|
41
|
+
}
|
|
42
|
+
export interface MarkdownController {
|
|
43
|
+
readonly state: MarkdownViewState;
|
|
44
|
+
dispatch(action: MarkdownAction): void;
|
|
45
|
+
matches(): readonly MarkdownMatch[];
|
|
46
|
+
subscribe(listener: () => void): () => void;
|
|
47
|
+
}
|
|
48
|
+
/** State shared by the preview and source editor. History is kept here rather
|
|
49
|
+
* than relying on a textarea's platform-specific undo implementation. */
|
|
50
|
+
export declare function createMarkdownController(text: string, _headings: readonly MarkdownHeading[]): MarkdownController;
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
/** State shared by the preview and source editor. History is kept here rather
|
|
2
|
+
* than relying on a textarea's platform-specific undo implementation. */
|
|
3
|
+
export function createMarkdownController(text, _headings) {
|
|
4
|
+
let state = {
|
|
5
|
+
mode: 'preview', query: '', matchIndex: 0, source: text, savedSource: text,
|
|
6
|
+
dirty: false, canUndo: false, canRedo: false
|
|
7
|
+
};
|
|
8
|
+
const undo = [];
|
|
9
|
+
const redo = [];
|
|
10
|
+
const listeners = new Set();
|
|
11
|
+
const emit = () => listeners.forEach(listener => listener());
|
|
12
|
+
const setSource = (source) => {
|
|
13
|
+
state = { ...state, source, dirty: source !== state.savedSource, canUndo: undo.length > 0, canRedo: redo.length > 0 };
|
|
14
|
+
};
|
|
15
|
+
const matches = () => {
|
|
16
|
+
const needle = state.query.toLocaleLowerCase();
|
|
17
|
+
if (!needle)
|
|
18
|
+
return [];
|
|
19
|
+
const haystack = state.source.toLocaleLowerCase();
|
|
20
|
+
const result = [];
|
|
21
|
+
for (let at = haystack.indexOf(needle); at >= 0; at = haystack.indexOf(needle, at + Math.max(1, needle.length))) {
|
|
22
|
+
result.push({ start: at, end: at + needle.length });
|
|
23
|
+
}
|
|
24
|
+
return result;
|
|
25
|
+
};
|
|
26
|
+
return {
|
|
27
|
+
get state() { return state; },
|
|
28
|
+
dispatch(action) {
|
|
29
|
+
if (action.type === 'set-mode')
|
|
30
|
+
state = { ...state, mode: action.mode };
|
|
31
|
+
else if (action.type === 'set-search')
|
|
32
|
+
state = { ...state, query: action.query, matchIndex: 0 };
|
|
33
|
+
else if (action.type === 'next-match') {
|
|
34
|
+
const count = matches().length;
|
|
35
|
+
state = { ...state, matchIndex: count ? (state.matchIndex + 1) % count : 0 };
|
|
36
|
+
}
|
|
37
|
+
else if (action.type === 'select-heading')
|
|
38
|
+
state = { ...state, selectedHeading: action.id };
|
|
39
|
+
else if (action.type === 'edit-source' && action.source !== state.source) {
|
|
40
|
+
undo.push(state.source);
|
|
41
|
+
if (undo.length > 100)
|
|
42
|
+
undo.shift();
|
|
43
|
+
redo.length = 0;
|
|
44
|
+
setSource(action.source);
|
|
45
|
+
}
|
|
46
|
+
else if (action.type === 'undo' && undo.length) {
|
|
47
|
+
redo.push(state.source);
|
|
48
|
+
setSource(undo.pop());
|
|
49
|
+
}
|
|
50
|
+
else if (action.type === 'redo' && redo.length) {
|
|
51
|
+
undo.push(state.source);
|
|
52
|
+
setSource(redo.pop());
|
|
53
|
+
}
|
|
54
|
+
else if (action.type === 'mark-saved') {
|
|
55
|
+
state = { ...state, savedSource: state.source, dirty: false };
|
|
56
|
+
}
|
|
57
|
+
emit();
|
|
58
|
+
},
|
|
59
|
+
matches,
|
|
60
|
+
subscribe(listener) { listeners.add(listener); return () => listeners.delete(listener); }
|
|
61
|
+
};
|
|
62
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
import type { ClipboardService, DocumentAssetsService, FileWritebackService, HostContext, NavigationService } from '../../host/index.js';
|
|
2
|
+
import { type MarkdownParseOptions } from '../../parsers/markdown/index.js';
|
|
3
|
+
import type { ResourceLimits } from '../../parsers/types.js';
|
|
4
|
+
import { type MountOptions, type ViewerHandle, type ViewerInput } from '../types.js';
|
|
5
|
+
export { parseMarkdown, type MarkdownDocument } from '../../parsers/markdown/index.js';
|
|
6
|
+
export { markdownViewerCss } from './styles.js';
|
|
7
|
+
export { createMarkdownController, type MarkdownAction, type MarkdownController, type MarkdownViewMode, type MarkdownViewState } from './controller.js';
|
|
8
|
+
export { maskMathSegments, mathSegmentLiteral, type MathSegment, type MaskedMathSource } from './math.js';
|
|
9
|
+
export declare const MARKDOWN_VIEWER_META: {
|
|
10
|
+
id: string;
|
|
11
|
+
displayNameKey: string;
|
|
12
|
+
extensions: string[];
|
|
13
|
+
priority: number;
|
|
14
|
+
requiredServices: readonly [];
|
|
15
|
+
optionalServices: readonly ["clipboard", "navigation", "documentAssets", "writeback"];
|
|
16
|
+
inputOwnership: "borrows";
|
|
17
|
+
};
|
|
18
|
+
export interface MarkdownRenderer {
|
|
19
|
+
parse(markdown: string): string;
|
|
20
|
+
}
|
|
21
|
+
export interface DomPurify {
|
|
22
|
+
sanitize(html: string, options: Record<string, unknown>): string;
|
|
23
|
+
}
|
|
24
|
+
export interface MarkdownHighlighter {
|
|
25
|
+
highlight(source: string, options: {
|
|
26
|
+
language: string;
|
|
27
|
+
ignoreIllegals: boolean;
|
|
28
|
+
}): {
|
|
29
|
+
value: string;
|
|
30
|
+
language?: string;
|
|
31
|
+
};
|
|
32
|
+
highlightAuto(source: string): {
|
|
33
|
+
value: string;
|
|
34
|
+
language?: string;
|
|
35
|
+
};
|
|
36
|
+
getLanguage(language: string): unknown;
|
|
37
|
+
}
|
|
38
|
+
export interface MarkdownDiagramRenderer {
|
|
39
|
+
renderMermaid?(id: string, source: string): Promise<string>;
|
|
40
|
+
renderPlantUml?(source: string, document: Document): SVGElement;
|
|
41
|
+
}
|
|
42
|
+
/** TeX → HTML (KaTeX renderToString shape). The output is sanitized before
|
|
43
|
+
* insertion, so the renderer does not need to be trusted with the DOM. */
|
|
44
|
+
export interface MarkdownMathRenderer {
|
|
45
|
+
renderToHtml(source: string, displayMode: boolean): string;
|
|
46
|
+
}
|
|
47
|
+
export interface MarkdownViewerDeps {
|
|
48
|
+
render: MarkdownRenderer;
|
|
49
|
+
createDOMPurify(window: Window): DomPurify;
|
|
50
|
+
highlighter?: MarkdownHighlighter;
|
|
51
|
+
diagrams?: MarkdownDiagramRenderer;
|
|
52
|
+
math?: MarkdownMathRenderer;
|
|
53
|
+
}
|
|
54
|
+
export type MarkdownViewerContext = HostContext & {
|
|
55
|
+
clipboard?: ClipboardService;
|
|
56
|
+
navigation?: NavigationService;
|
|
57
|
+
documentAssets?: DocumentAssetsService;
|
|
58
|
+
writeback?: FileWritebackService;
|
|
59
|
+
};
|
|
60
|
+
export interface MarkdownMountOptions extends MountOptions {
|
|
61
|
+
limits?: ResourceLimits;
|
|
62
|
+
markdownLimits?: MarkdownParseOptions['markdownLimits'];
|
|
63
|
+
}
|
|
64
|
+
export declare function mountMarkdownViewer(input: ViewerInput, container: HTMLElement, ctx: MarkdownViewerContext, deps: MarkdownViewerDeps, options?: MarkdownMountOptions): Promise<ViewerHandle>;
|