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,4 @@
|
|
|
1
|
+
import type { SlideDeck } from '../slide-model.js';
|
|
2
|
+
import type { ParseOptions, ParseOutcome } from '../types.js';
|
|
3
|
+
/** VS Code's full-fidelity PPTX parser, adapted from a file path to bytes. */
|
|
4
|
+
export declare function parsePptxVscode(input: Uint8Array, options?: ParseOptions): Promise<ParseOutcome<SlideDeck>>;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { PptxXmlParser } from './vscode-parser.js';
|
|
2
|
+
/** VS Code's full-fidelity PPTX parser, adapted from a file path to bytes. */
|
|
3
|
+
export async function parsePptxVscode(input, options = {}) {
|
|
4
|
+
const started = Date.now();
|
|
5
|
+
const diagnostics = [];
|
|
6
|
+
if (options.signal?.aborted)
|
|
7
|
+
return { result: { status: 'failed', failure: { code: 'aborted', retryable: true, messageKey: 'diag.aborted' }, diagnostics }, execution: { workerUsed: false, hardLimitEnforced: false, elapsedMillis: 0 } };
|
|
8
|
+
if (input.byteLength > (options.limits?.maxInputBytes ?? 50 * 1024 * 1024))
|
|
9
|
+
return { result: { status: 'failed', failure: { code: 'limit-exceeded', retryable: false, messageKey: 'diag.limit-exceeded.input' }, diagnostics }, execution: { workerUsed: false, hardLimitEnforced: false, elapsedMillis: Date.now() - started } };
|
|
10
|
+
try {
|
|
11
|
+
const parsed = await PptxXmlParser.parse(input);
|
|
12
|
+
const slides = parsed.slides;
|
|
13
|
+
return { result: { status: 'ok', document: { slides, totalSlides: parsed.totalSlides, ...(slides[0] ? { slideSize: { widthPx: slides[0].widthPx, heightPx: slides[0].heightPx } } : {}) }, diagnostics }, execution: { workerUsed: false, hardLimitEnforced: false, elapsedMillis: Date.now() - started } };
|
|
14
|
+
}
|
|
15
|
+
catch {
|
|
16
|
+
return { result: { status: 'failed', failure: { code: 'invalid-format', retryable: false, messageKey: 'diag.ppt.invalid-format' }, diagnostics }, execution: { workerUsed: false, hardLimitEnforced: false, elapsedMillis: Date.now() - started } };
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
const EOCD = 0x06054b50, CDFH = 0x02014b50, LFH = 0x04034b50;
|
|
2
|
+
function entries(input) { const v = new DataView(input.buffer, input.byteOffset, input.byteLength); let eocd = -1; for (let p = input.length - 22; p >= Math.max(0, input.length - 65557); p--)
|
|
3
|
+
if (v.getUint32(p, true) === EOCD) {
|
|
4
|
+
eocd = p;
|
|
5
|
+
break;
|
|
6
|
+
} if (eocd < 0)
|
|
7
|
+
throw new Error('Invalid ZIP'); const count = v.getUint16(eocd + 10, true), out = []; let p = v.getUint32(eocd + 16, true); for (let i = 0; i < count; i++) {
|
|
8
|
+
if (p + 46 > input.length || v.getUint32(p, true) !== CDFH)
|
|
9
|
+
break;
|
|
10
|
+
const nameLen = v.getUint16(p + 28, true), extra = v.getUint16(p + 30, true), comment = v.getUint16(p + 32, true);
|
|
11
|
+
out.push({ name: new TextDecoder().decode(input.subarray(p + 46, p + 46 + nameLen)), method: v.getUint16(p + 10, true), compressedSize: v.getUint32(p + 20, true), localOffset: v.getUint32(p + 42, true) });
|
|
12
|
+
p += 46 + nameLen + extra + comment;
|
|
13
|
+
} return out; }
|
|
14
|
+
async function inflate(data) { const stream = new Blob([new Uint8Array(data).buffer]).stream().pipeThrough(new DecompressionStream('deflate-raw')); return new Uint8Array(await new Response(stream).arrayBuffer()); }
|
|
15
|
+
export async function openPptxZip(input, options = {}) { const list = entries(input), byName = new Map(list.map(e => [e.name, e])); let decompressed = 0; const read = async (path) => { if (options.signal?.aborted)
|
|
16
|
+
throw new DOMException('Aborted', 'AbortError'); const e = byName.get(path); if (!e)
|
|
17
|
+
return; const v = new DataView(input.buffer, input.byteOffset, input.byteLength), p = e.localOffset; if (p + 30 > input.length || v.getUint32(p, true) !== LFH)
|
|
18
|
+
throw new Error('Invalid ZIP entry'); const start = p + 30 + v.getUint16(p + 26, true) + v.getUint16(p + 28, true), compressed = input.slice(start, start + e.compressedSize); const value = e.method === 0 ? compressed : e.method === 8 ? await inflate(compressed) : undefined; if (!value)
|
|
19
|
+
throw new Error('Unsupported ZIP compression'); decompressed += value.length; if (decompressed > (options.limits?.maxDecompressedBytes ?? 256 * 1024 * 1024))
|
|
20
|
+
throw new Error('ZIP limit'); return value; }; return { list: async () => list.map(e => e.name), bytes: read, text: async (path) => { const value = await read(path); return value ? new TextDecoder().decode(value) : undefined; } }; }
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
export interface ProtoRange {
|
|
2
|
+
startLine: number;
|
|
3
|
+
endLine: number;
|
|
4
|
+
}
|
|
5
|
+
export interface ProtoField {
|
|
6
|
+
name: string;
|
|
7
|
+
type: string;
|
|
8
|
+
label: string;
|
|
9
|
+
number: number;
|
|
10
|
+
repeated: boolean;
|
|
11
|
+
optional: boolean;
|
|
12
|
+
map: boolean;
|
|
13
|
+
oneof?: string;
|
|
14
|
+
options: string[];
|
|
15
|
+
documentation: string;
|
|
16
|
+
line: number;
|
|
17
|
+
}
|
|
18
|
+
export interface ProtoMessage {
|
|
19
|
+
kind: 'message';
|
|
20
|
+
name: string;
|
|
21
|
+
fullName: string;
|
|
22
|
+
documentation: string;
|
|
23
|
+
fields: ProtoField[];
|
|
24
|
+
messages: ProtoMessage[];
|
|
25
|
+
enums: ProtoEnum[];
|
|
26
|
+
oneofs: string[];
|
|
27
|
+
reserved: string[];
|
|
28
|
+
range: ProtoRange;
|
|
29
|
+
}
|
|
30
|
+
export interface ProtoEnumValue {
|
|
31
|
+
name: string;
|
|
32
|
+
number: number;
|
|
33
|
+
documentation: string;
|
|
34
|
+
line: number;
|
|
35
|
+
}
|
|
36
|
+
export interface ProtoEnum {
|
|
37
|
+
kind: 'enum';
|
|
38
|
+
name: string;
|
|
39
|
+
fullName: string;
|
|
40
|
+
documentation: string;
|
|
41
|
+
values: ProtoEnumValue[];
|
|
42
|
+
range: ProtoRange;
|
|
43
|
+
}
|
|
44
|
+
export interface ProtoRpc {
|
|
45
|
+
name: string;
|
|
46
|
+
requestType: string;
|
|
47
|
+
responseType: string;
|
|
48
|
+
requestStream: boolean;
|
|
49
|
+
responseStream: boolean;
|
|
50
|
+
documentation: string;
|
|
51
|
+
line: number;
|
|
52
|
+
}
|
|
53
|
+
export interface ProtoService {
|
|
54
|
+
kind: 'service';
|
|
55
|
+
name: string;
|
|
56
|
+
fullName: string;
|
|
57
|
+
documentation: string;
|
|
58
|
+
rpcs: ProtoRpc[];
|
|
59
|
+
range: ProtoRange;
|
|
60
|
+
}
|
|
61
|
+
export interface ProtoReference {
|
|
62
|
+
from: string;
|
|
63
|
+
fromKind: 'field' | 'rpc' | 'import';
|
|
64
|
+
name: string;
|
|
65
|
+
to: string;
|
|
66
|
+
line: number;
|
|
67
|
+
}
|
|
68
|
+
export interface ProtoModel {
|
|
69
|
+
fileName: string;
|
|
70
|
+
syntax: string;
|
|
71
|
+
packageName: string;
|
|
72
|
+
imports: string[];
|
|
73
|
+
messages: ProtoMessage[];
|
|
74
|
+
enums: ProtoEnum[];
|
|
75
|
+
services: ProtoService[];
|
|
76
|
+
references: ProtoReference[];
|
|
77
|
+
warnings: string[];
|
|
78
|
+
stats: {
|
|
79
|
+
messages: number;
|
|
80
|
+
enums: number;
|
|
81
|
+
services: number;
|
|
82
|
+
rpcs: number;
|
|
83
|
+
fields: number;
|
|
84
|
+
imports: number;
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
/** Parse a proto2/proto3 schema without loading protoc or executing schema code. */
|
|
88
|
+
export declare function parseProto(source: string, fileName?: string): ProtoModel;
|
|
89
|
+
export declare function flattenProtoMessages(messages: readonly ProtoMessage[]): ProtoMessage[];
|
|
90
|
+
export declare function allProtoTypes(model: ProtoModel): Array<ProtoMessage | ProtoEnum | ProtoService>;
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
const scalarTypes = new Set(['double', 'float', 'int32', 'int64', 'uint32', 'uint64', 'sint32', 'sint64', 'fixed32', 'fixed64', 'sfixed32', 'sfixed64', 'bool', 'string', 'bytes']);
|
|
2
|
+
const declarationPattern = /^(.+?)\s+([A-Za-z_][\w]*)\s*=\s*([0-9]+)\s*(?:\[([^\]]*)\])?\s*;/;
|
|
3
|
+
const labeledFieldPattern = /^(optional|required|repeated)\s+(.+?)$/;
|
|
4
|
+
/** Parse a proto2/proto3 schema without loading protoc or executing schema code. */
|
|
5
|
+
export function parseProto(source, fileName = '') {
|
|
6
|
+
const lines = source.replace(/\r\n/g, '\n').replace(/\r/g, '\n').split('\n');
|
|
7
|
+
const model = { fileName, syntax: '', packageName: '', imports: [], messages: [], enums: [], services: [], references: [], warnings: [], stats: { messages: 0, enums: 0, services: 0, rpcs: 0, fields: 0, imports: 0 } };
|
|
8
|
+
const stack = [];
|
|
9
|
+
const docs = [];
|
|
10
|
+
let inBlockComment = false;
|
|
11
|
+
let blockComment = [];
|
|
12
|
+
const consumeDocs = () => { const value = docs.join('\n').trim(); docs.length = 0; return value; };
|
|
13
|
+
const currentMessage = () => { for (let i = stack.length - 1; i >= 0; i--)
|
|
14
|
+
if (stack[i].kind === 'message')
|
|
15
|
+
return stack[i].node; return undefined; };
|
|
16
|
+
const currentEnum = () => stack.at(-1)?.kind === 'enum' ? stack.at(-1).node : undefined;
|
|
17
|
+
const currentService = () => stack.at(-1)?.kind === 'service' ? stack.at(-1).node : undefined;
|
|
18
|
+
const currentOneof = () => stack.at(-1)?.kind === 'oneof' ? stack.at(-1).name : undefined;
|
|
19
|
+
lines.forEach((rawLine, index) => {
|
|
20
|
+
const lineNumber = index + 1;
|
|
21
|
+
let line = rawLine.trim();
|
|
22
|
+
if (inBlockComment) {
|
|
23
|
+
const end = line.indexOf('*/');
|
|
24
|
+
if (end < 0) {
|
|
25
|
+
blockComment.push(cleanDocLine(line));
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
blockComment.push(cleanDocLine(line.slice(0, end)));
|
|
29
|
+
docs.push(blockComment.join('\n').trim());
|
|
30
|
+
blockComment = [];
|
|
31
|
+
inBlockComment = false;
|
|
32
|
+
line = line.slice(end + 2).trim();
|
|
33
|
+
}
|
|
34
|
+
if (!line)
|
|
35
|
+
return;
|
|
36
|
+
if (line.startsWith('//')) {
|
|
37
|
+
docs.push(line.replace(/^\/\/\s?/, ''));
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
if (line.startsWith('/*')) {
|
|
41
|
+
const end = line.indexOf('*/', 2);
|
|
42
|
+
if (end < 0) {
|
|
43
|
+
inBlockComment = true;
|
|
44
|
+
blockComment = [cleanDocLine(line.slice(2))];
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
docs.push(cleanDocLine(line.slice(2, end)));
|
|
48
|
+
line = line.slice(end + 2).trim();
|
|
49
|
+
}
|
|
50
|
+
line = stripInlineComment(line).trim();
|
|
51
|
+
if (!line)
|
|
52
|
+
return;
|
|
53
|
+
let match = line.match(/^syntax\s*=\s*"([^"]+)"\s*;/);
|
|
54
|
+
if (match) {
|
|
55
|
+
model.syntax = match[1];
|
|
56
|
+
consumeDocs();
|
|
57
|
+
return;
|
|
58
|
+
}
|
|
59
|
+
match = line.match(/^package\s+([\w.]+)\s*;/);
|
|
60
|
+
if (match) {
|
|
61
|
+
model.packageName = match[1];
|
|
62
|
+
consumeDocs();
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
match = line.match(/^import\s+(?:public\s+|weak\s+)?["']([^"']+)["']\s*;/);
|
|
66
|
+
if (match) {
|
|
67
|
+
const imported = match[1];
|
|
68
|
+
model.imports.push(imported);
|
|
69
|
+
model.references.push({ from: fileName || 'current file', fromKind: 'import', name: imported, to: imported, line: lineNumber });
|
|
70
|
+
consumeDocs();
|
|
71
|
+
return;
|
|
72
|
+
}
|
|
73
|
+
match = line.match(/^message\s+([A-Za-z_]\w*)\s*\{/);
|
|
74
|
+
if (match) {
|
|
75
|
+
const parent = currentMessage();
|
|
76
|
+
const fullName = qualify(match[1], parent?.fullName || model.packageName);
|
|
77
|
+
const node = { kind: 'message', name: match[1], fullName, documentation: consumeDocs(), fields: [], messages: [], enums: [], oneofs: [], reserved: [], range: { startLine: lineNumber, endLine: lineNumber } };
|
|
78
|
+
parent ? parent.messages.push(node) : model.messages.push(node);
|
|
79
|
+
stack.push({ kind: 'message', name: node.name, fullName, node });
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
match = line.match(/^enum\s+([A-Za-z_]\w*)\s*\{/);
|
|
83
|
+
if (match) {
|
|
84
|
+
const parent = currentMessage();
|
|
85
|
+
const fullName = qualify(match[1], parent?.fullName || model.packageName);
|
|
86
|
+
const node = { kind: 'enum', name: match[1], fullName, documentation: consumeDocs(), values: [], range: { startLine: lineNumber, endLine: lineNumber } };
|
|
87
|
+
parent ? parent.enums.push(node) : model.enums.push(node);
|
|
88
|
+
stack.push({ kind: 'enum', name: node.name, fullName, node });
|
|
89
|
+
return;
|
|
90
|
+
}
|
|
91
|
+
match = line.match(/^service\s+([A-Za-z_]\w*)\s*\{/);
|
|
92
|
+
if (match) {
|
|
93
|
+
const fullName = qualify(match[1], model.packageName);
|
|
94
|
+
const node = { kind: 'service', name: match[1], fullName, documentation: consumeDocs(), rpcs: [], range: { startLine: lineNumber, endLine: lineNumber } };
|
|
95
|
+
model.services.push(node);
|
|
96
|
+
stack.push({ kind: 'service', name: node.name, fullName, node });
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
match = line.match(/^oneof\s+([A-Za-z_]\w*)\s*\{/);
|
|
100
|
+
if (match) {
|
|
101
|
+
currentMessage()?.oneofs.push(match[1]);
|
|
102
|
+
stack.push({ kind: 'oneof', name: match[1], fullName: match[1] });
|
|
103
|
+
consumeDocs();
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
const enumNode = currentEnum();
|
|
107
|
+
match = line.match(/^([A-Za-z_]\w*)\s*=\s*(-?\d+)\s*(?:\[[^\]]*\])?\s*;/);
|
|
108
|
+
if (enumNode && match) {
|
|
109
|
+
enumNode.values.push({ name: match[1], number: Number(match[2]), documentation: consumeDocs(), line: lineNumber });
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
const service = currentService();
|
|
113
|
+
match = line.match(/^rpc\s+([A-Za-z_]\w*)\s*\(\s*(stream\s+)?([.\w]+)\s*\)\s+returns\s*\(\s*(stream\s+)?([.\w]+)\s*\)/);
|
|
114
|
+
if (service && match) {
|
|
115
|
+
const rpc = { name: match[1], requestType: cleanType(match[3]), responseType: cleanType(match[5]), requestStream: !!match[2], responseStream: !!match[4], documentation: consumeDocs(), line: lineNumber };
|
|
116
|
+
service.rpcs.push(rpc);
|
|
117
|
+
model.references.push({ from: `${service.fullName}.${rpc.name}`, fromKind: 'rpc', name: 'request', to: rpc.requestType, line: lineNumber }, { from: `${service.fullName}.${rpc.name}`, fromKind: 'rpc', name: 'response', to: rpc.responseType, line: lineNumber });
|
|
118
|
+
if (line.includes('{'))
|
|
119
|
+
stack.push({ kind: 'block', name: '', fullName: '' });
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
const message = currentMessage();
|
|
123
|
+
if (message) {
|
|
124
|
+
match = line.match(/^reserved\s+(.+);/);
|
|
125
|
+
if (match) {
|
|
126
|
+
message.reserved.push(match[1]);
|
|
127
|
+
consumeDocs();
|
|
128
|
+
return;
|
|
129
|
+
}
|
|
130
|
+
const field = parseField(line, lineNumber, consumeDocs(), currentOneof());
|
|
131
|
+
if (field) {
|
|
132
|
+
message.fields.push(field);
|
|
133
|
+
if (!scalarTypes.has(cleanType(field.type)) && !field.map)
|
|
134
|
+
model.references.push({ from: message.fullName, fromKind: 'field', name: field.name, to: cleanType(field.type), line: lineNumber });
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
if (line.includes('}')) {
|
|
139
|
+
for (let n = count(line, '}'); n > 0; n--) {
|
|
140
|
+
const frame = stack.pop();
|
|
141
|
+
if (frame?.node)
|
|
142
|
+
frame.node.range.endLine = lineNumber;
|
|
143
|
+
}
|
|
144
|
+
consumeDocs();
|
|
145
|
+
return;
|
|
146
|
+
}
|
|
147
|
+
if (line.endsWith('{') && !/^rpc\b/.test(line))
|
|
148
|
+
stack.push({ kind: 'block', name: '', fullName: '' });
|
|
149
|
+
consumeDocs();
|
|
150
|
+
});
|
|
151
|
+
model.stats = buildStats(model);
|
|
152
|
+
model.warnings = buildWarnings(model);
|
|
153
|
+
return model;
|
|
154
|
+
}
|
|
155
|
+
function parseField(line, lineNumber, documentation, oneof) {
|
|
156
|
+
if (line.startsWith('option ') || line.startsWith('extensions '))
|
|
157
|
+
return null;
|
|
158
|
+
let candidate = line;
|
|
159
|
+
let label = '';
|
|
160
|
+
const labeled = candidate.match(labeledFieldPattern);
|
|
161
|
+
if (labeled) {
|
|
162
|
+
label = labeled[1];
|
|
163
|
+
candidate = labeled[2];
|
|
164
|
+
}
|
|
165
|
+
const match = candidate.match(declarationPattern);
|
|
166
|
+
if (!match)
|
|
167
|
+
return null;
|
|
168
|
+
const type = match[1];
|
|
169
|
+
return { name: match[2], type, label, number: Number(match[3]), repeated: label === 'repeated', optional: label === 'optional', map: type.startsWith('map<'), ...(oneof ? { oneof } : {}), options: match[4]?.split(',').map(v => v.trim()).filter(Boolean) ?? [], documentation, line: lineNumber };
|
|
170
|
+
}
|
|
171
|
+
export function flattenProtoMessages(messages) { return messages.flatMap(message => [message, ...flattenProtoMessages(message.messages)]); }
|
|
172
|
+
export function allProtoTypes(model) { const messages = flattenProtoMessages(model.messages); return [...messages, ...model.enums, ...messages.flatMap(message => message.enums), ...model.services]; }
|
|
173
|
+
function buildStats(model) { const messages = flattenProtoMessages(model.messages); return { messages: messages.length, enums: model.enums.length + messages.reduce((n, m) => n + m.enums.length, 0), services: model.services.length, rpcs: model.services.reduce((n, s) => n + s.rpcs.length, 0), fields: messages.reduce((n, m) => n + m.fields.length, 0), imports: model.imports.length }; }
|
|
174
|
+
function buildWarnings(model) { const warnings = []; const messages = flattenProtoMessages(model.messages); const names = new Set([...messages.map(m => m.fullName), ...model.enums.map(e => e.fullName), ...messages.flatMap(m => m.enums.map(e => e.fullName))]); const shorts = new Set([...names].map(n => n.split('.').at(-1))); for (const message of messages) {
|
|
175
|
+
const numbers = new Map();
|
|
176
|
+
for (const field of message.fields) {
|
|
177
|
+
const previous = numbers.get(field.number);
|
|
178
|
+
if (previous)
|
|
179
|
+
warnings.push(`${message.fullName} reuses field number ${field.number} for ${previous} and ${field.name}.`);
|
|
180
|
+
numbers.set(field.number, field.name);
|
|
181
|
+
}
|
|
182
|
+
} for (const ref of model.references.filter(r => r.fromKind !== 'import')) {
|
|
183
|
+
const target = cleanType(ref.to);
|
|
184
|
+
if (!scalarTypes.has(target) && !names.has(target) && !shorts.has(target.split('.').at(-1)))
|
|
185
|
+
warnings.push(`${ref.from} references ${ref.to} on line ${ref.line}, but it is not declared in this file.`);
|
|
186
|
+
} if (!model.syntax)
|
|
187
|
+
warnings.push('No syntax declaration found.'); return warnings; }
|
|
188
|
+
function qualify(name, prefix) { return prefix ? `${prefix}.${name}` : name; }
|
|
189
|
+
function cleanType(type) { return type.replace(/^\./, '').trim(); }
|
|
190
|
+
function cleanDocLine(value) { return value.replace(/^\s*\*\s?/, '').trim(); }
|
|
191
|
+
function count(value, char) { return [...value].filter(v => v === char).length; }
|
|
192
|
+
function stripInlineComment(line) { let quoted = false; for (let i = 0; i < line.length - 1; i++) {
|
|
193
|
+
if (line[i] === '"' && line[i - 1] !== '\\')
|
|
194
|
+
quoted = !quoted;
|
|
195
|
+
if (!quoted && line[i] === '/' && line[i + 1] === '/')
|
|
196
|
+
return line.slice(0, i);
|
|
197
|
+
} return line; }
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export interface PsdHeader {
|
|
2
|
+
version: 1 | 2;
|
|
3
|
+
channels: number;
|
|
4
|
+
height: number;
|
|
5
|
+
width: number;
|
|
6
|
+
depth: number;
|
|
7
|
+
colorMode: number;
|
|
8
|
+
colorModeName: string;
|
|
9
|
+
pixelCount: number;
|
|
10
|
+
warnings: string[];
|
|
11
|
+
}
|
|
12
|
+
export interface PsdParseOptions {
|
|
13
|
+
maxBytes?: number;
|
|
14
|
+
maxPixels?: number;
|
|
15
|
+
}
|
|
16
|
+
export declare function parsePsdHeader(data: Uint8Array, options?: PsdParseOptions): PsdHeader;
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
const MODES = { 0: 'Bitmap', 1: 'Grayscale', 2: 'Indexed', 3: 'RGB', 4: 'CMYK', 7: 'Multichannel', 8: 'Duotone', 9: 'Lab' };
|
|
2
|
+
export function parsePsdHeader(data, options = {}) { const maxBytes = options.maxBytes ?? 128 * 1024 * 1024; if (data.byteLength > maxBytes)
|
|
3
|
+
throw new Error(`PSD exceeds the ${maxBytes.toLocaleString()} byte limit.`); if (data.length < 26)
|
|
4
|
+
throw new Error('PSD header is truncated.'); const sig = String.fromCharCode(...data.subarray(0, 4)); if (sig !== '8BPS')
|
|
5
|
+
throw new Error('Invalid PSD signature.'); const v = new DataView(data.buffer, data.byteOffset, data.byteLength), version = v.getUint16(4, false); if (version !== 1 && version !== 2)
|
|
6
|
+
throw new Error(`Unsupported PSD version ${version}.`); const channels = v.getUint16(12, false), height = v.getUint32(14, false), width = v.getUint32(18, false), depth = v.getUint16(22, false), colorMode = v.getUint16(24, false), pixelCount = width * height, maxPixels = options.maxPixels ?? 100_000_000; if (!width || !height || width > (version === 1 ? 30_000 : 300_000) || height > (version === 1 ? 30_000 : 300_000))
|
|
7
|
+
throw new Error('Invalid PSD canvas dimensions.'); if (pixelCount > maxPixels)
|
|
8
|
+
throw new Error(`PSD canvas exceeds the ${maxPixels.toLocaleString()} pixel limit.`); const warnings = []; if (![1, 8, 16, 32].includes(depth))
|
|
9
|
+
warnings.push(`Unusual channel depth: ${depth} bits.`); if (!MODES[colorMode])
|
|
10
|
+
warnings.push(`Unknown color mode ${colorMode}.`); return { version: version, channels, height, width, depth, colorMode, colorModeName: MODES[colorMode] ?? 'Unknown', pixelCount, warnings }; }
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
export type DbfValue = string | number | boolean | null;
|
|
2
|
+
export interface DbfField {
|
|
3
|
+
name: string;
|
|
4
|
+
/** dBASE type code: C(haracter), N(umeric), F(loat), L(ogical), D(ate)… */
|
|
5
|
+
type: string;
|
|
6
|
+
length: number;
|
|
7
|
+
decimals: number;
|
|
8
|
+
}
|
|
9
|
+
export interface DbfTable {
|
|
10
|
+
fields: DbfField[];
|
|
11
|
+
records: Array<Record<string, DbfValue>>;
|
|
12
|
+
recordCount: number;
|
|
13
|
+
warnings: string[];
|
|
14
|
+
}
|
|
15
|
+
export interface DbfParseOptions {
|
|
16
|
+
maxBytes?: number;
|
|
17
|
+
maxRecords?: number;
|
|
18
|
+
/** Text encoding of character fields. DBF predates Unicode; utf-8 with
|
|
19
|
+
* latin-1 fallback covers the practical corpus. */
|
|
20
|
+
encoding?: string;
|
|
21
|
+
signal?: AbortSignal;
|
|
22
|
+
}
|
|
23
|
+
export declare function parseDbf(data: Uint8Array, options?: DbfParseOptions): DbfTable;
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
// dBASE (.dbf) attribute table parser — the sidecar that carries per-feature
|
|
2
|
+
// attributes for an ESRI Shapefile. Record order matches .shp record order.
|
|
3
|
+
const FIELD_DESCRIPTOR_SIZE = 32;
|
|
4
|
+
const HEADER_TERMINATOR = 0x0d;
|
|
5
|
+
const DELETED_FLAG = 0x2a;
|
|
6
|
+
export function parseDbf(data, options = {}) {
|
|
7
|
+
const maxBytes = options.maxBytes ?? 64 * 1024 * 1024;
|
|
8
|
+
const maxRecords = options.maxRecords ?? 10_000;
|
|
9
|
+
if (options.signal?.aborted)
|
|
10
|
+
throw new Error('aborted');
|
|
11
|
+
if (data.byteLength > maxBytes)
|
|
12
|
+
throw new Error(`DBF exceeds the ${maxBytes.toLocaleString()} byte limit.`);
|
|
13
|
+
if (data.byteLength < 32)
|
|
14
|
+
throw new Error('DBF header is truncated.');
|
|
15
|
+
const view = new DataView(data.buffer, data.byteOffset, data.byteLength);
|
|
16
|
+
const declaredRecords = view.getUint32(4, true);
|
|
17
|
+
const headerSize = view.getUint16(8, true);
|
|
18
|
+
const recordSize = view.getUint16(10, true);
|
|
19
|
+
if (headerSize < 33 || headerSize > data.byteLength)
|
|
20
|
+
throw new Error('DBF header size is invalid.');
|
|
21
|
+
if (recordSize < 1)
|
|
22
|
+
throw new Error('DBF record size is invalid.');
|
|
23
|
+
const decoder = createDecoder(options.encoding);
|
|
24
|
+
const warnings = [];
|
|
25
|
+
const fields = [];
|
|
26
|
+
let cursor = 32;
|
|
27
|
+
while (cursor + FIELD_DESCRIPTOR_SIZE <= headerSize && data[cursor] !== HEADER_TERMINATOR) {
|
|
28
|
+
const nameBytes = data.subarray(cursor, cursor + 11);
|
|
29
|
+
const nul = nameBytes.indexOf(0);
|
|
30
|
+
const name = decoder.decode(nameBytes.subarray(0, nul === -1 ? 11 : nul)).trim();
|
|
31
|
+
fields.push({
|
|
32
|
+
name: name || `FIELD_${fields.length}`,
|
|
33
|
+
type: String.fromCharCode(data[cursor + 11]),
|
|
34
|
+
length: data[cursor + 16],
|
|
35
|
+
decimals: data[cursor + 17]
|
|
36
|
+
});
|
|
37
|
+
cursor += FIELD_DESCRIPTOR_SIZE;
|
|
38
|
+
}
|
|
39
|
+
if (fields.length === 0)
|
|
40
|
+
throw new Error('DBF contains no field descriptors.');
|
|
41
|
+
const fieldsSize = fields.reduce((sum, field) => sum + field.length, 0);
|
|
42
|
+
if (fieldsSize + 1 > recordSize)
|
|
43
|
+
warnings.push('DBF field lengths exceed the declared record size.');
|
|
44
|
+
const records = [];
|
|
45
|
+
let offset = headerSize;
|
|
46
|
+
let truncated = false;
|
|
47
|
+
while (offset + recordSize <= data.byteLength && records.length < maxRecords) {
|
|
48
|
+
if (options.signal?.aborted)
|
|
49
|
+
throw new Error('aborted');
|
|
50
|
+
if (data[offset] === 0x1a)
|
|
51
|
+
break; // EOF marker
|
|
52
|
+
const deleted = data[offset] === DELETED_FLAG;
|
|
53
|
+
if (!deleted) {
|
|
54
|
+
const record = {};
|
|
55
|
+
let at = offset + 1;
|
|
56
|
+
for (const field of fields) {
|
|
57
|
+
if (at + field.length > data.byteLength) {
|
|
58
|
+
truncated = true;
|
|
59
|
+
break;
|
|
60
|
+
}
|
|
61
|
+
record[field.name] = decodeValue(decoder.decode(data.subarray(at, at + field.length)), field);
|
|
62
|
+
at += field.length;
|
|
63
|
+
}
|
|
64
|
+
if (truncated)
|
|
65
|
+
break;
|
|
66
|
+
records.push(record);
|
|
67
|
+
}
|
|
68
|
+
offset += recordSize;
|
|
69
|
+
}
|
|
70
|
+
if (truncated)
|
|
71
|
+
warnings.push('DBF parsing stopped at a truncated record.');
|
|
72
|
+
if (declaredRecords > maxRecords && records.length >= maxRecords) {
|
|
73
|
+
warnings.push(`Attribute preview is limited to ${maxRecords.toLocaleString()} of ${declaredRecords.toLocaleString()} records.`);
|
|
74
|
+
}
|
|
75
|
+
else if (records.length < declaredRecords && !truncated) {
|
|
76
|
+
warnings.push(`DBF declares ${declaredRecords.toLocaleString()} records; ${records.length.toLocaleString()} were readable.`);
|
|
77
|
+
}
|
|
78
|
+
return { fields, records, recordCount: declaredRecords, warnings };
|
|
79
|
+
}
|
|
80
|
+
function decodeValue(raw, field) {
|
|
81
|
+
const text = raw.replace(/\0/g, '').trim();
|
|
82
|
+
switch (field.type) {
|
|
83
|
+
case 'N':
|
|
84
|
+
case 'F': {
|
|
85
|
+
if (!text)
|
|
86
|
+
return null;
|
|
87
|
+
const value = Number(text);
|
|
88
|
+
return Number.isFinite(value) ? value : null;
|
|
89
|
+
}
|
|
90
|
+
case 'L':
|
|
91
|
+
if (/^[YyTt]$/.test(text))
|
|
92
|
+
return true;
|
|
93
|
+
if (/^[NnFf]$/.test(text))
|
|
94
|
+
return false;
|
|
95
|
+
return null;
|
|
96
|
+
case 'D':
|
|
97
|
+
return /^\d{8}$/.test(text) ? `${text.slice(0, 4)}-${text.slice(4, 6)}-${text.slice(6, 8)}` : (text || null);
|
|
98
|
+
default:
|
|
99
|
+
return text;
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function createDecoder(encoding) {
|
|
103
|
+
for (const candidate of [encoding, 'utf-8', 'latin1']) {
|
|
104
|
+
if (!candidate)
|
|
105
|
+
continue;
|
|
106
|
+
try {
|
|
107
|
+
return new TextDecoder(candidate);
|
|
108
|
+
}
|
|
109
|
+
catch { /* try next */ }
|
|
110
|
+
}
|
|
111
|
+
return new TextDecoder();
|
|
112
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
export type ShpPosition = [number, number];
|
|
2
|
+
export type ShpGeometry = {
|
|
3
|
+
type: 'Point';
|
|
4
|
+
coordinates: ShpPosition;
|
|
5
|
+
} | {
|
|
6
|
+
type: 'MultiPoint';
|
|
7
|
+
coordinates: ShpPosition[];
|
|
8
|
+
} | {
|
|
9
|
+
type: 'LineString';
|
|
10
|
+
coordinates: ShpPosition[];
|
|
11
|
+
} |
|
|
12
|
+
/** First ring is the outer boundary; remaining rings are holes. */
|
|
13
|
+
{
|
|
14
|
+
type: 'Polygon';
|
|
15
|
+
coordinates: ShpPosition[][];
|
|
16
|
+
} | {
|
|
17
|
+
type: 'MultiLineString';
|
|
18
|
+
coordinates: ShpPosition[][];
|
|
19
|
+
} |
|
|
20
|
+
/** Each polygon contains an outer ring followed by zero or more holes. */
|
|
21
|
+
{
|
|
22
|
+
type: 'MultiPolygon';
|
|
23
|
+
coordinates: ShpPosition[][][];
|
|
24
|
+
};
|
|
25
|
+
export interface ShapefileFeature {
|
|
26
|
+
id: number;
|
|
27
|
+
geometry: ShpGeometry | null;
|
|
28
|
+
}
|
|
29
|
+
export interface ShapefileModel {
|
|
30
|
+
shapeType: number;
|
|
31
|
+
shapeTypeName: string;
|
|
32
|
+
fileLengthBytes: number;
|
|
33
|
+
bbox: [number, number, number, number] | null;
|
|
34
|
+
features: ShapefileFeature[];
|
|
35
|
+
vertexCount: number;
|
|
36
|
+
warnings: string[];
|
|
37
|
+
}
|
|
38
|
+
export interface ShapefileParseOptions {
|
|
39
|
+
maxBytes?: number;
|
|
40
|
+
maxFeatures?: number;
|
|
41
|
+
maxVertices?: number;
|
|
42
|
+
signal?: AbortSignal;
|
|
43
|
+
}
|
|
44
|
+
export declare function parseShapefile(data: Uint8Array, options?: ShapefileParseOptions): ShapefileModel;
|