@cj-tech-master/excelts 9.4.2 → 9.5.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/dist/browser/index.browser.d.ts +8 -5
- package/dist/browser/index.browser.js +19 -1
- package/dist/browser/index.d.ts +4 -2
- package/dist/browser/index.js +9 -1
- package/dist/browser/modules/excel/chart/cache-populator.d.ts +49 -0
- package/dist/browser/modules/excel/chart/cache-populator.js +1171 -0
- package/dist/browser/modules/excel/chart/chart-api.d.ts +92 -0
- package/dist/browser/modules/excel/chart/chart-api.js +364 -0
- package/dist/browser/modules/excel/chart/chart-builder.d.ts +48 -0
- package/dist/browser/modules/excel/chart/chart-builder.js +2432 -0
- package/dist/browser/modules/excel/chart/chart-ex-builder.d.ts +36 -0
- package/dist/browser/modules/excel/chart/chart-ex-builder.js +903 -0
- package/dist/browser/modules/excel/chart/chart-ex-parser.d.ts +8 -0
- package/dist/browser/modules/excel/chart/chart-ex-parser.js +1205 -0
- package/dist/browser/modules/excel/chart/chart-ex-renderer.d.ts +187 -0
- package/dist/browser/modules/excel/chart/chart-ex-renderer.js +5352 -0
- package/dist/browser/modules/excel/chart/chart-ex-types.d.ts +531 -0
- package/dist/browser/modules/excel/chart/chart-ex-types.js +11 -0
- package/dist/browser/modules/excel/chart/chart-images.d.ts +78 -0
- package/dist/browser/modules/excel/chart/chart-images.js +363 -0
- package/dist/browser/modules/excel/chart/chart-presets.d.ts +392 -0
- package/dist/browser/modules/excel/chart/chart-presets.js +179 -0
- package/dist/browser/modules/excel/chart/chart-renderer.d.ts +550 -0
- package/dist/browser/modules/excel/chart/chart-renderer.js +6440 -0
- package/dist/browser/modules/excel/chart/chart-sidecar.d.ts +21 -0
- package/dist/browser/modules/excel/chart/chart-sidecar.js +427 -0
- package/dist/browser/modules/excel/chart/chart-utils.d.ts +306 -0
- package/dist/browser/modules/excel/chart/chart-utils.js +821 -0
- package/dist/browser/modules/excel/chart/chart.d.ts +504 -0
- package/dist/browser/modules/excel/chart/chart.js +1320 -0
- package/dist/browser/modules/excel/chart/glyph-rasterizer.d.ts +62 -0
- package/dist/browser/modules/excel/chart/glyph-rasterizer.js +658 -0
- package/dist/browser/modules/excel/chart/index.d.ts +54 -0
- package/dist/browser/modules/excel/chart/index.js +46 -0
- package/dist/browser/modules/excel/chart/install.d.ts +44 -0
- package/dist/browser/modules/excel/chart/install.js +91 -0
- package/dist/browser/modules/excel/chart/shape-properties.d.ts +156 -0
- package/dist/browser/modules/excel/chart/shape-properties.js +1557 -0
- package/dist/browser/modules/excel/chart/stroke-font.d.ts +36 -0
- package/dist/browser/modules/excel/chart/stroke-font.js +1556 -0
- package/dist/browser/modules/excel/chart/topojson.d.ts +98 -0
- package/dist/browser/modules/excel/chart/topojson.js +236 -0
- package/dist/browser/modules/excel/chart/types.d.ts +2559 -0
- package/dist/browser/modules/excel/chart/types.js +8 -0
- package/dist/browser/modules/excel/chart-host-registry.d.ts +157 -0
- package/dist/browser/modules/excel/chart-host-registry.js +90 -0
- package/dist/browser/modules/excel/chartsheet.d.ts +102 -0
- package/dist/browser/modules/excel/chartsheet.js +196 -0
- package/dist/browser/modules/excel/defined-names.d.ts +35 -0
- package/dist/browser/modules/excel/defined-names.js +44 -4
- package/dist/browser/modules/excel/errors.d.ts +6 -0
- package/dist/browser/modules/excel/errors.js +9 -0
- package/dist/browser/modules/excel/form-control.d.ts +6 -0
- package/dist/browser/modules/excel/form-control.js +17 -0
- package/dist/browser/modules/excel/image.js +12 -2
- package/dist/browser/modules/excel/pivot-chart.d.ts +7 -0
- package/dist/browser/modules/excel/pivot-chart.js +53 -0
- package/dist/browser/modules/excel/pivot-table.d.ts +55 -0
- package/dist/browser/modules/excel/pivot-table.js +35 -0
- package/dist/browser/modules/excel/range.js +5 -1
- package/dist/browser/modules/excel/sparkline/index.d.ts +7 -0
- package/dist/browser/modules/excel/sparkline/index.js +7 -0
- package/dist/browser/modules/excel/sparkline/sparkline.d.ts +206 -0
- package/dist/browser/modules/excel/sparkline/sparkline.js +750 -0
- package/dist/browser/modules/excel/stream/worksheet-writer.js +3 -2
- package/dist/browser/modules/excel/table.js +42 -6
- package/dist/browser/modules/excel/types.d.ts +72 -0
- package/dist/browser/modules/excel/utils/address.d.ts +18 -0
- package/dist/browser/modules/excel/utils/address.js +28 -0
- package/dist/browser/modules/excel/utils/drawing-utils.js +11 -6
- package/dist/browser/modules/excel/utils/guid.d.ts +15 -0
- package/dist/browser/modules/excel/utils/guid.js +35 -0
- package/dist/browser/modules/excel/utils/ooxml-paths.d.ts +74 -0
- package/dist/browser/modules/excel/utils/ooxml-paths.js +206 -9
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chart-sidecar.d.ts +35 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +101 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chart.d.ts +32 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chart.js +2125 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chartsheet.d.ts +9 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-chartsheet.js +26 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-content-types.d.ts +16 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-content-types.js +181 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-drawing.d.ts +34 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-drawing.js +267 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-pivot.d.ts +14 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-pivot.js +104 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-relationships.d.ts +18 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-relationships.js +184 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-structure.d.ts +21 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-structure.js +56 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-styles.d.ts +15 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-styles.js +89 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-table.d.ts +31 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-table.js +177 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-workbook.d.ts +19 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-workbook.js +163 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-worksheet.d.ts +25 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/check-worksheet.js +569 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/context.d.ts +85 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/context.js +191 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/index.d.ts +31 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/index.js +102 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/path-utils.d.ts +67 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/path-utils.js +156 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/reporter.d.ts +41 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/reporter.js +61 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/types.d.ts +109 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/types.js +12 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/xml-utils.d.ts +38 -0
- package/dist/browser/modules/excel/utils/ooxml-validator/xml-utils.js +100 -0
- package/dist/browser/modules/excel/workbook.browser.d.ts +248 -30
- package/dist/browser/modules/excel/workbook.browser.js +966 -31
- package/dist/browser/modules/excel/workbook.d.ts +43 -0
- package/dist/browser/modules/excel/workbook.js +48 -0
- package/dist/browser/modules/excel/worksheet.d.ts +157 -3
- package/dist/browser/modules/excel/worksheet.js +394 -35
- package/dist/browser/modules/excel/xlsx/rel-type.d.ts +40 -0
- package/dist/browser/modules/excel/xlsx/rel-type.js +41 -1
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
- package/dist/browser/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
- package/dist/browser/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
- package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.d.ts +353 -0
- package/dist/browser/modules/excel/xlsx/xform/chart/chart-space-xform.js +6000 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/threaded-comments-xform.d.ts +60 -0
- package/dist/browser/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +213 -0
- package/dist/browser/modules/excel/xlsx/xform/core/content-types-xform.js +150 -11
- package/dist/browser/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.d.ts +30 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
- package/dist/browser/modules/excel/xlsx/xform/drawing/graphic-frame-xform.d.ts +54 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +225 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +3 -1
- package/dist/browser/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +46 -0
- package/dist/browser/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +13 -2
- package/dist/browser/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
- package/dist/browser/modules/excel/xlsx/xform/sheet/chartsheet-xform.d.ts +185 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +441 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -0
- package/dist/browser/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
- package/dist/browser/modules/excel/xlsx/xform/sheet/worksheet-xform.js +196 -20
- package/dist/browser/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
- package/dist/browser/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
- package/dist/browser/modules/excel/xlsx/xform/xsd-values.d.ts +63 -0
- package/dist/browser/modules/excel/xlsx/xform/xsd-values.js +101 -0
- package/dist/browser/modules/excel/xlsx/xlsx.browser.d.ts +115 -21
- package/dist/browser/modules/excel/xlsx/xlsx.browser.js +4422 -78
- package/dist/browser/modules/pdf/builder/document-builder.d.ts +74 -0
- package/dist/browser/modules/pdf/builder/document-builder.js +507 -2
- package/dist/browser/modules/pdf/builder/pdf-editor.js +48 -3
- package/dist/browser/modules/pdf/excel-bridge.d.ts +69 -0
- package/dist/browser/modules/pdf/excel-bridge.js +683 -12
- package/dist/browser/modules/pdf/font/font-manager.d.ts +25 -0
- package/dist/browser/modules/pdf/font/font-manager.js +39 -0
- package/dist/browser/modules/pdf/index.d.ts +5 -2
- package/dist/browser/modules/pdf/index.js +3 -1
- package/dist/browser/modules/pdf/render/chart-surface.d.ts +33 -0
- package/dist/browser/modules/pdf/render/chart-surface.js +200 -0
- package/dist/browser/modules/pdf/render/layout-engine.d.ts +22 -1
- package/dist/browser/modules/pdf/render/layout-engine.js +436 -56
- package/dist/browser/modules/pdf/render/page-renderer.js +169 -28
- package/dist/browser/modules/pdf/render/pdf-exporter.js +117 -7
- package/dist/browser/modules/pdf/types.d.ts +227 -23
- package/dist/browser/modules/pdf/types.js +4 -0
- package/dist/browser/modules/pdf/word-bridge.d.ts +47 -0
- package/dist/browser/modules/pdf/word-bridge.js +304 -0
- package/dist/browser/modules/word/constants.d.ts +179 -0
- package/dist/browser/modules/word/constants.js +231 -0
- package/dist/browser/modules/word/content-types.d.ts +27 -0
- package/dist/browser/modules/word/content-types.js +53 -0
- package/dist/browser/modules/word/digital-signatures.d.ts +87 -0
- package/dist/browser/modules/word/digital-signatures.js +134 -0
- package/dist/browser/modules/word/document.d.ts +728 -0
- package/dist/browser/modules/word/document.js +1795 -0
- package/dist/browser/modules/word/docx-packager.d.ts +14 -0
- package/dist/browser/modules/word/docx-packager.js +822 -0
- package/dist/browser/modules/word/docx-reader.d.ts +11 -0
- package/dist/browser/modules/word/docx-reader.js +4929 -0
- package/dist/browser/modules/word/encryption.d.ts +102 -0
- package/dist/browser/modules/word/encryption.js +274 -0
- package/dist/browser/modules/word/errors.d.ts +49 -0
- package/dist/browser/modules/word/errors.js +68 -0
- package/dist/browser/modules/word/font-obfuscation.d.ts +31 -0
- package/dist/browser/modules/word/font-obfuscation.js +83 -0
- package/dist/browser/modules/word/html-renderer.d.ts +38 -0
- package/dist/browser/modules/word/html-renderer.js +782 -0
- package/dist/browser/modules/word/index.base.d.ts +19 -0
- package/dist/browser/modules/word/index.base.js +51 -0
- package/dist/browser/modules/word/index.browser.d.ts +4 -0
- package/dist/browser/modules/word/index.browser.js +4 -0
- package/dist/browser/modules/word/index.d.ts +4 -0
- package/dist/browser/modules/word/index.js +4 -0
- package/dist/browser/modules/word/internal-utils.d.ts +23 -0
- package/dist/browser/modules/word/internal-utils.js +54 -0
- package/dist/browser/modules/word/relationships.d.ts +31 -0
- package/dist/browser/modules/word/relationships.js +56 -0
- package/dist/browser/modules/word/types.d.ts +2325 -0
- package/dist/browser/modules/word/types.js +10 -0
- package/dist/browser/modules/word/units.d.ts +49 -0
- package/dist/browser/modules/word/units.js +111 -0
- package/dist/browser/modules/word/writers/chart-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/chart-writer.js +385 -0
- package/dist/browser/modules/word/writers/checkbox-writer.d.ts +9 -0
- package/dist/browser/modules/word/writers/checkbox-writer.js +42 -0
- package/dist/browser/modules/word/writers/comment-writer.d.ts +15 -0
- package/dist/browser/modules/word/writers/comment-writer.js +70 -0
- package/dist/browser/modules/word/writers/document-writer.d.ts +16 -0
- package/dist/browser/modules/word/writers/document-writer.js +461 -0
- package/dist/browser/modules/word/writers/footnote-writer.d.ts +11 -0
- package/dist/browser/modules/word/writers/footnote-writer.js +72 -0
- package/dist/browser/modules/word/writers/header-footer-writer.d.ts +13 -0
- package/dist/browser/modules/word/writers/header-footer-writer.js +129 -0
- package/dist/browser/modules/word/writers/image-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/image-writer.js +185 -0
- package/dist/browser/modules/word/writers/math-writer.d.ts +9 -0
- package/dist/browser/modules/word/writers/math-writer.js +428 -0
- package/dist/browser/modules/word/writers/numbering-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/numbering-writer.js +125 -0
- package/dist/browser/modules/word/writers/paragraph-writer.d.ts +13 -0
- package/dist/browser/modules/word/writers/paragraph-writer.js +516 -0
- package/dist/browser/modules/word/writers/parts-writer.d.ts +26 -0
- package/dist/browser/modules/word/writers/parts-writer.js +660 -0
- package/dist/browser/modules/word/writers/run-writer.d.ts +15 -0
- package/dist/browser/modules/word/writers/run-writer.js +649 -0
- package/dist/browser/modules/word/writers/section-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/section-writer.js +238 -0
- package/dist/browser/modules/word/writers/styles-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/styles-writer.js +242 -0
- package/dist/browser/modules/word/writers/table-writer.d.ts +10 -0
- package/dist/browser/modules/word/writers/table-writer.js +503 -0
- package/dist/browser/modules/word/writers/textbox-writer.d.ts +9 -0
- package/dist/browser/modules/word/writers/textbox-writer.js +53 -0
- package/dist/browser/modules/word/writers/toc-writer.d.ts +9 -0
- package/dist/browser/modules/word/writers/toc-writer.js +79 -0
- package/dist/browser/modules/xml/encode.d.ts +56 -7
- package/dist/browser/modules/xml/encode.js +157 -11
- package/dist/cjs/index.js +13 -2
- package/dist/cjs/modules/excel/chart/cache-populator.js +1178 -0
- package/dist/cjs/modules/excel/chart/chart-api.js +371 -0
- package/dist/cjs/modules/excel/chart/chart-builder.js +2440 -0
- package/dist/cjs/modules/excel/chart/chart-ex-builder.js +907 -0
- package/dist/cjs/modules/excel/chart/chart-ex-parser.js +1208 -0
- package/dist/cjs/modules/excel/chart/chart-ex-renderer.js +5364 -0
- package/dist/cjs/modules/excel/chart/chart-ex-types.js +12 -0
- package/dist/cjs/modules/excel/chart/chart-images.js +366 -0
- package/dist/cjs/modules/excel/chart/chart-presets.js +184 -0
- package/dist/cjs/modules/excel/chart/chart-renderer.js +6450 -0
- package/dist/cjs/modules/excel/chart/chart-sidecar.js +433 -0
- package/dist/cjs/modules/excel/chart/chart-utils.js +845 -0
- package/dist/cjs/modules/excel/chart/chart.js +1324 -0
- package/dist/cjs/modules/excel/chart/glyph-rasterizer.js +664 -0
- package/dist/cjs/modules/excel/chart/index.js +101 -0
- package/dist/cjs/modules/excel/chart/install.js +95 -0
- package/dist/cjs/modules/excel/chart/shape-properties.js +1577 -0
- package/dist/cjs/modules/excel/chart/stroke-font.js +1559 -0
- package/dist/cjs/modules/excel/chart/topojson.js +239 -0
- package/dist/cjs/modules/excel/chart/types.js +9 -0
- package/dist/cjs/modules/excel/chart-host-registry.js +96 -0
- package/dist/cjs/modules/excel/chartsheet.js +199 -0
- package/dist/cjs/modules/excel/defined-names.js +44 -4
- package/dist/cjs/modules/excel/errors.js +11 -1
- package/dist/cjs/modules/excel/form-control.js +17 -0
- package/dist/cjs/modules/excel/image.js +12 -2
- package/dist/cjs/modules/excel/pivot-chart.js +56 -0
- package/dist/cjs/modules/excel/pivot-table.js +35 -0
- package/dist/cjs/modules/excel/range.js +5 -1
- package/dist/cjs/modules/excel/sparkline/index.js +23 -0
- package/dist/cjs/modules/excel/sparkline/sparkline.js +756 -0
- package/dist/cjs/modules/excel/stream/worksheet-writer.js +3 -2
- package/dist/cjs/modules/excel/table.js +42 -6
- package/dist/cjs/modules/excel/utils/address.js +29 -0
- package/dist/cjs/modules/excel/utils/drawing-utils.js +11 -6
- package/dist/cjs/modules/excel/utils/guid.js +38 -0
- package/dist/cjs/modules/excel/utils/ooxml-paths.js +246 -9
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +103 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-chart.js +2128 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-chartsheet.js +29 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-content-types.js +184 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-drawing.js +270 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-pivot.js +107 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-relationships.js +188 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-structure.js +60 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-styles.js +92 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-table.js +180 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-workbook.js +166 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/check-worksheet.js +572 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/context.js +196 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/index.js +105 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/path-utils.js +168 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/reporter.js +66 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/types.js +13 -0
- package/dist/cjs/modules/excel/utils/ooxml-validator/xml-utils.js +110 -0
- package/dist/cjs/modules/excel/workbook.browser.js +973 -38
- package/dist/cjs/modules/excel/workbook.js +48 -0
- package/dist/cjs/modules/excel/worksheet.js +393 -34
- package/dist/cjs/modules/excel/xlsx/rel-type.js +41 -1
- package/dist/cjs/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
- package/dist/cjs/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
- package/dist/cjs/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
- package/dist/cjs/modules/excel/xlsx/xform/chart/chart-space-xform.js +6003 -0
- package/dist/cjs/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +219 -0
- package/dist/cjs/modules/excel/xlsx/xform/core/content-types-xform.js +149 -10
- package/dist/cjs/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
- package/dist/cjs/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
- package/dist/cjs/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +228 -0
- package/dist/cjs/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
- package/dist/cjs/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
- package/dist/cjs/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
- package/dist/cjs/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +444 -0
- package/dist/cjs/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
- package/dist/cjs/modules/excel/xlsx/xform/sheet/worksheet-xform.js +195 -19
- package/dist/cjs/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
- package/dist/cjs/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
- package/dist/cjs/modules/excel/xlsx/xform/xsd-values.js +106 -0
- package/dist/cjs/modules/excel/xlsx/xlsx.browser.js +4420 -76
- package/dist/cjs/modules/pdf/builder/document-builder.js +506 -1
- package/dist/cjs/modules/pdf/builder/pdf-editor.js +48 -3
- package/dist/cjs/modules/pdf/excel-bridge.js +684 -12
- package/dist/cjs/modules/pdf/font/font-manager.js +39 -0
- package/dist/cjs/modules/pdf/index.js +5 -1
- package/dist/cjs/modules/pdf/render/chart-surface.js +203 -0
- package/dist/cjs/modules/pdf/render/layout-engine.js +437 -56
- package/dist/cjs/modules/pdf/render/page-renderer.js +169 -28
- package/dist/cjs/modules/pdf/render/pdf-exporter.js +115 -5
- package/dist/cjs/modules/pdf/types.js +5 -0
- package/dist/cjs/modules/pdf/word-bridge.js +307 -0
- package/dist/cjs/modules/word/constants.js +234 -0
- package/dist/cjs/modules/word/content-types.js +57 -0
- package/dist/cjs/modules/word/digital-signatures.js +140 -0
- package/dist/cjs/modules/word/document.js +1909 -0
- package/dist/cjs/modules/word/docx-packager.js +825 -0
- package/dist/cjs/modules/word/docx-reader.js +4932 -0
- package/dist/cjs/modules/word/encryption.js +282 -0
- package/dist/cjs/modules/word/errors.js +88 -0
- package/dist/cjs/modules/word/font-obfuscation.js +88 -0
- package/dist/cjs/modules/word/html-renderer.js +785 -0
- package/dist/cjs/modules/word/index.base.js +199 -0
- package/dist/cjs/modules/word/index.browser.js +20 -0
- package/dist/cjs/modules/word/index.js +20 -0
- package/dist/cjs/modules/word/internal-utils.js +59 -0
- package/dist/cjs/modules/word/relationships.js +60 -0
- package/dist/cjs/modules/word/types.js +11 -0
- package/dist/cjs/modules/word/units.js +135 -0
- package/dist/cjs/modules/word/writers/chart-writer.js +388 -0
- package/dist/cjs/modules/word/writers/checkbox-writer.js +45 -0
- package/dist/cjs/modules/word/writers/comment-writer.js +74 -0
- package/dist/cjs/modules/word/writers/document-writer.js +465 -0
- package/dist/cjs/modules/word/writers/footnote-writer.js +76 -0
- package/dist/cjs/modules/word/writers/header-footer-writer.js +134 -0
- package/dist/cjs/modules/word/writers/image-writer.js +188 -0
- package/dist/cjs/modules/word/writers/math-writer.js +431 -0
- package/dist/cjs/modules/word/writers/numbering-writer.js +128 -0
- package/dist/cjs/modules/word/writers/paragraph-writer.js +521 -0
- package/dist/cjs/modules/word/writers/parts-writer.js +671 -0
- package/dist/cjs/modules/word/writers/run-writer.js +655 -0
- package/dist/cjs/modules/word/writers/section-writer.js +241 -0
- package/dist/cjs/modules/word/writers/styles-writer.js +245 -0
- package/dist/cjs/modules/word/writers/table-writer.js +506 -0
- package/dist/cjs/modules/word/writers/textbox-writer.js +56 -0
- package/dist/cjs/modules/word/writers/toc-writer.js +82 -0
- package/dist/cjs/modules/xml/encode.js +158 -11
- package/dist/esm/index.browser.js +20 -2
- package/dist/esm/index.js +9 -1
- package/dist/esm/modules/excel/chart/cache-populator.js +1171 -0
- package/dist/esm/modules/excel/chart/chart-api.js +364 -0
- package/dist/esm/modules/excel/chart/chart-builder.js +2432 -0
- package/dist/esm/modules/excel/chart/chart-ex-builder.js +903 -0
- package/dist/esm/modules/excel/chart/chart-ex-parser.js +1205 -0
- package/dist/esm/modules/excel/chart/chart-ex-renderer.js +5352 -0
- package/dist/esm/modules/excel/chart/chart-ex-types.js +11 -0
- package/dist/esm/modules/excel/chart/chart-images.js +363 -0
- package/dist/esm/modules/excel/chart/chart-presets.js +179 -0
- package/dist/esm/modules/excel/chart/chart-renderer.js +6440 -0
- package/dist/esm/modules/excel/chart/chart-sidecar.js +427 -0
- package/dist/esm/modules/excel/chart/chart-utils.js +821 -0
- package/dist/esm/modules/excel/chart/chart.js +1320 -0
- package/dist/esm/modules/excel/chart/glyph-rasterizer.js +658 -0
- package/dist/esm/modules/excel/chart/index.js +46 -0
- package/dist/esm/modules/excel/chart/install.js +91 -0
- package/dist/esm/modules/excel/chart/shape-properties.js +1557 -0
- package/dist/esm/modules/excel/chart/stroke-font.js +1556 -0
- package/dist/esm/modules/excel/chart/topojson.js +236 -0
- package/dist/esm/modules/excel/chart/types.js +8 -0
- package/dist/esm/modules/excel/chart-host-registry.js +90 -0
- package/dist/esm/modules/excel/chartsheet.js +196 -0
- package/dist/esm/modules/excel/defined-names.js +44 -4
- package/dist/esm/modules/excel/errors.js +9 -0
- package/dist/esm/modules/excel/form-control.js +17 -0
- package/dist/esm/modules/excel/image.js +12 -2
- package/dist/esm/modules/excel/pivot-chart.js +53 -0
- package/dist/esm/modules/excel/pivot-table.js +35 -0
- package/dist/esm/modules/excel/range.js +5 -1
- package/dist/esm/modules/excel/sparkline/index.js +7 -0
- package/dist/esm/modules/excel/sparkline/sparkline.js +750 -0
- package/dist/esm/modules/excel/stream/worksheet-writer.js +3 -2
- package/dist/esm/modules/excel/table.js +42 -6
- package/dist/esm/modules/excel/utils/address.js +28 -0
- package/dist/esm/modules/excel/utils/drawing-utils.js +11 -6
- package/dist/esm/modules/excel/utils/guid.js +35 -0
- package/dist/esm/modules/excel/utils/ooxml-paths.js +206 -9
- package/dist/esm/modules/excel/utils/ooxml-validator/check-chart-sidecar.js +101 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-chart.js +2125 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-chartsheet.js +26 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-content-types.js +181 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-drawing.js +267 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-pivot.js +104 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-relationships.js +184 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-structure.js +56 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-styles.js +89 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-table.js +177 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-workbook.js +163 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/check-worksheet.js +569 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/context.js +191 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/index.js +102 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/path-utils.js +156 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/reporter.js +61 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/types.js +12 -0
- package/dist/esm/modules/excel/utils/ooxml-validator/xml-utils.js +100 -0
- package/dist/esm/modules/excel/workbook.browser.js +969 -34
- package/dist/esm/modules/excel/workbook.js +48 -0
- package/dist/esm/modules/excel/worksheet.js +394 -35
- package/dist/esm/modules/excel/xlsx/rel-type.js +41 -1
- package/dist/esm/modules/excel/xlsx/xform/book/defined-name-xform.js +11 -2
- package/dist/esm/modules/excel/xlsx/xform/book/external-link-xform.js +12 -10
- package/dist/esm/modules/excel/xlsx/xform/book/workbook-xform.js +96 -22
- package/dist/esm/modules/excel/xlsx/xform/chart/chart-space-xform.js +6000 -0
- package/dist/esm/modules/excel/xlsx/xform/comment/threaded-comments-xform.js +213 -0
- package/dist/esm/modules/excel/xlsx/xform/core/content-types-xform.js +150 -11
- package/dist/esm/modules/excel/xlsx/xform/drawing/absolute-anchor-xform.js +20 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/base-cell-anchor-xform.js +1 -1
- package/dist/esm/modules/excel/xlsx/xform/drawing/drawing-xform.js +109 -5
- package/dist/esm/modules/excel/xlsx/xform/drawing/graphic-frame-xform.js +225 -0
- package/dist/esm/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.js +18 -3
- package/dist/esm/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.js +294 -12
- package/dist/esm/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.js +32 -6
- package/dist/esm/modules/excel/xlsx/xform/sheet/chartsheet-xform.js +441 -0
- package/dist/esm/modules/excel/xlsx/xform/sheet/ext-lst-xform.js +51 -2
- package/dist/esm/modules/excel/xlsx/xform/sheet/worksheet-xform.js +196 -20
- package/dist/esm/modules/excel/xlsx/xform/table/auto-filter-xform.js +16 -1
- package/dist/esm/modules/excel/xlsx/xform/table/table-column-xform.js +17 -2
- package/dist/esm/modules/excel/xlsx/xform/xsd-values.js +101 -0
- package/dist/esm/modules/excel/xlsx/xlsx.browser.js +4422 -78
- package/dist/esm/modules/pdf/builder/document-builder.js +507 -2
- package/dist/esm/modules/pdf/builder/pdf-editor.js +48 -3
- package/dist/esm/modules/pdf/excel-bridge.js +683 -12
- package/dist/esm/modules/pdf/font/font-manager.js +39 -0
- package/dist/esm/modules/pdf/index.js +3 -1
- package/dist/esm/modules/pdf/render/chart-surface.js +200 -0
- package/dist/esm/modules/pdf/render/layout-engine.js +436 -56
- package/dist/esm/modules/pdf/render/page-renderer.js +169 -28
- package/dist/esm/modules/pdf/render/pdf-exporter.js +117 -7
- package/dist/esm/modules/pdf/types.js +4 -0
- package/dist/esm/modules/pdf/word-bridge.js +304 -0
- package/dist/esm/modules/word/constants.js +231 -0
- package/dist/esm/modules/word/content-types.js +53 -0
- package/dist/esm/modules/word/digital-signatures.js +134 -0
- package/dist/esm/modules/word/document.js +1795 -0
- package/dist/esm/modules/word/docx-packager.js +822 -0
- package/dist/esm/modules/word/docx-reader.js +4929 -0
- package/dist/esm/modules/word/encryption.js +274 -0
- package/dist/esm/modules/word/errors.js +68 -0
- package/dist/esm/modules/word/font-obfuscation.js +83 -0
- package/dist/esm/modules/word/html-renderer.js +782 -0
- package/dist/esm/modules/word/index.base.js +51 -0
- package/dist/esm/modules/word/index.browser.js +4 -0
- package/dist/esm/modules/word/index.js +4 -0
- package/dist/esm/modules/word/internal-utils.js +54 -0
- package/dist/esm/modules/word/relationships.js +56 -0
- package/dist/esm/modules/word/types.js +10 -0
- package/dist/esm/modules/word/units.js +111 -0
- package/dist/esm/modules/word/writers/chart-writer.js +385 -0
- package/dist/esm/modules/word/writers/checkbox-writer.js +42 -0
- package/dist/esm/modules/word/writers/comment-writer.js +70 -0
- package/dist/esm/modules/word/writers/document-writer.js +461 -0
- package/dist/esm/modules/word/writers/footnote-writer.js +72 -0
- package/dist/esm/modules/word/writers/header-footer-writer.js +129 -0
- package/dist/esm/modules/word/writers/image-writer.js +185 -0
- package/dist/esm/modules/word/writers/math-writer.js +428 -0
- package/dist/esm/modules/word/writers/numbering-writer.js +125 -0
- package/dist/esm/modules/word/writers/paragraph-writer.js +516 -0
- package/dist/esm/modules/word/writers/parts-writer.js +660 -0
- package/dist/esm/modules/word/writers/run-writer.js +649 -0
- package/dist/esm/modules/word/writers/section-writer.js +238 -0
- package/dist/esm/modules/word/writers/styles-writer.js +242 -0
- package/dist/esm/modules/word/writers/table-writer.js +503 -0
- package/dist/esm/modules/word/writers/textbox-writer.js +53 -0
- package/dist/esm/modules/word/writers/toc-writer.js +79 -0
- package/dist/esm/modules/xml/encode.js +157 -11
- package/dist/iife/excelts.iife.js +11789 -687
- package/dist/iife/excelts.iife.js.map +1 -1
- package/dist/iife/excelts.iife.min.js +52 -44
- package/dist/types/index.browser.d.ts +8 -5
- package/dist/types/index.d.ts +4 -2
- package/dist/types/modules/excel/chart/cache-populator.d.ts +49 -0
- package/dist/types/modules/excel/chart/chart-api.d.ts +92 -0
- package/dist/types/modules/excel/chart/chart-builder.d.ts +48 -0
- package/dist/types/modules/excel/chart/chart-ex-builder.d.ts +36 -0
- package/dist/types/modules/excel/chart/chart-ex-parser.d.ts +8 -0
- package/dist/types/modules/excel/chart/chart-ex-renderer.d.ts +187 -0
- package/dist/types/modules/excel/chart/chart-ex-types.d.ts +531 -0
- package/dist/types/modules/excel/chart/chart-images.d.ts +78 -0
- package/dist/types/modules/excel/chart/chart-presets.d.ts +392 -0
- package/dist/types/modules/excel/chart/chart-renderer.d.ts +550 -0
- package/dist/types/modules/excel/chart/chart-sidecar.d.ts +21 -0
- package/dist/types/modules/excel/chart/chart-utils.d.ts +306 -0
- package/dist/types/modules/excel/chart/chart.d.ts +504 -0
- package/dist/types/modules/excel/chart/glyph-rasterizer.d.ts +62 -0
- package/dist/types/modules/excel/chart/index.d.ts +54 -0
- package/dist/types/modules/excel/chart/install.d.ts +44 -0
- package/dist/types/modules/excel/chart/shape-properties.d.ts +156 -0
- package/dist/types/modules/excel/chart/stroke-font.d.ts +36 -0
- package/dist/types/modules/excel/chart/topojson.d.ts +98 -0
- package/dist/types/modules/excel/chart/types.d.ts +2559 -0
- package/dist/types/modules/excel/chart-host-registry.d.ts +157 -0
- package/dist/types/modules/excel/chartsheet.d.ts +102 -0
- package/dist/types/modules/excel/defined-names.d.ts +35 -0
- package/dist/types/modules/excel/errors.d.ts +6 -0
- package/dist/types/modules/excel/form-control.d.ts +6 -0
- package/dist/types/modules/excel/pivot-chart.d.ts +7 -0
- package/dist/types/modules/excel/pivot-table.d.ts +55 -0
- package/dist/types/modules/excel/sparkline/index.d.ts +7 -0
- package/dist/types/modules/excel/sparkline/sparkline.d.ts +206 -0
- package/dist/types/modules/excel/types.d.ts +72 -0
- package/dist/types/modules/excel/utils/address.d.ts +18 -0
- package/dist/types/modules/excel/utils/guid.d.ts +15 -0
- package/dist/types/modules/excel/utils/ooxml-paths.d.ts +74 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-chart-sidecar.d.ts +35 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-chart.d.ts +32 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-chartsheet.d.ts +9 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-content-types.d.ts +16 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-drawing.d.ts +34 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-pivot.d.ts +14 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-relationships.d.ts +18 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-structure.d.ts +21 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-styles.d.ts +15 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-table.d.ts +31 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-workbook.d.ts +19 -0
- package/dist/types/modules/excel/utils/ooxml-validator/check-worksheet.d.ts +25 -0
- package/dist/types/modules/excel/utils/ooxml-validator/context.d.ts +85 -0
- package/dist/types/modules/excel/utils/ooxml-validator/index.d.ts +31 -0
- package/dist/types/modules/excel/utils/ooxml-validator/path-utils.d.ts +67 -0
- package/dist/types/modules/excel/utils/ooxml-validator/reporter.d.ts +41 -0
- package/dist/types/modules/excel/utils/ooxml-validator/types.d.ts +109 -0
- package/dist/types/modules/excel/utils/ooxml-validator/xml-utils.d.ts +38 -0
- package/dist/types/modules/excel/workbook.browser.d.ts +248 -30
- package/dist/types/modules/excel/workbook.d.ts +43 -0
- package/dist/types/modules/excel/worksheet.d.ts +157 -3
- package/dist/types/modules/excel/xlsx/rel-type.d.ts +40 -0
- package/dist/types/modules/excel/xlsx/xform/book/defined-name-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/chart/chart-space-xform.d.ts +353 -0
- package/dist/types/modules/excel/xlsx/xform/comment/threaded-comments-xform.d.ts +60 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/drawing-xform.d.ts +30 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/graphic-frame-xform.d.ts +54 -0
- package/dist/types/modules/excel/xlsx/xform/drawing/one-cell-anchor-xform.d.ts +3 -1
- package/dist/types/modules/excel/xlsx/xform/drawing/two-cell-anchor-xform.d.ts +46 -0
- package/dist/types/modules/excel/xlsx/xform/pivot-table/pivot-table-xform.d.ts +13 -2
- package/dist/types/modules/excel/xlsx/xform/sheet/chartsheet-xform.d.ts +185 -0
- package/dist/types/modules/excel/xlsx/xform/sheet/ext-lst-xform.d.ts +1 -0
- package/dist/types/modules/excel/xlsx/xform/xsd-values.d.ts +63 -0
- package/dist/types/modules/excel/xlsx/xlsx.browser.d.ts +115 -21
- package/dist/types/modules/pdf/builder/document-builder.d.ts +74 -0
- package/dist/types/modules/pdf/excel-bridge.d.ts +69 -0
- package/dist/types/modules/pdf/font/font-manager.d.ts +25 -0
- package/dist/types/modules/pdf/index.d.ts +5 -2
- package/dist/types/modules/pdf/render/chart-surface.d.ts +33 -0
- package/dist/types/modules/pdf/render/layout-engine.d.ts +22 -1
- package/dist/types/modules/pdf/types.d.ts +227 -23
- package/dist/types/modules/pdf/word-bridge.d.ts +47 -0
- package/dist/types/modules/word/constants.d.ts +179 -0
- package/dist/types/modules/word/content-types.d.ts +27 -0
- package/dist/types/modules/word/digital-signatures.d.ts +87 -0
- package/dist/types/modules/word/document.d.ts +728 -0
- package/dist/types/modules/word/docx-packager.d.ts +14 -0
- package/dist/types/modules/word/docx-reader.d.ts +11 -0
- package/dist/types/modules/word/encryption.d.ts +102 -0
- package/dist/types/modules/word/errors.d.ts +49 -0
- package/dist/types/modules/word/font-obfuscation.d.ts +31 -0
- package/dist/types/modules/word/html-renderer.d.ts +38 -0
- package/dist/types/modules/word/index.base.d.ts +19 -0
- package/dist/types/modules/word/index.browser.d.ts +4 -0
- package/dist/types/modules/word/index.d.ts +4 -0
- package/dist/types/modules/word/internal-utils.d.ts +23 -0
- package/dist/types/modules/word/relationships.d.ts +31 -0
- package/dist/types/modules/word/types.d.ts +2325 -0
- package/dist/types/modules/word/units.d.ts +49 -0
- package/dist/types/modules/word/writers/chart-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/checkbox-writer.d.ts +9 -0
- package/dist/types/modules/word/writers/comment-writer.d.ts +15 -0
- package/dist/types/modules/word/writers/document-writer.d.ts +16 -0
- package/dist/types/modules/word/writers/footnote-writer.d.ts +11 -0
- package/dist/types/modules/word/writers/header-footer-writer.d.ts +13 -0
- package/dist/types/modules/word/writers/image-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/math-writer.d.ts +9 -0
- package/dist/types/modules/word/writers/numbering-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/paragraph-writer.d.ts +13 -0
- package/dist/types/modules/word/writers/parts-writer.d.ts +26 -0
- package/dist/types/modules/word/writers/run-writer.d.ts +15 -0
- package/dist/types/modules/word/writers/section-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/styles-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/table-writer.d.ts +10 -0
- package/dist/types/modules/word/writers/textbox-writer.d.ts +9 -0
- package/dist/types/modules/word/writers/toc-writer.d.ts +9 -0
- package/dist/types/modules/xml/encode.d.ts +56 -7
- package/package.json +29 -11
- package/dist/browser/modules/excel/utils/ooxml-validator.d.ts +0 -48
- package/dist/browser/modules/excel/utils/ooxml-validator.js +0 -493
- package/dist/browser/modules/excel/utils/passthrough-manager.d.ts +0 -77
- package/dist/browser/modules/excel/utils/passthrough-manager.js +0 -129
- package/dist/cjs/modules/excel/utils/ooxml-validator.js +0 -499
- package/dist/cjs/modules/excel/utils/passthrough-manager.js +0 -133
- package/dist/esm/modules/excel/utils/ooxml-validator.js +0 -493
- package/dist/esm/modules/excel/utils/passthrough-manager.js +0 -129
- package/dist/types/modules/excel/utils/ooxml-validator.d.ts +0 -48
- package/dist/types/modules/excel/utils/passthrough-manager.d.ts +0 -77
|
@@ -0,0 +1,4932 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* DOCX Module - Reader / Parser
|
|
4
|
+
*
|
|
5
|
+
* Reads a DOCX ZIP file and parses it into a DocxDocument model.
|
|
6
|
+
* Uses the archive module for ZIP reading and XML module for parsing.
|
|
7
|
+
*/
|
|
8
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
9
|
+
exports.readDocx = readDocx;
|
|
10
|
+
const read_archive_1 = require("../archive/read-archive.js");
|
|
11
|
+
const dom_1 = require("../xml/dom.js");
|
|
12
|
+
const constants_1 = require("./constants");
|
|
13
|
+
const errors_1 = require("./errors");
|
|
14
|
+
// Module-level parsing context: set at the start of readDocx, used by parseParagraph etc.
|
|
15
|
+
let _parseRelMap = new Map();
|
|
16
|
+
// =============================================================================
|
|
17
|
+
// Helper Functions
|
|
18
|
+
// =============================================================================
|
|
19
|
+
function attrVal(el, name) {
|
|
20
|
+
// Try with w: prefix and without
|
|
21
|
+
return el.attributes[`w:${name}`] ?? el.attributes[name];
|
|
22
|
+
}
|
|
23
|
+
function attrInt(el, name) {
|
|
24
|
+
const v = attrVal(el, name);
|
|
25
|
+
if (v === undefined) {
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
const n = parseInt(v, 10);
|
|
29
|
+
return Number.isFinite(n) ? n : undefined;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Read an attribute as a strict boolean:
|
|
33
|
+
* "1"|"true" → true
|
|
34
|
+
* "0"|"false" → false
|
|
35
|
+
* otherwise → undefined
|
|
36
|
+
* Useful for attributes where default-false vs explicit-false matters.
|
|
37
|
+
*/
|
|
38
|
+
function _attrBool(el, name) {
|
|
39
|
+
const v = attrVal(el, name);
|
|
40
|
+
if (v === undefined) {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
if (v === "1" || v === "true") {
|
|
44
|
+
return true;
|
|
45
|
+
}
|
|
46
|
+
if (v === "0" || v === "false") {
|
|
47
|
+
return false;
|
|
48
|
+
}
|
|
49
|
+
return undefined;
|
|
50
|
+
}
|
|
51
|
+
function findChildNs(el, localName) {
|
|
52
|
+
// Match either w:localName or just localName
|
|
53
|
+
return (0, dom_1.findChild)(el, `w:${localName}`) ?? (0, dom_1.findChild)(el, localName);
|
|
54
|
+
}
|
|
55
|
+
function findChildrenNs(el, localName) {
|
|
56
|
+
const a = (0, dom_1.findChildren)(el, `w:${localName}`);
|
|
57
|
+
return a.length > 0 ? a : (0, dom_1.findChildren)(el, localName);
|
|
58
|
+
}
|
|
59
|
+
/** Check for a boolean toggle element (present = true, w:val="0" or "false" = false). */
|
|
60
|
+
function boolToggle(parent, name) {
|
|
61
|
+
const el = findChildNs(parent, name);
|
|
62
|
+
if (!el) {
|
|
63
|
+
return undefined;
|
|
64
|
+
}
|
|
65
|
+
const v = attrVal(el, "val");
|
|
66
|
+
if (v === "0" || v === "false") {
|
|
67
|
+
return false;
|
|
68
|
+
}
|
|
69
|
+
return true;
|
|
70
|
+
}
|
|
71
|
+
/** Escape special XML characters in text content. */
|
|
72
|
+
function escapeXml(s) {
|
|
73
|
+
return s
|
|
74
|
+
.replace(/&/g, "&")
|
|
75
|
+
.replace(/</g, "<")
|
|
76
|
+
.replace(/>/g, ">")
|
|
77
|
+
.replace(/"/g, """);
|
|
78
|
+
}
|
|
79
|
+
/** Serialize an XmlElement back to an XML string (for opaque preservation). */
|
|
80
|
+
function serializeElement(el) {
|
|
81
|
+
let s = `<${el.name}`;
|
|
82
|
+
for (const [k, v] of Object.entries(el.attributes)) {
|
|
83
|
+
s += ` ${k}="${escapeXml(v)}"`;
|
|
84
|
+
}
|
|
85
|
+
if (el.children.length === 0) {
|
|
86
|
+
return s + "/>";
|
|
87
|
+
}
|
|
88
|
+
s += ">";
|
|
89
|
+
for (const child of el.children) {
|
|
90
|
+
if (child.type === "element") {
|
|
91
|
+
s += serializeElement(child);
|
|
92
|
+
}
|
|
93
|
+
else if (child.type === "text") {
|
|
94
|
+
s += escapeXml(child.value);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
s += `</${el.name}>`;
|
|
98
|
+
return s;
|
|
99
|
+
}
|
|
100
|
+
/** Extract all r:xxx attribute values (relationship IDs) from an element tree. */
|
|
101
|
+
function collectRIds(el, out) {
|
|
102
|
+
for (const [k, v] of Object.entries(el.attributes)) {
|
|
103
|
+
if (k.startsWith("r:") || k === "r:id" || k === "r:embed" || k === "r:link") {
|
|
104
|
+
out.add(v);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
for (const child of el.children) {
|
|
108
|
+
if (child.type === "element") {
|
|
109
|
+
collectRIds(child, out);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Get the .rels path for a given part path. */
|
|
114
|
+
function getPartRelsPath(partPath) {
|
|
115
|
+
const lastSlash = partPath.lastIndexOf("/");
|
|
116
|
+
const dir = lastSlash >= 0 ? partPath.substring(0, lastSlash) : "";
|
|
117
|
+
const name = lastSlash >= 0 ? partPath.substring(lastSlash + 1) : partPath;
|
|
118
|
+
return dir ? `${dir}/_rels/${name}.rels` : `_rels/${name}.rels`;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Resolve a relationship target path to an absolute package-root path.
|
|
122
|
+
*
|
|
123
|
+
* - Leading "/" → package root absolute
|
|
124
|
+
* - "../" / "./" → resolved relative to the source part's directory
|
|
125
|
+
* - Plain paths → resolved relative to the source part's directory
|
|
126
|
+
*/
|
|
127
|
+
function resolvePartPath(sourcePart, target) {
|
|
128
|
+
if (!target) {
|
|
129
|
+
return "";
|
|
130
|
+
}
|
|
131
|
+
if (target.startsWith("/")) {
|
|
132
|
+
return target.slice(1);
|
|
133
|
+
}
|
|
134
|
+
const lastSlash = sourcePart.lastIndexOf("/");
|
|
135
|
+
const baseDir = lastSlash >= 0 ? sourcePart.substring(0, lastSlash).split("/") : [];
|
|
136
|
+
const segs = target.split("/");
|
|
137
|
+
for (const seg of segs) {
|
|
138
|
+
if (seg === "..") {
|
|
139
|
+
baseDir.pop();
|
|
140
|
+
}
|
|
141
|
+
else if (seg !== "." && seg !== "") {
|
|
142
|
+
baseDir.push(seg);
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
return baseDir.join("/");
|
|
146
|
+
}
|
|
147
|
+
/** Parse footnote/endnote properties element. */
|
|
148
|
+
function parseNoteProperties(el) {
|
|
149
|
+
const props = {};
|
|
150
|
+
const numFmtEl = findChildNs(el, "numFmt");
|
|
151
|
+
if (numFmtEl) {
|
|
152
|
+
props.numFmt = attrVal(numFmtEl, "val");
|
|
153
|
+
}
|
|
154
|
+
const numStartEl = findChildNs(el, "numStart");
|
|
155
|
+
if (numStartEl) {
|
|
156
|
+
props.numStart = attrInt(numStartEl, "val");
|
|
157
|
+
}
|
|
158
|
+
const numRestartEl = findChildNs(el, "numRestart");
|
|
159
|
+
if (numRestartEl) {
|
|
160
|
+
props.numRestart = attrVal(numRestartEl, "val");
|
|
161
|
+
}
|
|
162
|
+
const posEl = findChildNs(el, "pos");
|
|
163
|
+
if (posEl) {
|
|
164
|
+
props.position = attrVal(posEl, "val");
|
|
165
|
+
}
|
|
166
|
+
return Object.keys(props).length > 0 ? props : undefined;
|
|
167
|
+
}
|
|
168
|
+
/** Parse w:ffData element into a FormField. */
|
|
169
|
+
function parseFfData(el) {
|
|
170
|
+
const nameEl = findChildNs(el, "name");
|
|
171
|
+
const name = nameEl ? attrVal(nameEl, "val") : undefined;
|
|
172
|
+
const enabledEl = findChildNs(el, "enabled");
|
|
173
|
+
const enabled = enabledEl ? attrVal(enabledEl, "val") !== "0" : undefined;
|
|
174
|
+
const helpTextEl = findChildNs(el, "helpText");
|
|
175
|
+
const helpText = helpTextEl ? attrVal(helpTextEl, "val") : undefined;
|
|
176
|
+
const statusTextEl = findChildNs(el, "statusText");
|
|
177
|
+
const statusText = statusTextEl ? attrVal(statusTextEl, "val") : undefined;
|
|
178
|
+
// Text input
|
|
179
|
+
const textInputEl = findChildNs(el, "textInput");
|
|
180
|
+
if (textInputEl) {
|
|
181
|
+
const defEl = findChildNs(textInputEl, "default");
|
|
182
|
+
const maxLenEl = findChildNs(textInputEl, "maxLength");
|
|
183
|
+
const fmtEl = findChildNs(textInputEl, "format");
|
|
184
|
+
return {
|
|
185
|
+
type: "text",
|
|
186
|
+
name,
|
|
187
|
+
default: defEl ? attrVal(defEl, "val") : undefined,
|
|
188
|
+
maxLength: maxLenEl ? attrInt(maxLenEl, "val") : undefined,
|
|
189
|
+
format: fmtEl ? attrVal(fmtEl, "val") : undefined,
|
|
190
|
+
helpText,
|
|
191
|
+
statusText,
|
|
192
|
+
enabled
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
// CheckBox
|
|
196
|
+
const cbEl = findChildNs(el, "checkBox");
|
|
197
|
+
if (cbEl) {
|
|
198
|
+
const checkedEl = findChildNs(cbEl, "checked");
|
|
199
|
+
const defEl = findChildNs(cbEl, "default");
|
|
200
|
+
const sizeEl = findChildNs(cbEl, "size");
|
|
201
|
+
return {
|
|
202
|
+
type: "checkBox",
|
|
203
|
+
name,
|
|
204
|
+
checked: checkedEl ? attrVal(checkedEl, "val") !== "0" : undefined,
|
|
205
|
+
default: defEl ? attrVal(defEl, "val") !== "0" : undefined,
|
|
206
|
+
size: sizeEl ? attrInt(sizeEl, "val") : undefined
|
|
207
|
+
};
|
|
208
|
+
}
|
|
209
|
+
// Drop-down list
|
|
210
|
+
const ddlEl = findChildNs(el, "ddList");
|
|
211
|
+
if (ddlEl) {
|
|
212
|
+
const defEl = findChildNs(ddlEl, "default");
|
|
213
|
+
const entries = [];
|
|
214
|
+
for (const le of findChildrenNs(ddlEl, "listEntry")) {
|
|
215
|
+
const v = attrVal(le, "val");
|
|
216
|
+
if (v !== undefined) {
|
|
217
|
+
entries.push(v);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
return {
|
|
221
|
+
type: "dropDown",
|
|
222
|
+
name,
|
|
223
|
+
entries: entries.length > 0 ? entries : undefined,
|
|
224
|
+
default: defEl ? attrInt(defEl, "val") : undefined,
|
|
225
|
+
helpText,
|
|
226
|
+
statusText,
|
|
227
|
+
enabled
|
|
228
|
+
};
|
|
229
|
+
}
|
|
230
|
+
return undefined;
|
|
231
|
+
}
|
|
232
|
+
// =============================================================================
|
|
233
|
+
// Run Properties Parser
|
|
234
|
+
// =============================================================================
|
|
235
|
+
function parseRunProperties(rPrEl) {
|
|
236
|
+
const rPr = {};
|
|
237
|
+
const rStyleEl = findChildNs(rPrEl, "rStyle");
|
|
238
|
+
if (rStyleEl) {
|
|
239
|
+
rPr.style = attrVal(rStyleEl, "val");
|
|
240
|
+
}
|
|
241
|
+
const fontsEl = findChildNs(rPrEl, "rFonts");
|
|
242
|
+
if (fontsEl) {
|
|
243
|
+
const f = {};
|
|
244
|
+
const ascii = attrVal(fontsEl, "ascii");
|
|
245
|
+
const hAnsi = attrVal(fontsEl, "hAnsi");
|
|
246
|
+
const eastAsia = attrVal(fontsEl, "eastAsia");
|
|
247
|
+
const cs = attrVal(fontsEl, "cs");
|
|
248
|
+
const hint = attrVal(fontsEl, "hint");
|
|
249
|
+
if (ascii) {
|
|
250
|
+
f.ascii = ascii;
|
|
251
|
+
}
|
|
252
|
+
if (hAnsi) {
|
|
253
|
+
f.hAnsi = hAnsi;
|
|
254
|
+
}
|
|
255
|
+
if (eastAsia) {
|
|
256
|
+
f.eastAsia = eastAsia;
|
|
257
|
+
}
|
|
258
|
+
if (cs) {
|
|
259
|
+
f.cs = cs;
|
|
260
|
+
}
|
|
261
|
+
if (hint) {
|
|
262
|
+
f.hint = hint;
|
|
263
|
+
}
|
|
264
|
+
const asciiTheme = attrVal(fontsEl, "asciiTheme");
|
|
265
|
+
if (asciiTheme) {
|
|
266
|
+
f.asciiTheme = asciiTheme;
|
|
267
|
+
}
|
|
268
|
+
const hAnsiTheme = attrVal(fontsEl, "hAnsiTheme");
|
|
269
|
+
if (hAnsiTheme) {
|
|
270
|
+
f.hAnsiTheme = hAnsiTheme;
|
|
271
|
+
}
|
|
272
|
+
const eastAsiaTheme = attrVal(fontsEl, "eastAsiaTheme");
|
|
273
|
+
if (eastAsiaTheme) {
|
|
274
|
+
f.eastAsiaTheme = eastAsiaTheme;
|
|
275
|
+
}
|
|
276
|
+
const cstheme = attrVal(fontsEl, "cstheme");
|
|
277
|
+
if (cstheme) {
|
|
278
|
+
f.cstheme = cstheme;
|
|
279
|
+
}
|
|
280
|
+
rPr.font = f;
|
|
281
|
+
}
|
|
282
|
+
// Boolean toggles: true-only (element presence = true; absence = undefined)
|
|
283
|
+
// Format: [elementName, propertyKey]
|
|
284
|
+
const RUN_ONCE_TOGGLES = [
|
|
285
|
+
["strike", "strike"],
|
|
286
|
+
["dstrike", "doubleStrike"],
|
|
287
|
+
["caps", "caps"],
|
|
288
|
+
["smallCaps", "smallCaps"],
|
|
289
|
+
["vanish", "vanish"],
|
|
290
|
+
["emboss", "emboss"],
|
|
291
|
+
["imprint", "imprint"],
|
|
292
|
+
["noProof", "noProof"],
|
|
293
|
+
["specVanish", "specVanish"],
|
|
294
|
+
["outline", "outline"],
|
|
295
|
+
["shadow", "shadow"],
|
|
296
|
+
["cs", "complexScript"],
|
|
297
|
+
["oMath", "math"],
|
|
298
|
+
["webHidden", "webHidden"]
|
|
299
|
+
];
|
|
300
|
+
for (const [tag, key] of RUN_ONCE_TOGGLES) {
|
|
301
|
+
if (findChildNs(rPrEl, tag) && boolToggle(rPrEl, tag) !== false) {
|
|
302
|
+
rPr[key] = true;
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
// Boolean toggles: tri-state (can be explicitly true or false)
|
|
306
|
+
const RUN_TRISTATE_TOGGLES = [
|
|
307
|
+
["b", "bold"],
|
|
308
|
+
["bCs", "boldCs"],
|
|
309
|
+
["i", "italic"],
|
|
310
|
+
["iCs", "italicCs"],
|
|
311
|
+
["snapToGrid", "snapToGrid"],
|
|
312
|
+
["rtl", "rightToLeft"]
|
|
313
|
+
];
|
|
314
|
+
for (const [tag, key] of RUN_TRISTATE_TOGGLES) {
|
|
315
|
+
const v = boolToggle(rPrEl, tag);
|
|
316
|
+
if (v !== undefined) {
|
|
317
|
+
rPr[key] = v;
|
|
318
|
+
}
|
|
319
|
+
}
|
|
320
|
+
// fitText
|
|
321
|
+
const fitTextEl = findChildNs(rPrEl, "fitText");
|
|
322
|
+
if (fitTextEl) {
|
|
323
|
+
const val = attrInt(fitTextEl, "val");
|
|
324
|
+
if (val !== undefined) {
|
|
325
|
+
const fitText = { val };
|
|
326
|
+
const id = attrInt(fitTextEl, "id");
|
|
327
|
+
if (id !== undefined) {
|
|
328
|
+
fitText.id = id;
|
|
329
|
+
}
|
|
330
|
+
rPr.fitText = fitText;
|
|
331
|
+
}
|
|
332
|
+
}
|
|
333
|
+
const colorEl = findChildNs(rPrEl, "color");
|
|
334
|
+
if (colorEl) {
|
|
335
|
+
const val = attrVal(colorEl, "val");
|
|
336
|
+
const themeColor = attrVal(colorEl, "themeColor");
|
|
337
|
+
if (themeColor) {
|
|
338
|
+
const spec = { val, themeColor };
|
|
339
|
+
const themeTint = attrVal(colorEl, "themeTint");
|
|
340
|
+
const themeShade = attrVal(colorEl, "themeShade");
|
|
341
|
+
if (themeTint) {
|
|
342
|
+
spec.themeTint = themeTint;
|
|
343
|
+
}
|
|
344
|
+
if (themeShade) {
|
|
345
|
+
spec.themeShade = themeShade;
|
|
346
|
+
}
|
|
347
|
+
rPr.color = spec;
|
|
348
|
+
}
|
|
349
|
+
else {
|
|
350
|
+
rPr.color = val;
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
const szEl = findChildNs(rPrEl, "sz");
|
|
354
|
+
if (szEl) {
|
|
355
|
+
rPr.size = attrInt(szEl, "val");
|
|
356
|
+
}
|
|
357
|
+
const szCsEl = findChildNs(rPrEl, "szCs");
|
|
358
|
+
if (szCsEl) {
|
|
359
|
+
rPr.sizeCs = attrInt(szCsEl, "val");
|
|
360
|
+
}
|
|
361
|
+
const uEl = findChildNs(rPrEl, "u");
|
|
362
|
+
if (uEl) {
|
|
363
|
+
const uStyle = attrVal(uEl, "val") ?? "single";
|
|
364
|
+
const uColor = attrVal(uEl, "color");
|
|
365
|
+
if (uColor) {
|
|
366
|
+
rPr.underline = { style: uStyle, color: uColor };
|
|
367
|
+
}
|
|
368
|
+
else {
|
|
369
|
+
rPr.underline = uStyle;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
const highlightEl = findChildNs(rPrEl, "highlight");
|
|
373
|
+
if (highlightEl) {
|
|
374
|
+
rPr.highlight = attrVal(highlightEl, "val");
|
|
375
|
+
}
|
|
376
|
+
const vertAlignEl = findChildNs(rPrEl, "vertAlign");
|
|
377
|
+
if (vertAlignEl) {
|
|
378
|
+
rPr.vertAlign = attrVal(vertAlignEl, "val");
|
|
379
|
+
}
|
|
380
|
+
const spacingEl = findChildNs(rPrEl, "spacing");
|
|
381
|
+
if (spacingEl) {
|
|
382
|
+
rPr.spacing = attrInt(spacingEl, "val");
|
|
383
|
+
}
|
|
384
|
+
const shdEl = findChildNs(rPrEl, "shd");
|
|
385
|
+
if (shdEl) {
|
|
386
|
+
rPr.shading = parseShading(shdEl);
|
|
387
|
+
}
|
|
388
|
+
const langEl = findChildNs(rPrEl, "lang");
|
|
389
|
+
if (langEl) {
|
|
390
|
+
rPr.language = {
|
|
391
|
+
val: attrVal(langEl, "val"),
|
|
392
|
+
eastAsia: attrVal(langEl, "eastAsia"),
|
|
393
|
+
bidi: attrVal(langEl, "bidi")
|
|
394
|
+
};
|
|
395
|
+
}
|
|
396
|
+
// New valued properties
|
|
397
|
+
const kernEl = findChildNs(rPrEl, "kern");
|
|
398
|
+
if (kernEl) {
|
|
399
|
+
rPr.kern = attrInt(kernEl, "val");
|
|
400
|
+
}
|
|
401
|
+
const positionEl = findChildNs(rPrEl, "position");
|
|
402
|
+
if (positionEl) {
|
|
403
|
+
rPr.position = attrInt(positionEl, "val");
|
|
404
|
+
}
|
|
405
|
+
const wEl = findChildNs(rPrEl, "w");
|
|
406
|
+
if (wEl) {
|
|
407
|
+
rPr.scale = attrInt(wEl, "val");
|
|
408
|
+
}
|
|
409
|
+
const effectEl = findChildNs(rPrEl, "effect");
|
|
410
|
+
if (effectEl) {
|
|
411
|
+
rPr.effect = attrVal(effectEl, "val");
|
|
412
|
+
}
|
|
413
|
+
const emEl = findChildNs(rPrEl, "em");
|
|
414
|
+
if (emEl) {
|
|
415
|
+
rPr.emphasisMark = attrVal(emEl, "val");
|
|
416
|
+
}
|
|
417
|
+
const bdrEl = findChildNs(rPrEl, "bdr");
|
|
418
|
+
if (bdrEl) {
|
|
419
|
+
rPr.border = parseBorder(bdrEl);
|
|
420
|
+
}
|
|
421
|
+
// rPrChange (track changes for run properties)
|
|
422
|
+
const rPrChangeEl = findChildNs(rPrEl, "rPrChange");
|
|
423
|
+
if (rPrChangeEl) {
|
|
424
|
+
const rev = parseRevisionInfo(rPrChangeEl);
|
|
425
|
+
if (rev) {
|
|
426
|
+
const prevRPrEl = findChildNs(rPrChangeEl, "rPr");
|
|
427
|
+
const change = {
|
|
428
|
+
revision: rev,
|
|
429
|
+
previousProperties: prevRPrEl ? parseRunProperties(prevRPrEl) : undefined
|
|
430
|
+
};
|
|
431
|
+
rPr.propertyChange = change;
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
return rPr;
|
|
435
|
+
}
|
|
436
|
+
function parseShading(el) {
|
|
437
|
+
return {
|
|
438
|
+
pattern: attrVal(el, "val"),
|
|
439
|
+
color: attrVal(el, "color"),
|
|
440
|
+
fill: attrVal(el, "fill") ?? "auto"
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function parseBorder(el) {
|
|
444
|
+
const b = {
|
|
445
|
+
style: (attrVal(el, "val") ?? "single"),
|
|
446
|
+
size: attrInt(el, "sz"),
|
|
447
|
+
space: attrInt(el, "space"),
|
|
448
|
+
color: attrVal(el, "color")
|
|
449
|
+
};
|
|
450
|
+
const tc = attrVal(el, "themeColor");
|
|
451
|
+
if (tc) {
|
|
452
|
+
b.themeColor = tc;
|
|
453
|
+
}
|
|
454
|
+
const shadow = attrVal(el, "shadow");
|
|
455
|
+
if (shadow === "1" || shadow === "true") {
|
|
456
|
+
b.shadow = true;
|
|
457
|
+
}
|
|
458
|
+
const frame = attrVal(el, "frame");
|
|
459
|
+
if (frame === "1" || frame === "true") {
|
|
460
|
+
b.frame = true;
|
|
461
|
+
}
|
|
462
|
+
const art = attrVal(el, "art");
|
|
463
|
+
if (art) {
|
|
464
|
+
b.art = art;
|
|
465
|
+
}
|
|
466
|
+
return b;
|
|
467
|
+
}
|
|
468
|
+
function parseTableWidth(el) {
|
|
469
|
+
return {
|
|
470
|
+
value: parseInt(el.attributes["w:w"] ?? el.attributes["w"] ?? "0", 10),
|
|
471
|
+
type: (el.attributes["w:type"] ?? el.attributes["type"] ?? "dxa")
|
|
472
|
+
};
|
|
473
|
+
}
|
|
474
|
+
// =============================================================================
|
|
475
|
+
// Paragraph Properties Parser
|
|
476
|
+
// =============================================================================
|
|
477
|
+
function parseParagraphProperties(pPrEl) {
|
|
478
|
+
const pPr = {};
|
|
479
|
+
const pStyleEl = findChildNs(pPrEl, "pStyle");
|
|
480
|
+
if (pStyleEl) {
|
|
481
|
+
pPr.style = attrVal(pStyleEl, "val");
|
|
482
|
+
}
|
|
483
|
+
const jcEl = findChildNs(pPrEl, "jc");
|
|
484
|
+
if (jcEl) {
|
|
485
|
+
pPr.alignment = attrVal(jcEl, "val");
|
|
486
|
+
}
|
|
487
|
+
if (findChildNs(pPrEl, "keepNext")) {
|
|
488
|
+
pPr.keepNext = true;
|
|
489
|
+
}
|
|
490
|
+
if (findChildNs(pPrEl, "keepLines")) {
|
|
491
|
+
pPr.keepLines = true;
|
|
492
|
+
}
|
|
493
|
+
if (findChildNs(pPrEl, "pageBreakBefore")) {
|
|
494
|
+
pPr.pageBreakBefore = true;
|
|
495
|
+
}
|
|
496
|
+
if (findChildNs(pPrEl, "bidi")) {
|
|
497
|
+
pPr.bidi = true;
|
|
498
|
+
}
|
|
499
|
+
// New boolean toggles
|
|
500
|
+
const ctxSp = boolToggle(pPrEl, "contextualSpacing");
|
|
501
|
+
if (ctxSp !== undefined) {
|
|
502
|
+
pPr.contextualSpacing = ctxSp;
|
|
503
|
+
}
|
|
504
|
+
const suppLn = boolToggle(pPrEl, "suppressLineNumbers");
|
|
505
|
+
if (suppLn !== undefined) {
|
|
506
|
+
pPr.suppressLineNumbers = suppLn;
|
|
507
|
+
}
|
|
508
|
+
const suppHyph = boolToggle(pPrEl, "suppressAutoHyphens");
|
|
509
|
+
if (suppHyph !== undefined) {
|
|
510
|
+
pPr.suppressAutoHyphens = suppHyph;
|
|
511
|
+
}
|
|
512
|
+
const mirr = boolToggle(pPrEl, "mirrorIndents");
|
|
513
|
+
if (mirr !== undefined) {
|
|
514
|
+
pPr.mirrorIndents = mirr;
|
|
515
|
+
}
|
|
516
|
+
const wc = boolToggle(pPrEl, "widowControl");
|
|
517
|
+
if (wc !== undefined) {
|
|
518
|
+
pPr.widowControl = wc;
|
|
519
|
+
}
|
|
520
|
+
const ww = boolToggle(pPrEl, "wordWrap");
|
|
521
|
+
if (ww !== undefined) {
|
|
522
|
+
pPr.wordWrap = ww;
|
|
523
|
+
}
|
|
524
|
+
const stg = boolToggle(pPrEl, "snapToGrid");
|
|
525
|
+
if (stg !== undefined) {
|
|
526
|
+
pPr.snapToGrid = stg;
|
|
527
|
+
}
|
|
528
|
+
const ofp = boolToggle(pPrEl, "overflowPunct");
|
|
529
|
+
if (ofp !== undefined) {
|
|
530
|
+
pPr.overflowPunctuation = ofp;
|
|
531
|
+
}
|
|
532
|
+
const topLinePunct = boolToggle(pPrEl, "topLinePunct");
|
|
533
|
+
if (topLinePunct !== undefined) {
|
|
534
|
+
pPr.topLinePunctuation = topLinePunct;
|
|
535
|
+
}
|
|
536
|
+
const kinsoku = boolToggle(pPrEl, "kinsoku");
|
|
537
|
+
if (kinsoku !== undefined) {
|
|
538
|
+
pPr.kinsoku = kinsoku;
|
|
539
|
+
}
|
|
540
|
+
const asd = boolToggle(pPrEl, "autoSpaceDE");
|
|
541
|
+
if (asd !== undefined) {
|
|
542
|
+
pPr.autoSpaceEastAsianText = asd;
|
|
543
|
+
}
|
|
544
|
+
const asdn = boolToggle(pPrEl, "autoSpaceDN");
|
|
545
|
+
if (asdn !== undefined) {
|
|
546
|
+
pPr.autoSpaceEastAsianDigit = asdn;
|
|
547
|
+
}
|
|
548
|
+
const textAlignEl = findChildNs(pPrEl, "textAlignment");
|
|
549
|
+
if (textAlignEl) {
|
|
550
|
+
pPr.textAlignment = attrVal(textAlignEl, "val");
|
|
551
|
+
}
|
|
552
|
+
const outlineLvlEl = findChildNs(pPrEl, "outlineLvl");
|
|
553
|
+
if (outlineLvlEl) {
|
|
554
|
+
pPr.outlineLevel = attrInt(outlineLvlEl, "val");
|
|
555
|
+
}
|
|
556
|
+
const textDirEl = findChildNs(pPrEl, "textDirection");
|
|
557
|
+
if (textDirEl) {
|
|
558
|
+
pPr.textDirection = attrVal(textDirEl, "val");
|
|
559
|
+
}
|
|
560
|
+
// Paragraph frame
|
|
561
|
+
const framePrEl = findChildNs(pPrEl, "framePr");
|
|
562
|
+
if (framePrEl) {
|
|
563
|
+
const frame = {};
|
|
564
|
+
const f = frame;
|
|
565
|
+
const dropCap = attrVal(framePrEl, "dropCap");
|
|
566
|
+
if (dropCap) {
|
|
567
|
+
f.dropCap = dropCap;
|
|
568
|
+
}
|
|
569
|
+
const lines = attrInt(framePrEl, "lines");
|
|
570
|
+
if (lines !== undefined) {
|
|
571
|
+
f.lines = lines;
|
|
572
|
+
}
|
|
573
|
+
const fw = attrInt(framePrEl, "w");
|
|
574
|
+
if (fw !== undefined) {
|
|
575
|
+
f.width = fw;
|
|
576
|
+
}
|
|
577
|
+
const fh = attrInt(framePrEl, "h");
|
|
578
|
+
if (fh !== undefined) {
|
|
579
|
+
f.height = fh;
|
|
580
|
+
}
|
|
581
|
+
const hSpace = attrInt(framePrEl, "hSpace");
|
|
582
|
+
if (hSpace !== undefined) {
|
|
583
|
+
f.hSpace = hSpace;
|
|
584
|
+
}
|
|
585
|
+
const vSpace = attrInt(framePrEl, "vSpace");
|
|
586
|
+
if (vSpace !== undefined) {
|
|
587
|
+
f.vSpace = vSpace;
|
|
588
|
+
}
|
|
589
|
+
const wrap = attrVal(framePrEl, "wrap");
|
|
590
|
+
if (wrap) {
|
|
591
|
+
f.wrap = wrap;
|
|
592
|
+
}
|
|
593
|
+
const hAnchor = attrVal(framePrEl, "hAnchor");
|
|
594
|
+
if (hAnchor) {
|
|
595
|
+
f.hAnchor = hAnchor;
|
|
596
|
+
}
|
|
597
|
+
const vAnchor = attrVal(framePrEl, "vAnchor");
|
|
598
|
+
if (vAnchor) {
|
|
599
|
+
f.vAnchor = vAnchor;
|
|
600
|
+
}
|
|
601
|
+
const x = attrInt(framePrEl, "x");
|
|
602
|
+
if (x !== undefined) {
|
|
603
|
+
f.x = x;
|
|
604
|
+
}
|
|
605
|
+
const xAlign = attrVal(framePrEl, "xAlign");
|
|
606
|
+
if (xAlign) {
|
|
607
|
+
f.xAlign = xAlign;
|
|
608
|
+
}
|
|
609
|
+
const y = attrInt(framePrEl, "y");
|
|
610
|
+
if (y !== undefined) {
|
|
611
|
+
f.y = y;
|
|
612
|
+
}
|
|
613
|
+
const yAlign = attrVal(framePrEl, "yAlign");
|
|
614
|
+
if (yAlign) {
|
|
615
|
+
f.yAlign = yAlign;
|
|
616
|
+
}
|
|
617
|
+
pPr.frame = frame;
|
|
618
|
+
}
|
|
619
|
+
// Thematic break: check for bottom border with special pattern
|
|
620
|
+
const pBdrEl = findChildNs(pPrEl, "pBdr");
|
|
621
|
+
if (pBdrEl) {
|
|
622
|
+
const borders = {};
|
|
623
|
+
for (const side of ["top", "bottom", "left", "right", "between", "bar"]) {
|
|
624
|
+
const sideEl = findChildNs(pBdrEl, side);
|
|
625
|
+
if (sideEl) {
|
|
626
|
+
borders[side] = parseBorder(sideEl);
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
pPr.borders = borders;
|
|
630
|
+
}
|
|
631
|
+
const spacingEl = findChildNs(pPrEl, "spacing");
|
|
632
|
+
if (spacingEl) {
|
|
633
|
+
const spacing = {};
|
|
634
|
+
const before = attrInt(spacingEl, "before");
|
|
635
|
+
const after = attrInt(spacingEl, "after");
|
|
636
|
+
const line = attrInt(spacingEl, "line");
|
|
637
|
+
const lineRule = attrVal(spacingEl, "lineRule");
|
|
638
|
+
if (before !== undefined) {
|
|
639
|
+
spacing.before = before;
|
|
640
|
+
}
|
|
641
|
+
if (after !== undefined) {
|
|
642
|
+
spacing.after = after;
|
|
643
|
+
}
|
|
644
|
+
if (line !== undefined) {
|
|
645
|
+
spacing.line = line;
|
|
646
|
+
// Per ECMA-376, w:lineRule defaults to "auto" when line is set
|
|
647
|
+
spacing.lineRule = (lineRule ?? "auto");
|
|
648
|
+
}
|
|
649
|
+
else if (lineRule) {
|
|
650
|
+
spacing.lineRule = lineRule;
|
|
651
|
+
}
|
|
652
|
+
const beforeAuto = attrVal(spacingEl, "beforeAutospacing");
|
|
653
|
+
if (beforeAuto === "1" || beforeAuto === "true") {
|
|
654
|
+
spacing.beforeAutoSpacing = true;
|
|
655
|
+
}
|
|
656
|
+
const afterAuto = attrVal(spacingEl, "afterAutospacing");
|
|
657
|
+
if (afterAuto === "1" || afterAuto === "true") {
|
|
658
|
+
spacing.afterAutoSpacing = true;
|
|
659
|
+
}
|
|
660
|
+
pPr.spacing = spacing;
|
|
661
|
+
}
|
|
662
|
+
const indEl = findChildNs(pPrEl, "ind");
|
|
663
|
+
if (indEl) {
|
|
664
|
+
const indent = {};
|
|
665
|
+
const left = attrInt(indEl, "left");
|
|
666
|
+
const right = attrInt(indEl, "right");
|
|
667
|
+
const hanging = attrInt(indEl, "hanging");
|
|
668
|
+
const firstLine = attrInt(indEl, "firstLine");
|
|
669
|
+
const start = attrInt(indEl, "start");
|
|
670
|
+
const end = attrInt(indEl, "end");
|
|
671
|
+
if (left !== undefined) {
|
|
672
|
+
indent.left = left;
|
|
673
|
+
}
|
|
674
|
+
if (right !== undefined) {
|
|
675
|
+
indent.right = right;
|
|
676
|
+
}
|
|
677
|
+
if (hanging !== undefined) {
|
|
678
|
+
indent.hanging = hanging;
|
|
679
|
+
}
|
|
680
|
+
if (firstLine !== undefined) {
|
|
681
|
+
indent.firstLine = firstLine;
|
|
682
|
+
}
|
|
683
|
+
if (start !== undefined) {
|
|
684
|
+
indent.start = start;
|
|
685
|
+
}
|
|
686
|
+
if (end !== undefined) {
|
|
687
|
+
indent.end = end;
|
|
688
|
+
}
|
|
689
|
+
pPr.indent = indent;
|
|
690
|
+
}
|
|
691
|
+
const numPrEl = findChildNs(pPrEl, "numPr");
|
|
692
|
+
if (numPrEl) {
|
|
693
|
+
const ilvlEl = findChildNs(numPrEl, "ilvl");
|
|
694
|
+
const numIdEl = findChildNs(numPrEl, "numId");
|
|
695
|
+
// Per OOXML schema, numId is required but ilvl is optional (defaults to 0).
|
|
696
|
+
if (numIdEl) {
|
|
697
|
+
pPr.numbering = {
|
|
698
|
+
level: ilvlEl ? (attrInt(ilvlEl, "val") ?? 0) : 0,
|
|
699
|
+
numId: attrInt(numIdEl, "val") ?? 0
|
|
700
|
+
};
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
const tabsEl = findChildNs(pPrEl, "tabs");
|
|
704
|
+
if (tabsEl) {
|
|
705
|
+
const tabs = [];
|
|
706
|
+
for (const tabEl of findChildrenNs(tabsEl, "tab")) {
|
|
707
|
+
tabs.push({
|
|
708
|
+
type: (attrVal(tabEl, "val") ?? "left"),
|
|
709
|
+
position: attrInt(tabEl, "pos") ?? 0,
|
|
710
|
+
leader: attrVal(tabEl, "leader")
|
|
711
|
+
});
|
|
712
|
+
}
|
|
713
|
+
if (tabs.length > 0) {
|
|
714
|
+
pPr.tabs = tabs;
|
|
715
|
+
}
|
|
716
|
+
}
|
|
717
|
+
const shdEl = findChildNs(pPrEl, "shd");
|
|
718
|
+
if (shdEl) {
|
|
719
|
+
pPr.shading = parseShading(shdEl);
|
|
720
|
+
}
|
|
721
|
+
const rPrEl = findChildNs(pPrEl, "rPr");
|
|
722
|
+
if (rPrEl) {
|
|
723
|
+
pPr.markRunProperties = parseRunProperties(rPrEl);
|
|
724
|
+
}
|
|
725
|
+
const sectPrEl = findChildNs(pPrEl, "sectPr");
|
|
726
|
+
if (sectPrEl) {
|
|
727
|
+
pPr.sectionProperties = parseSectionProperties(sectPrEl);
|
|
728
|
+
}
|
|
729
|
+
// Conditional formatting style mask
|
|
730
|
+
const cnfStyleEl = findChildNs(pPrEl, "cnfStyle");
|
|
731
|
+
if (cnfStyleEl) {
|
|
732
|
+
pPr.cnfStyle = attrVal(cnfStyleEl, "val");
|
|
733
|
+
}
|
|
734
|
+
// Paragraph property change
|
|
735
|
+
const pPrChangeEl = findChildNs(pPrEl, "pPrChange");
|
|
736
|
+
if (pPrChangeEl) {
|
|
737
|
+
const rev = parseRevisionInfo(pPrChangeEl);
|
|
738
|
+
if (rev) {
|
|
739
|
+
const prevPPrEl = findChildNs(pPrChangeEl, "pPr");
|
|
740
|
+
pPr.propertyChange = {
|
|
741
|
+
revision: rev,
|
|
742
|
+
previousProperties: prevPPrEl ? parseParagraphProperties(prevPPrEl) : undefined
|
|
743
|
+
};
|
|
744
|
+
}
|
|
745
|
+
}
|
|
746
|
+
// Paragraph mark insertion/deletion (w:pPr > w:rPr > w:ins/w:del)
|
|
747
|
+
const rPrInPPr = findChildNs(pPrEl, "rPr");
|
|
748
|
+
if (rPrInPPr) {
|
|
749
|
+
const insEl = findChildNs(rPrInPPr, "ins");
|
|
750
|
+
if (insEl) {
|
|
751
|
+
const rev = parseRevisionInfo(insEl);
|
|
752
|
+
if (rev) {
|
|
753
|
+
pPr.paragraphInsertion = rev;
|
|
754
|
+
}
|
|
755
|
+
}
|
|
756
|
+
const delEl = findChildNs(rPrInPPr, "del");
|
|
757
|
+
if (delEl) {
|
|
758
|
+
const rev = parseRevisionInfo(delEl);
|
|
759
|
+
if (rev) {
|
|
760
|
+
pPr.paragraphDeletion = rev;
|
|
761
|
+
}
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
return pPr;
|
|
765
|
+
}
|
|
766
|
+
// =============================================================================
|
|
767
|
+
// Revision Info Parser
|
|
768
|
+
// =============================================================================
|
|
769
|
+
function parseRevisionInfo(el) {
|
|
770
|
+
const author = attrVal(el, "author");
|
|
771
|
+
const id = attrInt(el, "id");
|
|
772
|
+
if (author === undefined || id === undefined) {
|
|
773
|
+
return undefined;
|
|
774
|
+
}
|
|
775
|
+
return {
|
|
776
|
+
author,
|
|
777
|
+
id,
|
|
778
|
+
date: attrVal(el, "date")
|
|
779
|
+
};
|
|
780
|
+
}
|
|
781
|
+
// =============================================================================
|
|
782
|
+
// Run Content Parser
|
|
783
|
+
// =============================================================================
|
|
784
|
+
function parseRunContent(el) {
|
|
785
|
+
const content = [];
|
|
786
|
+
for (const child of el.children) {
|
|
787
|
+
if (child.type !== "element") {
|
|
788
|
+
continue;
|
|
789
|
+
}
|
|
790
|
+
const name = child.name.replace(/^w:/, "");
|
|
791
|
+
switch (name) {
|
|
792
|
+
case "t":
|
|
793
|
+
content.push({ type: "text", text: (0, dom_1.textContent)(child) });
|
|
794
|
+
break;
|
|
795
|
+
case "br": {
|
|
796
|
+
const brType = attrVal(child, "type");
|
|
797
|
+
content.push({ type: "break", breakType: brType });
|
|
798
|
+
break;
|
|
799
|
+
}
|
|
800
|
+
case "tab":
|
|
801
|
+
content.push({ type: "tab" });
|
|
802
|
+
break;
|
|
803
|
+
case "ptab": {
|
|
804
|
+
const alignment = attrVal(child, "alignment") ?? "left";
|
|
805
|
+
const relativeTo = attrVal(child, "relativeTo") ?? "margin";
|
|
806
|
+
const leader = attrVal(child, "leader");
|
|
807
|
+
const ptab = {
|
|
808
|
+
type: "ptab",
|
|
809
|
+
alignment,
|
|
810
|
+
relativeTo
|
|
811
|
+
};
|
|
812
|
+
if (leader) {
|
|
813
|
+
ptab.leader = leader;
|
|
814
|
+
}
|
|
815
|
+
content.push(ptab);
|
|
816
|
+
break;
|
|
817
|
+
}
|
|
818
|
+
case "ruby": {
|
|
819
|
+
const ruby = { type: "ruby" };
|
|
820
|
+
const rubyPrEl = findChildNs(child, "rubyPr");
|
|
821
|
+
if (rubyPrEl) {
|
|
822
|
+
const props = {};
|
|
823
|
+
const alignEl = findChildNs(rubyPrEl, "rubyAlign");
|
|
824
|
+
if (alignEl) {
|
|
825
|
+
props.align = attrVal(alignEl, "val");
|
|
826
|
+
}
|
|
827
|
+
const hpsEl = findChildNs(rubyPrEl, "hps");
|
|
828
|
+
if (hpsEl) {
|
|
829
|
+
props.fontSize = attrInt(hpsEl, "val");
|
|
830
|
+
}
|
|
831
|
+
const hpsRaiseEl = findChildNs(rubyPrEl, "hpsRaise");
|
|
832
|
+
if (hpsRaiseEl) {
|
|
833
|
+
props.raise = attrInt(hpsRaiseEl, "val");
|
|
834
|
+
}
|
|
835
|
+
const hpsBaseTextEl = findChildNs(rubyPrEl, "hpsBaseText");
|
|
836
|
+
if (hpsBaseTextEl) {
|
|
837
|
+
props.baseFontSize = attrInt(hpsBaseTextEl, "val");
|
|
838
|
+
}
|
|
839
|
+
const lidEl = findChildNs(rubyPrEl, "lid");
|
|
840
|
+
if (lidEl) {
|
|
841
|
+
props.language = attrVal(lidEl, "val");
|
|
842
|
+
}
|
|
843
|
+
if (Object.keys(props).length > 0) {
|
|
844
|
+
ruby.properties = props;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
// Parse w:rt (ruby text)
|
|
848
|
+
const rtEl = findChildNs(child, "rt");
|
|
849
|
+
const rubyText = [];
|
|
850
|
+
if (rtEl) {
|
|
851
|
+
for (const rtChild of rtEl.children) {
|
|
852
|
+
if (rtChild.type === "element" && rtChild.name.replace(/^w:/, "") === "r") {
|
|
853
|
+
rubyText.push(parseRun(rtChild));
|
|
854
|
+
}
|
|
855
|
+
}
|
|
856
|
+
}
|
|
857
|
+
ruby.rubyText = rubyText;
|
|
858
|
+
// Parse w:rubyBase
|
|
859
|
+
const baseEl = findChildNs(child, "rubyBase");
|
|
860
|
+
const baseText = [];
|
|
861
|
+
if (baseEl) {
|
|
862
|
+
for (const bChild of baseEl.children) {
|
|
863
|
+
if (bChild.type === "element" && bChild.name.replace(/^w:/, "") === "r") {
|
|
864
|
+
baseText.push(parseRun(bChild));
|
|
865
|
+
}
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
ruby.baseText = baseText;
|
|
869
|
+
content.push(ruby);
|
|
870
|
+
break;
|
|
871
|
+
}
|
|
872
|
+
case "sym":
|
|
873
|
+
content.push({
|
|
874
|
+
type: "symbol",
|
|
875
|
+
font: attrVal(child, "font") ?? "",
|
|
876
|
+
char: attrVal(child, "char") ?? ""
|
|
877
|
+
});
|
|
878
|
+
break;
|
|
879
|
+
case "footnoteReference": {
|
|
880
|
+
const fr = { type: "footnoteRef", id: attrInt(child, "id") ?? 0 };
|
|
881
|
+
const cmf = attrVal(child, "customMarkFollows");
|
|
882
|
+
if (cmf === "1" || cmf === "true") {
|
|
883
|
+
fr.customMarkFollows = true;
|
|
884
|
+
}
|
|
885
|
+
content.push(fr);
|
|
886
|
+
break;
|
|
887
|
+
}
|
|
888
|
+
case "endnoteReference": {
|
|
889
|
+
const er = { type: "endnoteRef", id: attrInt(child, "id") ?? 0 };
|
|
890
|
+
const cmf = attrVal(child, "customMarkFollows");
|
|
891
|
+
if (cmf === "1" || cmf === "true") {
|
|
892
|
+
er.customMarkFollows = true;
|
|
893
|
+
}
|
|
894
|
+
content.push(er);
|
|
895
|
+
break;
|
|
896
|
+
}
|
|
897
|
+
case "drawing":
|
|
898
|
+
parseDrawingContent(child, content);
|
|
899
|
+
break;
|
|
900
|
+
case "cr":
|
|
901
|
+
content.push({ type: "carriageReturn" });
|
|
902
|
+
break;
|
|
903
|
+
case "noBreakHyphen":
|
|
904
|
+
content.push({ type: "noBreakHyphen" });
|
|
905
|
+
break;
|
|
906
|
+
case "softHyphen":
|
|
907
|
+
content.push({ type: "softHyphen" });
|
|
908
|
+
break;
|
|
909
|
+
case "lastRenderedPageBreak":
|
|
910
|
+
content.push({ type: "lastRenderedPageBreak" });
|
|
911
|
+
break;
|
|
912
|
+
case "annotationRef":
|
|
913
|
+
content.push({ type: "annotationReference", id: attrInt(child, "id") ?? 0 });
|
|
914
|
+
break;
|
|
915
|
+
case "commentReference":
|
|
916
|
+
// This is annotationReference for comments inside runs
|
|
917
|
+
content.push({ type: "annotationReference", id: attrInt(child, "id") ?? 0 });
|
|
918
|
+
break;
|
|
919
|
+
}
|
|
920
|
+
}
|
|
921
|
+
return content;
|
|
922
|
+
}
|
|
923
|
+
function parseDrawingContent(drawingEl, content) {
|
|
924
|
+
// Look for wp:inline
|
|
925
|
+
const inlineEl = (0, dom_1.findChild)(drawingEl, "wp:inline");
|
|
926
|
+
if (inlineEl) {
|
|
927
|
+
const extentEl = (0, dom_1.findChild)(inlineEl, "wp:extent");
|
|
928
|
+
const docPrEl = (0, dom_1.findChild)(inlineEl, "wp:docPr");
|
|
929
|
+
const graphicEl = (0, dom_1.findChild)(inlineEl, "a:graphic");
|
|
930
|
+
const graphicDataEl = graphicEl ? (0, dom_1.findChild)(graphicEl, "a:graphicData") : undefined;
|
|
931
|
+
const picEl = graphicDataEl ? (0, dom_1.findChild)(graphicDataEl, "pic:pic") : undefined;
|
|
932
|
+
const blipFillEl = picEl ? (0, dom_1.findChild)(picEl, "pic:blipFill") : undefined;
|
|
933
|
+
const blipEl = blipFillEl ? (0, dom_1.findChild)(blipFillEl, "a:blip") : undefined;
|
|
934
|
+
const rId = blipEl?.attributes["r:embed"] ?? "";
|
|
935
|
+
const cx = parseInt(extentEl?.attributes["cx"] ?? "0", 10);
|
|
936
|
+
const cy = parseInt(extentEl?.attributes["cy"] ?? "0", 10);
|
|
937
|
+
const img = {
|
|
938
|
+
type: "image",
|
|
939
|
+
rId,
|
|
940
|
+
width: cx,
|
|
941
|
+
height: cy,
|
|
942
|
+
altText: docPrEl?.attributes["descr"],
|
|
943
|
+
name: docPrEl?.attributes["name"],
|
|
944
|
+
drawingId: docPrEl ? parseInt(docPrEl.attributes["id"] ?? "1", 10) : undefined
|
|
945
|
+
};
|
|
946
|
+
// Parse xfrm for rotation/flip
|
|
947
|
+
const spPrEl = picEl ? (0, dom_1.findChild)(picEl, "pic:spPr") : undefined;
|
|
948
|
+
if (spPrEl) {
|
|
949
|
+
const xfrmEl = (0, dom_1.findChild)(spPrEl, "a:xfrm");
|
|
950
|
+
if (xfrmEl) {
|
|
951
|
+
const rot = xfrmEl.attributes["rot"];
|
|
952
|
+
if (rot !== undefined && rot !== "") {
|
|
953
|
+
img.rotation = parseInt(rot, 10);
|
|
954
|
+
}
|
|
955
|
+
if (xfrmEl.attributes["flipH"] === "1") {
|
|
956
|
+
img.flipHorizontal = true;
|
|
957
|
+
}
|
|
958
|
+
if (xfrmEl.attributes["flipV"] === "1") {
|
|
959
|
+
img.flipVertical = true;
|
|
960
|
+
}
|
|
961
|
+
}
|
|
962
|
+
// Outline
|
|
963
|
+
const lnEl = (0, dom_1.findChild)(spPrEl, "a:ln");
|
|
964
|
+
if (lnEl) {
|
|
965
|
+
const outline = {};
|
|
966
|
+
const w = lnEl.attributes["w"];
|
|
967
|
+
if (w) {
|
|
968
|
+
outline.width = parseInt(w, 10);
|
|
969
|
+
}
|
|
970
|
+
const sfEl = (0, dom_1.findChild)(lnEl, "a:solidFill");
|
|
971
|
+
const srgbEl = sfEl ? (0, dom_1.findChild)(sfEl, "a:srgbClr") : undefined;
|
|
972
|
+
if (srgbEl) {
|
|
973
|
+
outline.color = srgbEl.attributes["val"];
|
|
974
|
+
}
|
|
975
|
+
img.outline = outline;
|
|
976
|
+
}
|
|
977
|
+
}
|
|
978
|
+
// SVG blip in a:extLst
|
|
979
|
+
if (blipEl) {
|
|
980
|
+
const extLst = (0, dom_1.findChild)(blipEl, "a:extLst");
|
|
981
|
+
if (extLst) {
|
|
982
|
+
for (const ext of (0, dom_1.findChildren)(extLst, "a:ext")) {
|
|
983
|
+
const svgBlip = (0, dom_1.findChild)(ext, "asvg:svgBlip") ?? findChildNs(ext, "svgBlip");
|
|
984
|
+
if (svgBlip) {
|
|
985
|
+
const svgEmbed = svgBlip.attributes["r:embed"];
|
|
986
|
+
if (svgEmbed) {
|
|
987
|
+
img.svgRId = svgEmbed;
|
|
988
|
+
}
|
|
989
|
+
}
|
|
990
|
+
}
|
|
991
|
+
}
|
|
992
|
+
}
|
|
993
|
+
content.push(img);
|
|
994
|
+
}
|
|
995
|
+
}
|
|
996
|
+
// =============================================================================
|
|
997
|
+
// Floating Image Parser
|
|
998
|
+
// =============================================================================
|
|
999
|
+
function parseFloatingImage(anchorEl) {
|
|
1000
|
+
const docPrEl = (0, dom_1.findChild)(anchorEl, "wp:docPr");
|
|
1001
|
+
const extentEl = (0, dom_1.findChild)(anchorEl, "wp:extent");
|
|
1002
|
+
const graphicEl = (0, dom_1.findChild)(anchorEl, "a:graphic");
|
|
1003
|
+
const graphicDataEl = graphicEl ? (0, dom_1.findChild)(graphicEl, "a:graphicData") : undefined;
|
|
1004
|
+
const picEl = graphicDataEl ? (0, dom_1.findChild)(graphicDataEl, "pic:pic") : undefined;
|
|
1005
|
+
const blipFillEl = picEl ? (0, dom_1.findChild)(picEl, "pic:blipFill") : undefined;
|
|
1006
|
+
const blipEl = blipFillEl ? (0, dom_1.findChild)(blipFillEl, "a:blip") : undefined;
|
|
1007
|
+
const rId = blipEl?.attributes["r:embed"];
|
|
1008
|
+
if (!rId) {
|
|
1009
|
+
return undefined;
|
|
1010
|
+
}
|
|
1011
|
+
const cx = parseInt(extentEl?.attributes["cx"] ?? "0", 10);
|
|
1012
|
+
const cy = parseInt(extentEl?.attributes["cy"] ?? "0", 10);
|
|
1013
|
+
const img = {
|
|
1014
|
+
type: "floatingImage",
|
|
1015
|
+
rId,
|
|
1016
|
+
width: cx,
|
|
1017
|
+
height: cy,
|
|
1018
|
+
altText: docPrEl?.attributes["descr"],
|
|
1019
|
+
name: docPrEl?.attributes["name"],
|
|
1020
|
+
drawingId: docPrEl ? parseInt(docPrEl.attributes["id"] ?? "1", 10) : undefined
|
|
1021
|
+
};
|
|
1022
|
+
// Attributes
|
|
1023
|
+
if (anchorEl.attributes["behindDoc"] === "1") {
|
|
1024
|
+
img.behindDoc = true;
|
|
1025
|
+
}
|
|
1026
|
+
if (anchorEl.attributes["locked"] === "1") {
|
|
1027
|
+
img.lockAnchor = true;
|
|
1028
|
+
}
|
|
1029
|
+
if (anchorEl.attributes["layoutInCell"] === "0") {
|
|
1030
|
+
img.layoutInCell = false;
|
|
1031
|
+
}
|
|
1032
|
+
if (anchorEl.attributes["allowOverlap"] === "0") {
|
|
1033
|
+
img.allowOverlap = false;
|
|
1034
|
+
}
|
|
1035
|
+
const rh = anchorEl.attributes["relativeHeight"];
|
|
1036
|
+
if (rh) {
|
|
1037
|
+
img.relativeHeight = parseInt(rh, 10);
|
|
1038
|
+
}
|
|
1039
|
+
// Dist*
|
|
1040
|
+
const distT = anchorEl.attributes["distT"];
|
|
1041
|
+
if (distT) {
|
|
1042
|
+
img.distT = parseInt(distT, 10);
|
|
1043
|
+
}
|
|
1044
|
+
const distB = anchorEl.attributes["distB"];
|
|
1045
|
+
if (distB) {
|
|
1046
|
+
img.distB = parseInt(distB, 10);
|
|
1047
|
+
}
|
|
1048
|
+
const distL = anchorEl.attributes["distL"];
|
|
1049
|
+
if (distL) {
|
|
1050
|
+
img.distL = parseInt(distL, 10);
|
|
1051
|
+
}
|
|
1052
|
+
const distR = anchorEl.attributes["distR"];
|
|
1053
|
+
if (distR) {
|
|
1054
|
+
img.distR = parseInt(distR, 10);
|
|
1055
|
+
}
|
|
1056
|
+
// Simple positioning
|
|
1057
|
+
if (anchorEl.attributes["simplePos"] === "1") {
|
|
1058
|
+
const sposEl = (0, dom_1.findChild)(anchorEl, "wp:simplePos");
|
|
1059
|
+
if (sposEl) {
|
|
1060
|
+
const x = parseInt(sposEl.attributes["x"] ?? "0", 10);
|
|
1061
|
+
const y = parseInt(sposEl.attributes["y"] ?? "0", 10);
|
|
1062
|
+
img.simplePos = { x, y };
|
|
1063
|
+
}
|
|
1064
|
+
}
|
|
1065
|
+
// Horizontal position
|
|
1066
|
+
const hPosEl = (0, dom_1.findChild)(anchorEl, "wp:positionH");
|
|
1067
|
+
if (hPosEl) {
|
|
1068
|
+
const h = { relativeTo: hPosEl.attributes["relativeFrom"] };
|
|
1069
|
+
const offsetEl = (0, dom_1.findChild)(hPosEl, "wp:posOffset");
|
|
1070
|
+
if (offsetEl) {
|
|
1071
|
+
h.offset = parseInt((0, dom_1.textContent)(offsetEl), 10);
|
|
1072
|
+
}
|
|
1073
|
+
const alignEl = (0, dom_1.findChild)(hPosEl, "wp:align");
|
|
1074
|
+
if (alignEl) {
|
|
1075
|
+
h.align = (0, dom_1.textContent)(alignEl);
|
|
1076
|
+
}
|
|
1077
|
+
img.horizontalPosition = h;
|
|
1078
|
+
}
|
|
1079
|
+
// Vertical position
|
|
1080
|
+
const vPosEl = (0, dom_1.findChild)(anchorEl, "wp:positionV");
|
|
1081
|
+
if (vPosEl) {
|
|
1082
|
+
const v = { relativeTo: vPosEl.attributes["relativeFrom"] };
|
|
1083
|
+
const offsetEl = (0, dom_1.findChild)(vPosEl, "wp:posOffset");
|
|
1084
|
+
if (offsetEl) {
|
|
1085
|
+
v.offset = parseInt((0, dom_1.textContent)(offsetEl), 10);
|
|
1086
|
+
}
|
|
1087
|
+
const alignEl = (0, dom_1.findChild)(vPosEl, "wp:align");
|
|
1088
|
+
if (alignEl) {
|
|
1089
|
+
v.align = (0, dom_1.textContent)(alignEl);
|
|
1090
|
+
}
|
|
1091
|
+
img.verticalPosition = v;
|
|
1092
|
+
}
|
|
1093
|
+
// Wrap
|
|
1094
|
+
for (const wrapChild of anchorEl.children) {
|
|
1095
|
+
if (wrapChild.type !== "element") {
|
|
1096
|
+
continue;
|
|
1097
|
+
}
|
|
1098
|
+
const wn = wrapChild.name;
|
|
1099
|
+
if (wn === "wp:wrapSquare") {
|
|
1100
|
+
img.wrap = { style: "square", side: wrapChild.attributes["wrapText"] };
|
|
1101
|
+
}
|
|
1102
|
+
else if (wn === "wp:wrapTight") {
|
|
1103
|
+
img.wrap = { style: "tight", side: wrapChild.attributes["wrapText"] };
|
|
1104
|
+
}
|
|
1105
|
+
else if (wn === "wp:wrapThrough") {
|
|
1106
|
+
img.wrap = { style: "through", side: wrapChild.attributes["wrapText"] };
|
|
1107
|
+
}
|
|
1108
|
+
else if (wn === "wp:wrapTopAndBottom") {
|
|
1109
|
+
img.wrap = { style: "topAndBottom" };
|
|
1110
|
+
}
|
|
1111
|
+
else if (wn === "wp:wrapNone") {
|
|
1112
|
+
img.wrap = { style: "none" };
|
|
1113
|
+
}
|
|
1114
|
+
if (img.wrap) {
|
|
1115
|
+
// Parse wrap margins
|
|
1116
|
+
const distT = anchorEl.attributes["distT"];
|
|
1117
|
+
const distB = anchorEl.attributes["distB"];
|
|
1118
|
+
const distL = anchorEl.attributes["distL"];
|
|
1119
|
+
const distR = anchorEl.attributes["distR"];
|
|
1120
|
+
if (distT || distB || distL || distR) {
|
|
1121
|
+
const margins = {};
|
|
1122
|
+
if (distT) {
|
|
1123
|
+
margins.top = parseInt(distT, 10);
|
|
1124
|
+
}
|
|
1125
|
+
if (distB) {
|
|
1126
|
+
margins.bottom = parseInt(distB, 10);
|
|
1127
|
+
}
|
|
1128
|
+
if (distL) {
|
|
1129
|
+
margins.left = parseInt(distL, 10);
|
|
1130
|
+
}
|
|
1131
|
+
if (distR) {
|
|
1132
|
+
margins.right = parseInt(distR, 10);
|
|
1133
|
+
}
|
|
1134
|
+
img.wrap.margins = margins;
|
|
1135
|
+
}
|
|
1136
|
+
break;
|
|
1137
|
+
}
|
|
1138
|
+
}
|
|
1139
|
+
// Rotation/flip from spPr
|
|
1140
|
+
const spPrEl = picEl ? (0, dom_1.findChild)(picEl, "pic:spPr") : undefined;
|
|
1141
|
+
if (spPrEl) {
|
|
1142
|
+
const xfrmEl = (0, dom_1.findChild)(spPrEl, "a:xfrm");
|
|
1143
|
+
if (xfrmEl) {
|
|
1144
|
+
const rot = xfrmEl.attributes["rot"];
|
|
1145
|
+
if (rot !== undefined && rot !== "") {
|
|
1146
|
+
img.rotation = parseInt(rot, 10);
|
|
1147
|
+
}
|
|
1148
|
+
if (xfrmEl.attributes["flipH"] === "1") {
|
|
1149
|
+
img.flipHorizontal = true;
|
|
1150
|
+
}
|
|
1151
|
+
if (xfrmEl.attributes["flipV"] === "1") {
|
|
1152
|
+
img.flipVertical = true;
|
|
1153
|
+
}
|
|
1154
|
+
}
|
|
1155
|
+
const lnEl = (0, dom_1.findChild)(spPrEl, "a:ln");
|
|
1156
|
+
if (lnEl) {
|
|
1157
|
+
const outline = {};
|
|
1158
|
+
const w = lnEl.attributes["w"];
|
|
1159
|
+
if (w) {
|
|
1160
|
+
outline.width = parseInt(w, 10);
|
|
1161
|
+
}
|
|
1162
|
+
const sfEl = (0, dom_1.findChild)(lnEl, "a:solidFill");
|
|
1163
|
+
const srgbEl = sfEl ? (0, dom_1.findChild)(sfEl, "a:srgbClr") : undefined;
|
|
1164
|
+
if (srgbEl) {
|
|
1165
|
+
outline.color = srgbEl.attributes["val"];
|
|
1166
|
+
}
|
|
1167
|
+
img.outline = outline;
|
|
1168
|
+
}
|
|
1169
|
+
}
|
|
1170
|
+
// SVG blip in a:extLst
|
|
1171
|
+
if (blipEl) {
|
|
1172
|
+
const extLst = (0, dom_1.findChild)(blipEl, "a:extLst");
|
|
1173
|
+
if (extLst) {
|
|
1174
|
+
for (const ext of (0, dom_1.findChildren)(extLst, "a:ext")) {
|
|
1175
|
+
const svgBlip = (0, dom_1.findChild)(ext, "asvg:svgBlip") ?? findChildNs(ext, "svgBlip");
|
|
1176
|
+
if (svgBlip) {
|
|
1177
|
+
const svgEmbed = svgBlip.attributes["r:embed"];
|
|
1178
|
+
if (svgEmbed) {
|
|
1179
|
+
img.svgRId = svgEmbed;
|
|
1180
|
+
}
|
|
1181
|
+
}
|
|
1182
|
+
}
|
|
1183
|
+
}
|
|
1184
|
+
}
|
|
1185
|
+
// Source rectangle (crop)
|
|
1186
|
+
if (blipFillEl) {
|
|
1187
|
+
const srcRectEl = (0, dom_1.findChild)(blipFillEl, "a:srcRect");
|
|
1188
|
+
if (srcRectEl) {
|
|
1189
|
+
const sr = {};
|
|
1190
|
+
const lAttr = srcRectEl.attributes["l"];
|
|
1191
|
+
const tAttr = srcRectEl.attributes["t"];
|
|
1192
|
+
const rAttr = srcRectEl.attributes["r"];
|
|
1193
|
+
const bAttr = srcRectEl.attributes["b"];
|
|
1194
|
+
if (lAttr !== undefined) {
|
|
1195
|
+
sr.l = parseInt(lAttr, 10);
|
|
1196
|
+
}
|
|
1197
|
+
if (tAttr !== undefined) {
|
|
1198
|
+
sr.t = parseInt(tAttr, 10);
|
|
1199
|
+
}
|
|
1200
|
+
if (rAttr !== undefined) {
|
|
1201
|
+
sr.r = parseInt(rAttr, 10);
|
|
1202
|
+
}
|
|
1203
|
+
if (bAttr !== undefined) {
|
|
1204
|
+
sr.b = parseInt(bAttr, 10);
|
|
1205
|
+
}
|
|
1206
|
+
if (Object.keys(sr).length > 0) {
|
|
1207
|
+
img.srcRect = sr;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
}
|
|
1211
|
+
return img;
|
|
1212
|
+
}
|
|
1213
|
+
// =============================================================================
|
|
1214
|
+
// DrawingML Shape Parser
|
|
1215
|
+
// =============================================================================
|
|
1216
|
+
function parseDrawingShape(anchorEl, wspEl) {
|
|
1217
|
+
const docPrEl = (0, dom_1.findChild)(anchorEl, "wp:docPr");
|
|
1218
|
+
const extentEl = (0, dom_1.findChild)(anchorEl, "wp:extent");
|
|
1219
|
+
const cx = parseInt(extentEl?.attributes["cx"] ?? "0", 10);
|
|
1220
|
+
const cy = parseInt(extentEl?.attributes["cy"] ?? "0", 10);
|
|
1221
|
+
// Parse preset shape type from wps:spPr > a:prstGeom
|
|
1222
|
+
const spPrEl = (0, dom_1.findChild)(wspEl, "wps:spPr") ?? findChildNs(wspEl, "spPr");
|
|
1223
|
+
const prstGeomEl = spPrEl
|
|
1224
|
+
? ((0, dom_1.findChild)(spPrEl, "a:prstGeom") ?? findChildNs(spPrEl, "prstGeom"))
|
|
1225
|
+
: undefined;
|
|
1226
|
+
const shapeType = prstGeomEl?.attributes["prst"] ?? "rect";
|
|
1227
|
+
const shape = {
|
|
1228
|
+
type: "drawingShape",
|
|
1229
|
+
shapeType,
|
|
1230
|
+
width: cx,
|
|
1231
|
+
height: cy,
|
|
1232
|
+
altText: docPrEl?.attributes["descr"],
|
|
1233
|
+
name: docPrEl?.attributes["name"]
|
|
1234
|
+
};
|
|
1235
|
+
// Parse fill
|
|
1236
|
+
if (spPrEl) {
|
|
1237
|
+
const solidFill = (0, dom_1.findChild)(spPrEl, "a:solidFill") ?? findChildNs(spPrEl, "solidFill");
|
|
1238
|
+
if (solidFill) {
|
|
1239
|
+
const srgb = (0, dom_1.findChild)(solidFill, "a:srgbClr") ?? findChildNs(solidFill, "srgbClr");
|
|
1240
|
+
if (srgb) {
|
|
1241
|
+
shape.fillColor = srgb.attributes["val"];
|
|
1242
|
+
}
|
|
1243
|
+
}
|
|
1244
|
+
const noFill = (0, dom_1.findChild)(spPrEl, "a:noFill") ?? findChildNs(spPrEl, "noFill");
|
|
1245
|
+
if (noFill) {
|
|
1246
|
+
shape.noFill = true;
|
|
1247
|
+
}
|
|
1248
|
+
// Parse outline
|
|
1249
|
+
const lnEl = (0, dom_1.findChild)(spPrEl, "a:ln") ?? findChildNs(spPrEl, "ln");
|
|
1250
|
+
if (lnEl) {
|
|
1251
|
+
const w = lnEl.attributes["w"];
|
|
1252
|
+
if (w) {
|
|
1253
|
+
shape.outlineWidth = parseInt(w, 10);
|
|
1254
|
+
}
|
|
1255
|
+
const lnFill = (0, dom_1.findChild)(lnEl, "a:solidFill") ?? findChildNs(lnEl, "solidFill");
|
|
1256
|
+
if (lnFill) {
|
|
1257
|
+
const srgb = (0, dom_1.findChild)(lnFill, "a:srgbClr") ?? findChildNs(lnFill, "srgbClr");
|
|
1258
|
+
if (srgb) {
|
|
1259
|
+
shape.outlineColor = srgb.attributes["val"];
|
|
1260
|
+
}
|
|
1261
|
+
}
|
|
1262
|
+
const noLn = (0, dom_1.findChild)(lnEl, "a:noFill") ?? findChildNs(lnEl, "noFill");
|
|
1263
|
+
if (noLn) {
|
|
1264
|
+
shape.noOutline = true;
|
|
1265
|
+
}
|
|
1266
|
+
}
|
|
1267
|
+
}
|
|
1268
|
+
// Parse text content (wps:txbx > w:txbxContent)
|
|
1269
|
+
const txbxEl = (0, dom_1.findChild)(wspEl, "wps:txbx") ?? findChildNs(wspEl, "txbx");
|
|
1270
|
+
const txbxContentEl = txbxEl
|
|
1271
|
+
? ((0, dom_1.findChild)(txbxEl, "w:txbxContent") ?? findChildNs(txbxEl, "txbxContent"))
|
|
1272
|
+
: undefined;
|
|
1273
|
+
if (txbxContentEl) {
|
|
1274
|
+
const paras = [];
|
|
1275
|
+
for (const child of txbxContentEl.children) {
|
|
1276
|
+
if (child.type === "element" && child.name.replace(/^w:/, "") === "p") {
|
|
1277
|
+
paras.push(parseParagraph(child));
|
|
1278
|
+
}
|
|
1279
|
+
}
|
|
1280
|
+
if (paras.length > 0) {
|
|
1281
|
+
shape.textContent = paras;
|
|
1282
|
+
}
|
|
1283
|
+
}
|
|
1284
|
+
// Parse positioning
|
|
1285
|
+
const posH = (0, dom_1.findChild)(anchorEl, "wp:positionH");
|
|
1286
|
+
if (posH) {
|
|
1287
|
+
const hp = { relativeTo: posH.attributes["relativeFrom"] };
|
|
1288
|
+
const offsetEl = (0, dom_1.findChild)(posH, "wp:posOffset");
|
|
1289
|
+
if (offsetEl) {
|
|
1290
|
+
hp.offset = parseInt((0, dom_1.textContent)(offsetEl), 10);
|
|
1291
|
+
}
|
|
1292
|
+
const alignEl = (0, dom_1.findChild)(posH, "wp:align");
|
|
1293
|
+
if (alignEl) {
|
|
1294
|
+
hp.align = (0, dom_1.textContent)(alignEl);
|
|
1295
|
+
}
|
|
1296
|
+
shape.horizontalPosition = hp;
|
|
1297
|
+
}
|
|
1298
|
+
const posV = (0, dom_1.findChild)(anchorEl, "wp:positionV");
|
|
1299
|
+
if (posV) {
|
|
1300
|
+
const vp = { relativeTo: posV.attributes["relativeFrom"] };
|
|
1301
|
+
const offsetEl = (0, dom_1.findChild)(posV, "wp:posOffset");
|
|
1302
|
+
if (offsetEl) {
|
|
1303
|
+
vp.offset = parseInt((0, dom_1.textContent)(offsetEl), 10);
|
|
1304
|
+
}
|
|
1305
|
+
const alignEl = (0, dom_1.findChild)(posV, "wp:align");
|
|
1306
|
+
if (alignEl) {
|
|
1307
|
+
vp.align = (0, dom_1.textContent)(alignEl);
|
|
1308
|
+
}
|
|
1309
|
+
shape.verticalPosition = vp;
|
|
1310
|
+
}
|
|
1311
|
+
// Wrap
|
|
1312
|
+
for (const wrapChild of anchorEl.children) {
|
|
1313
|
+
if (wrapChild.type !== "element") {
|
|
1314
|
+
continue;
|
|
1315
|
+
}
|
|
1316
|
+
const wn = wrapChild.name;
|
|
1317
|
+
if (wn === "wp:wrapSquare") {
|
|
1318
|
+
shape.wrap = { style: "square", side: wrapChild.attributes["wrapText"] };
|
|
1319
|
+
}
|
|
1320
|
+
else if (wn === "wp:wrapTight") {
|
|
1321
|
+
shape.wrap = { style: "tight", side: wrapChild.attributes["wrapText"] };
|
|
1322
|
+
}
|
|
1323
|
+
else if (wn === "wp:wrapTopAndBottom") {
|
|
1324
|
+
shape.wrap = { style: "topAndBottom" };
|
|
1325
|
+
}
|
|
1326
|
+
else if (wn === "wp:wrapNone") {
|
|
1327
|
+
shape.wrap = { style: "none" };
|
|
1328
|
+
}
|
|
1329
|
+
}
|
|
1330
|
+
// Behind doc
|
|
1331
|
+
if (anchorEl.attributes["behindDoc"] === "1") {
|
|
1332
|
+
shape.behindDoc = true;
|
|
1333
|
+
}
|
|
1334
|
+
// Rotation
|
|
1335
|
+
if (spPrEl) {
|
|
1336
|
+
const xfrmEl = (0, dom_1.findChild)(spPrEl, "a:xfrm") ?? findChildNs(spPrEl, "xfrm");
|
|
1337
|
+
if (xfrmEl?.attributes["rot"]) {
|
|
1338
|
+
shape.rotation = parseInt(xfrmEl.attributes["rot"], 10);
|
|
1339
|
+
}
|
|
1340
|
+
}
|
|
1341
|
+
return shape;
|
|
1342
|
+
}
|
|
1343
|
+
// =============================================================================
|
|
1344
|
+
// Math Parser
|
|
1345
|
+
// =============================================================================
|
|
1346
|
+
function findMathChild(el, localName) {
|
|
1347
|
+
return (0, dom_1.findChild)(el, `m:${localName}`) ?? (0, dom_1.findChild)(el, localName);
|
|
1348
|
+
}
|
|
1349
|
+
function mathAttrVal(el, name) {
|
|
1350
|
+
return el.attributes[`m:${name}`] ?? el.attributes[name];
|
|
1351
|
+
}
|
|
1352
|
+
function findMathChildren(el, localName) {
|
|
1353
|
+
const a = (0, dom_1.findChildren)(el, `m:${localName}`);
|
|
1354
|
+
return a.length > 0 ? a : (0, dom_1.findChildren)(el, localName);
|
|
1355
|
+
}
|
|
1356
|
+
function parseMathContent(el) {
|
|
1357
|
+
const result = [];
|
|
1358
|
+
for (const child of el.children) {
|
|
1359
|
+
if (child.type !== "element") {
|
|
1360
|
+
continue;
|
|
1361
|
+
}
|
|
1362
|
+
const name = child.name.replace(/^m:/, "");
|
|
1363
|
+
switch (name) {
|
|
1364
|
+
case "r": {
|
|
1365
|
+
// Math run
|
|
1366
|
+
const tEl = findMathChild(child, "t");
|
|
1367
|
+
const mrPrEl = findMathChild(child, "rPr");
|
|
1368
|
+
const mr = { type: "mathRun", text: tEl ? (0, dom_1.textContent)(tEl) : "" };
|
|
1369
|
+
if (mrPrEl) {
|
|
1370
|
+
const props = {};
|
|
1371
|
+
const sty = findMathChild(mrPrEl, "sty");
|
|
1372
|
+
if (sty) {
|
|
1373
|
+
const v = sty.attributes["m:val"] ?? sty.attributes["val"];
|
|
1374
|
+
if (v === "p" || v === "b") {
|
|
1375
|
+
props.italic = false;
|
|
1376
|
+
}
|
|
1377
|
+
if (v === "b" || v === "bi") {
|
|
1378
|
+
props.bold = true;
|
|
1379
|
+
}
|
|
1380
|
+
}
|
|
1381
|
+
if (Object.keys(props).length > 0) {
|
|
1382
|
+
mr.properties = props;
|
|
1383
|
+
}
|
|
1384
|
+
}
|
|
1385
|
+
result.push(mr);
|
|
1386
|
+
break;
|
|
1387
|
+
}
|
|
1388
|
+
case "f": {
|
|
1389
|
+
const fPrEl = findMathChild(child, "fPr");
|
|
1390
|
+
const num = findMathChild(child, "num");
|
|
1391
|
+
const den = findMathChild(child, "den");
|
|
1392
|
+
const frac = {
|
|
1393
|
+
type: "mathFraction",
|
|
1394
|
+
numerator: num ? parseMathContent(num) : [],
|
|
1395
|
+
denominator: den ? parseMathContent(den) : []
|
|
1396
|
+
};
|
|
1397
|
+
if (fPrEl) {
|
|
1398
|
+
const typeEl = findMathChild(fPrEl, "type");
|
|
1399
|
+
if (typeEl) {
|
|
1400
|
+
frac.fractionType = typeEl.attributes["m:val"] ?? typeEl.attributes["val"];
|
|
1401
|
+
}
|
|
1402
|
+
}
|
|
1403
|
+
result.push(frac);
|
|
1404
|
+
break;
|
|
1405
|
+
}
|
|
1406
|
+
case "sSup": {
|
|
1407
|
+
const base = findMathChild(child, "e");
|
|
1408
|
+
const sup = findMathChild(child, "sup");
|
|
1409
|
+
result.push({
|
|
1410
|
+
type: "mathSuperScript",
|
|
1411
|
+
base: base ? parseMathContent(base) : [],
|
|
1412
|
+
superScript: sup ? parseMathContent(sup) : []
|
|
1413
|
+
});
|
|
1414
|
+
break;
|
|
1415
|
+
}
|
|
1416
|
+
case "sSub": {
|
|
1417
|
+
const base = findMathChild(child, "e");
|
|
1418
|
+
const sub = findMathChild(child, "sub");
|
|
1419
|
+
result.push({
|
|
1420
|
+
type: "mathSubScript",
|
|
1421
|
+
base: base ? parseMathContent(base) : [],
|
|
1422
|
+
subScript: sub ? parseMathContent(sub) : []
|
|
1423
|
+
});
|
|
1424
|
+
break;
|
|
1425
|
+
}
|
|
1426
|
+
case "sSubSup": {
|
|
1427
|
+
const base = findMathChild(child, "e");
|
|
1428
|
+
const sub = findMathChild(child, "sub");
|
|
1429
|
+
const sup = findMathChild(child, "sup");
|
|
1430
|
+
result.push({
|
|
1431
|
+
type: "mathSubSuperScript",
|
|
1432
|
+
base: base ? parseMathContent(base) : [],
|
|
1433
|
+
subScript: sub ? parseMathContent(sub) : [],
|
|
1434
|
+
superScript: sup ? parseMathContent(sup) : []
|
|
1435
|
+
});
|
|
1436
|
+
break;
|
|
1437
|
+
}
|
|
1438
|
+
case "sPre": {
|
|
1439
|
+
const base = findMathChild(child, "e");
|
|
1440
|
+
const sub = findMathChild(child, "sub");
|
|
1441
|
+
const sup = findMathChild(child, "sup");
|
|
1442
|
+
result.push({
|
|
1443
|
+
type: "mathPreSubSuperScript",
|
|
1444
|
+
base: base ? parseMathContent(base) : [],
|
|
1445
|
+
preSubScript: sub ? parseMathContent(sub) : [],
|
|
1446
|
+
preSuperScript: sup ? parseMathContent(sup) : []
|
|
1447
|
+
});
|
|
1448
|
+
break;
|
|
1449
|
+
}
|
|
1450
|
+
case "phant": {
|
|
1451
|
+
const eEl = findMathChild(child, "e");
|
|
1452
|
+
const phantPrEl = findMathChild(child, "phantPr");
|
|
1453
|
+
const ph = {
|
|
1454
|
+
type: "mathPhantom",
|
|
1455
|
+
content: eEl ? parseMathContent(eEl) : []
|
|
1456
|
+
};
|
|
1457
|
+
if (phantPrEl) {
|
|
1458
|
+
const boolAttr = (name) => {
|
|
1459
|
+
const el = findMathChild(phantPrEl, name);
|
|
1460
|
+
if (!el) {
|
|
1461
|
+
return false;
|
|
1462
|
+
}
|
|
1463
|
+
const v = mathAttrVal(el, "val");
|
|
1464
|
+
return v !== "0" && v !== "false";
|
|
1465
|
+
};
|
|
1466
|
+
if (boolAttr("show")) {
|
|
1467
|
+
ph.show = true;
|
|
1468
|
+
}
|
|
1469
|
+
if (boolAttr("zeroWid")) {
|
|
1470
|
+
ph.zeroWidth = true;
|
|
1471
|
+
}
|
|
1472
|
+
if (boolAttr("zeroAsc")) {
|
|
1473
|
+
ph.zeroAscent = true;
|
|
1474
|
+
}
|
|
1475
|
+
if (boolAttr("zeroDesc")) {
|
|
1476
|
+
ph.zeroDescent = true;
|
|
1477
|
+
}
|
|
1478
|
+
if (boolAttr("transp")) {
|
|
1479
|
+
ph.transparent = true;
|
|
1480
|
+
}
|
|
1481
|
+
}
|
|
1482
|
+
result.push(ph);
|
|
1483
|
+
break;
|
|
1484
|
+
}
|
|
1485
|
+
case "groupChr": {
|
|
1486
|
+
const eEl = findMathChild(child, "e");
|
|
1487
|
+
const prEl = findMathChild(child, "groupChrPr");
|
|
1488
|
+
const g = {
|
|
1489
|
+
type: "mathGroupChar",
|
|
1490
|
+
base: eEl ? parseMathContent(eEl) : []
|
|
1491
|
+
};
|
|
1492
|
+
if (prEl) {
|
|
1493
|
+
const chrEl = findMathChild(prEl, "chr");
|
|
1494
|
+
if (chrEl) {
|
|
1495
|
+
g.char = mathAttrVal(chrEl, "val");
|
|
1496
|
+
}
|
|
1497
|
+
const posEl = findMathChild(prEl, "pos");
|
|
1498
|
+
if (posEl) {
|
|
1499
|
+
const v = mathAttrVal(posEl, "val");
|
|
1500
|
+
if (v === "top" || v === "bottom") {
|
|
1501
|
+
g.position = v;
|
|
1502
|
+
}
|
|
1503
|
+
}
|
|
1504
|
+
const vjcEl = findMathChild(prEl, "vertJc");
|
|
1505
|
+
if (vjcEl) {
|
|
1506
|
+
const v = mathAttrVal(vjcEl, "val");
|
|
1507
|
+
if (v === "top" || v === "center" || v === "bottom") {
|
|
1508
|
+
g.verticalAlign = v;
|
|
1509
|
+
}
|
|
1510
|
+
}
|
|
1511
|
+
}
|
|
1512
|
+
result.push(g);
|
|
1513
|
+
break;
|
|
1514
|
+
}
|
|
1515
|
+
case "borderBox": {
|
|
1516
|
+
const eEl = findMathChild(child, "e");
|
|
1517
|
+
const prEl = findMathChild(child, "borderBoxPr");
|
|
1518
|
+
const b = {
|
|
1519
|
+
type: "mathBorderBox",
|
|
1520
|
+
content: eEl ? parseMathContent(eEl) : []
|
|
1521
|
+
};
|
|
1522
|
+
if (prEl) {
|
|
1523
|
+
const boolAttr = (name) => {
|
|
1524
|
+
const el = findMathChild(prEl, name);
|
|
1525
|
+
if (!el) {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
const v = mathAttrVal(el, "val");
|
|
1529
|
+
return v !== "0" && v !== "false";
|
|
1530
|
+
};
|
|
1531
|
+
if (boolAttr("hideTop")) {
|
|
1532
|
+
b.hideTop = true;
|
|
1533
|
+
}
|
|
1534
|
+
if (boolAttr("hideBot")) {
|
|
1535
|
+
b.hideBottom = true;
|
|
1536
|
+
}
|
|
1537
|
+
if (boolAttr("hideLeft")) {
|
|
1538
|
+
b.hideLeft = true;
|
|
1539
|
+
}
|
|
1540
|
+
if (boolAttr("hideRight")) {
|
|
1541
|
+
b.hideRight = true;
|
|
1542
|
+
}
|
|
1543
|
+
if (boolAttr("strikeBLTR")) {
|
|
1544
|
+
b.strikeBlTr = true;
|
|
1545
|
+
}
|
|
1546
|
+
if (boolAttr("strikeTLBR")) {
|
|
1547
|
+
b.strikeTlBr = true;
|
|
1548
|
+
}
|
|
1549
|
+
if (boolAttr("strikeH")) {
|
|
1550
|
+
b.strikeH = true;
|
|
1551
|
+
}
|
|
1552
|
+
if (boolAttr("strikeV")) {
|
|
1553
|
+
b.strikeV = true;
|
|
1554
|
+
}
|
|
1555
|
+
}
|
|
1556
|
+
result.push(b);
|
|
1557
|
+
break;
|
|
1558
|
+
}
|
|
1559
|
+
case "rad": {
|
|
1560
|
+
const radPrEl = findMathChild(child, "radPr");
|
|
1561
|
+
const deg = findMathChild(child, "deg");
|
|
1562
|
+
const e = findMathChild(child, "e");
|
|
1563
|
+
const rad = {
|
|
1564
|
+
type: "mathRadical",
|
|
1565
|
+
content: e ? parseMathContent(e) : []
|
|
1566
|
+
};
|
|
1567
|
+
if (deg) {
|
|
1568
|
+
rad.degree = parseMathContent(deg);
|
|
1569
|
+
}
|
|
1570
|
+
if (radPrEl) {
|
|
1571
|
+
const hd = findMathChild(radPrEl, "degHide");
|
|
1572
|
+
if (hd) {
|
|
1573
|
+
const v = hd.attributes["m:val"] ?? hd.attributes["val"];
|
|
1574
|
+
if (v === "1" || v === "on" || v === "true") {
|
|
1575
|
+
rad.hideDegree = true;
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
result.push(rad);
|
|
1580
|
+
break;
|
|
1581
|
+
}
|
|
1582
|
+
case "d": {
|
|
1583
|
+
const dPrEl = findMathChild(child, "dPr");
|
|
1584
|
+
const delim = { type: "mathDelimiter", content: [] };
|
|
1585
|
+
if (dPrEl) {
|
|
1586
|
+
const bc = findMathChild(dPrEl, "begChr");
|
|
1587
|
+
if (bc) {
|
|
1588
|
+
delim.beginChar = bc.attributes["m:val"] ?? bc.attributes["val"];
|
|
1589
|
+
}
|
|
1590
|
+
const ec = findMathChild(dPrEl, "endChr");
|
|
1591
|
+
if (ec) {
|
|
1592
|
+
delim.endChar = ec.attributes["m:val"] ?? ec.attributes["val"];
|
|
1593
|
+
}
|
|
1594
|
+
const sc = findMathChild(dPrEl, "sepChr");
|
|
1595
|
+
if (sc) {
|
|
1596
|
+
delim.separatorChar = sc.attributes["m:val"] ?? sc.attributes["val"];
|
|
1597
|
+
}
|
|
1598
|
+
}
|
|
1599
|
+
for (const eEl of findMathChildren(child, "e")) {
|
|
1600
|
+
delim.content.push(parseMathContent(eEl));
|
|
1601
|
+
}
|
|
1602
|
+
result.push(delim);
|
|
1603
|
+
break;
|
|
1604
|
+
}
|
|
1605
|
+
case "nary": {
|
|
1606
|
+
const nPrEl = findMathChild(child, "naryPr");
|
|
1607
|
+
const sub = findMathChild(child, "sub");
|
|
1608
|
+
const sup = findMathChild(child, "sup");
|
|
1609
|
+
const e = findMathChild(child, "e");
|
|
1610
|
+
const nary = {
|
|
1611
|
+
type: "mathNary",
|
|
1612
|
+
content: e ? parseMathContent(e) : []
|
|
1613
|
+
};
|
|
1614
|
+
if (sub) {
|
|
1615
|
+
nary.sub = parseMathContent(sub);
|
|
1616
|
+
}
|
|
1617
|
+
if (sup) {
|
|
1618
|
+
nary.sup = parseMathContent(sup);
|
|
1619
|
+
}
|
|
1620
|
+
if (nPrEl) {
|
|
1621
|
+
const chrEl = findMathChild(nPrEl, "chr");
|
|
1622
|
+
if (chrEl) {
|
|
1623
|
+
nary.char = chrEl.attributes["m:val"] ?? chrEl.attributes["val"];
|
|
1624
|
+
}
|
|
1625
|
+
const limLoc = findMathChild(nPrEl, "limLoc");
|
|
1626
|
+
if (limLoc) {
|
|
1627
|
+
nary.limitsLocation = limLoc.attributes["m:val"] ?? limLoc.attributes["val"];
|
|
1628
|
+
}
|
|
1629
|
+
const sh = findMathChild(nPrEl, "supHide");
|
|
1630
|
+
if (sh && (sh.attributes["m:val"] ?? sh.attributes["val"]) === "1") {
|
|
1631
|
+
nary.supHide = true;
|
|
1632
|
+
}
|
|
1633
|
+
const sbh = findMathChild(nPrEl, "subHide");
|
|
1634
|
+
if (sbh && (sbh.attributes["m:val"] ?? sbh.attributes["val"]) === "1") {
|
|
1635
|
+
nary.subHide = true;
|
|
1636
|
+
}
|
|
1637
|
+
}
|
|
1638
|
+
result.push(nary);
|
|
1639
|
+
break;
|
|
1640
|
+
}
|
|
1641
|
+
case "func": {
|
|
1642
|
+
const fName = findMathChild(child, "fName");
|
|
1643
|
+
const e = findMathChild(child, "e");
|
|
1644
|
+
result.push({
|
|
1645
|
+
type: "mathFunction",
|
|
1646
|
+
name: fName ? parseMathContent(fName) : [],
|
|
1647
|
+
content: e ? parseMathContent(e) : []
|
|
1648
|
+
});
|
|
1649
|
+
break;
|
|
1650
|
+
}
|
|
1651
|
+
case "limLow": {
|
|
1652
|
+
const base = findMathChild(child, "e");
|
|
1653
|
+
const lim = findMathChild(child, "lim");
|
|
1654
|
+
result.push({
|
|
1655
|
+
type: "mathLimit",
|
|
1656
|
+
limitType: "lower",
|
|
1657
|
+
base: base ? parseMathContent(base) : [],
|
|
1658
|
+
limit: lim ? parseMathContent(lim) : []
|
|
1659
|
+
});
|
|
1660
|
+
break;
|
|
1661
|
+
}
|
|
1662
|
+
case "limUpp": {
|
|
1663
|
+
const base = findMathChild(child, "e");
|
|
1664
|
+
const lim = findMathChild(child, "lim");
|
|
1665
|
+
result.push({
|
|
1666
|
+
type: "mathLimit",
|
|
1667
|
+
limitType: "upper",
|
|
1668
|
+
base: base ? parseMathContent(base) : [],
|
|
1669
|
+
limit: lim ? parseMathContent(lim) : []
|
|
1670
|
+
});
|
|
1671
|
+
break;
|
|
1672
|
+
}
|
|
1673
|
+
case "m": {
|
|
1674
|
+
// Matrix
|
|
1675
|
+
const rows = [];
|
|
1676
|
+
for (const mrEl of findMathChildren(child, "mr")) {
|
|
1677
|
+
const row = [];
|
|
1678
|
+
for (const eEl of findMathChildren(mrEl, "e")) {
|
|
1679
|
+
row.push(parseMathContent(eEl));
|
|
1680
|
+
}
|
|
1681
|
+
rows.push(row);
|
|
1682
|
+
}
|
|
1683
|
+
result.push({ type: "mathMatrix", rows });
|
|
1684
|
+
break;
|
|
1685
|
+
}
|
|
1686
|
+
case "acc": {
|
|
1687
|
+
const accPrEl = findMathChild(child, "accPr");
|
|
1688
|
+
const e = findMathChild(child, "e");
|
|
1689
|
+
const acc = {
|
|
1690
|
+
type: "mathAccent",
|
|
1691
|
+
content: e ? parseMathContent(e) : []
|
|
1692
|
+
};
|
|
1693
|
+
if (accPrEl) {
|
|
1694
|
+
const chr = findMathChild(accPrEl, "chr");
|
|
1695
|
+
if (chr) {
|
|
1696
|
+
acc.char = chr.attributes["m:val"] ?? chr.attributes["val"];
|
|
1697
|
+
}
|
|
1698
|
+
}
|
|
1699
|
+
result.push(acc);
|
|
1700
|
+
break;
|
|
1701
|
+
}
|
|
1702
|
+
case "bar": {
|
|
1703
|
+
const barPrEl = findMathChild(child, "barPr");
|
|
1704
|
+
const e = findMathChild(child, "e");
|
|
1705
|
+
let position = "top";
|
|
1706
|
+
if (barPrEl) {
|
|
1707
|
+
const pos = findMathChild(barPrEl, "pos");
|
|
1708
|
+
if (pos) {
|
|
1709
|
+
const v = pos.attributes["m:val"] ?? pos.attributes["val"];
|
|
1710
|
+
if (v === "bot") {
|
|
1711
|
+
position = "bottom";
|
|
1712
|
+
}
|
|
1713
|
+
}
|
|
1714
|
+
}
|
|
1715
|
+
result.push({
|
|
1716
|
+
type: "mathBar",
|
|
1717
|
+
position,
|
|
1718
|
+
content: e ? parseMathContent(e) : []
|
|
1719
|
+
});
|
|
1720
|
+
break;
|
|
1721
|
+
}
|
|
1722
|
+
case "box": {
|
|
1723
|
+
const e = findMathChild(child, "e");
|
|
1724
|
+
result.push({
|
|
1725
|
+
type: "mathBox",
|
|
1726
|
+
content: e ? parseMathContent(e) : []
|
|
1727
|
+
});
|
|
1728
|
+
break;
|
|
1729
|
+
}
|
|
1730
|
+
case "eqArr": {
|
|
1731
|
+
const rows = [];
|
|
1732
|
+
for (const eEl of findMathChildren(child, "e")) {
|
|
1733
|
+
rows.push(parseMathContent(eEl));
|
|
1734
|
+
}
|
|
1735
|
+
result.push({ type: "mathEquationArray", rows });
|
|
1736
|
+
break;
|
|
1737
|
+
}
|
|
1738
|
+
// Recurse into oMath elements
|
|
1739
|
+
case "oMath": {
|
|
1740
|
+
result.push(...parseMathContent(child));
|
|
1741
|
+
break;
|
|
1742
|
+
}
|
|
1743
|
+
}
|
|
1744
|
+
}
|
|
1745
|
+
return result;
|
|
1746
|
+
}
|
|
1747
|
+
function parseMathBlock(oMathParaEl) {
|
|
1748
|
+
const content = [];
|
|
1749
|
+
for (const child of oMathParaEl.children) {
|
|
1750
|
+
if (child.type === "element") {
|
|
1751
|
+
const n = child.name.replace(/^m:/, "");
|
|
1752
|
+
if (n === "oMath") {
|
|
1753
|
+
content.push(...parseMathContent(child));
|
|
1754
|
+
}
|
|
1755
|
+
}
|
|
1756
|
+
}
|
|
1757
|
+
return { type: "math", content };
|
|
1758
|
+
}
|
|
1759
|
+
// =============================================================================
|
|
1760
|
+
// TextBox Parser
|
|
1761
|
+
// =============================================================================
|
|
1762
|
+
function parseTextBox(pictEl) {
|
|
1763
|
+
// Look for v:shape > v:textbox > w:txbxContent
|
|
1764
|
+
let txbxContentEl;
|
|
1765
|
+
let shapeEl;
|
|
1766
|
+
for (const child of pictEl.children) {
|
|
1767
|
+
if (child.type === "element" && (child.name === "v:shape" || child.name === "v:rect")) {
|
|
1768
|
+
shapeEl = child;
|
|
1769
|
+
for (const sc of child.children) {
|
|
1770
|
+
if (sc.type === "element" && sc.name === "v:textbox") {
|
|
1771
|
+
for (const tc of sc.children) {
|
|
1772
|
+
if (tc.type === "element" &&
|
|
1773
|
+
(tc.name === "w:txbxContent" || tc.name === "txbxContent")) {
|
|
1774
|
+
txbxContentEl = tc;
|
|
1775
|
+
}
|
|
1776
|
+
}
|
|
1777
|
+
}
|
|
1778
|
+
}
|
|
1779
|
+
}
|
|
1780
|
+
}
|
|
1781
|
+
if (!txbxContentEl) {
|
|
1782
|
+
return undefined;
|
|
1783
|
+
}
|
|
1784
|
+
const paragraphs = [];
|
|
1785
|
+
for (const c of txbxContentEl.children) {
|
|
1786
|
+
if (c.type === "element" && c.name.replace(/^w:/, "") === "p") {
|
|
1787
|
+
paragraphs.push(parseParagraph(c));
|
|
1788
|
+
}
|
|
1789
|
+
}
|
|
1790
|
+
const tb = { type: "textBox", content: paragraphs };
|
|
1791
|
+
if (shapeEl) {
|
|
1792
|
+
const style = shapeEl.attributes["style"];
|
|
1793
|
+
if (style) {
|
|
1794
|
+
tb.style = style;
|
|
1795
|
+
}
|
|
1796
|
+
const sc = shapeEl.attributes["strokecolor"];
|
|
1797
|
+
if (sc) {
|
|
1798
|
+
tb.strokeColor = sc;
|
|
1799
|
+
}
|
|
1800
|
+
const fc = shapeEl.attributes["fillcolor"];
|
|
1801
|
+
if (fc) {
|
|
1802
|
+
tb.fillColor = fc;
|
|
1803
|
+
}
|
|
1804
|
+
if (shapeEl.attributes["stroked"] === "f") {
|
|
1805
|
+
tb.stroke = false;
|
|
1806
|
+
}
|
|
1807
|
+
if (shapeEl.attributes["filled"] === "f") {
|
|
1808
|
+
tb.fill = false;
|
|
1809
|
+
}
|
|
1810
|
+
}
|
|
1811
|
+
return tb;
|
|
1812
|
+
}
|
|
1813
|
+
// =============================================================================
|
|
1814
|
+
// SDT / CheckBox / TOC Parser
|
|
1815
|
+
// =============================================================================
|
|
1816
|
+
function parseSdt(sdtEl) {
|
|
1817
|
+
const sdtPrEl = findChildNs(sdtEl, "sdtPr");
|
|
1818
|
+
const sdtContentEl = findChildNs(sdtEl, "sdtContent");
|
|
1819
|
+
// Check for checkbox (w14:checkbox)
|
|
1820
|
+
if (sdtPrEl) {
|
|
1821
|
+
const checkBoxEl = (0, dom_1.findChild)(sdtPrEl, "w14:checkbox");
|
|
1822
|
+
if (checkBoxEl) {
|
|
1823
|
+
return parseCheckBox(checkBoxEl);
|
|
1824
|
+
}
|
|
1825
|
+
}
|
|
1826
|
+
// Check for TOC (contains docPartObj with docPartGallery "Table of Contents")
|
|
1827
|
+
if (sdtPrEl) {
|
|
1828
|
+
const docPartObjEl = findChildNs(sdtPrEl, "docPartObj");
|
|
1829
|
+
if (docPartObjEl) {
|
|
1830
|
+
const galleryEl = findChildNs(docPartObjEl, "docPartGallery");
|
|
1831
|
+
const galleryVal = galleryEl ? attrVal(galleryEl, "val") : undefined;
|
|
1832
|
+
if (galleryVal === "Table of Contents") {
|
|
1833
|
+
return parseTocFromSdt(sdtContentEl);
|
|
1834
|
+
}
|
|
1835
|
+
}
|
|
1836
|
+
}
|
|
1837
|
+
// Generic SDT
|
|
1838
|
+
const props = {};
|
|
1839
|
+
if (sdtPrEl) {
|
|
1840
|
+
const tagEl = findChildNs(sdtPrEl, "tag");
|
|
1841
|
+
if (tagEl) {
|
|
1842
|
+
props.tag = attrVal(tagEl, "val");
|
|
1843
|
+
}
|
|
1844
|
+
const aliasEl = findChildNs(sdtPrEl, "alias");
|
|
1845
|
+
if (aliasEl) {
|
|
1846
|
+
props.alias = attrVal(aliasEl, "val");
|
|
1847
|
+
}
|
|
1848
|
+
const lockEl = findChildNs(sdtPrEl, "lock");
|
|
1849
|
+
if (lockEl) {
|
|
1850
|
+
const v = attrVal(lockEl, "val");
|
|
1851
|
+
if (v === "contentLocked" || v === "sdtContentLocked") {
|
|
1852
|
+
props.lockContent = true;
|
|
1853
|
+
}
|
|
1854
|
+
if (v === "sdtLocked" || v === "sdtContentLocked") {
|
|
1855
|
+
props.lockSdt = true;
|
|
1856
|
+
}
|
|
1857
|
+
}
|
|
1858
|
+
// Plain text
|
|
1859
|
+
if (findChildNs(sdtPrEl, "text")) {
|
|
1860
|
+
props.plainText = true;
|
|
1861
|
+
}
|
|
1862
|
+
// showingPlcHdr is a toggle, not a property with a val
|
|
1863
|
+
if (findChildNs(sdtPrEl, "showingPlcHdr")) {
|
|
1864
|
+
const v = boolToggle(sdtPrEl, "showingPlcHdr");
|
|
1865
|
+
if (v !== false) {
|
|
1866
|
+
props.showingPlaceholder = true;
|
|
1867
|
+
}
|
|
1868
|
+
}
|
|
1869
|
+
// w15:appearance (replaces the old misused showingPlcHdr)
|
|
1870
|
+
const appearanceEl = (0, dom_1.findChild)(sdtPrEl, "w15:appearance");
|
|
1871
|
+
if (appearanceEl) {
|
|
1872
|
+
const v = appearanceEl.attributes["w15:val"] ?? appearanceEl.attributes["val"];
|
|
1873
|
+
if (v === "boundingBox" || v === "tags" || v === "hidden") {
|
|
1874
|
+
props.appearance = v;
|
|
1875
|
+
}
|
|
1876
|
+
}
|
|
1877
|
+
// Dropdown list
|
|
1878
|
+
const ddlEl = findChildNs(sdtPrEl, "dropDownList");
|
|
1879
|
+
if (ddlEl) {
|
|
1880
|
+
const items = [];
|
|
1881
|
+
for (const li of findChildrenNs(ddlEl, "listItem")) {
|
|
1882
|
+
const item = { value: attrVal(li, "value") ?? "" };
|
|
1883
|
+
const dt = attrVal(li, "displayText");
|
|
1884
|
+
if (dt) {
|
|
1885
|
+
item.displayText = dt;
|
|
1886
|
+
}
|
|
1887
|
+
items.push(item);
|
|
1888
|
+
}
|
|
1889
|
+
props.dropdownList = items;
|
|
1890
|
+
}
|
|
1891
|
+
// ComboBox
|
|
1892
|
+
const cbEl = findChildNs(sdtPrEl, "comboBox");
|
|
1893
|
+
if (cbEl) {
|
|
1894
|
+
const items = [];
|
|
1895
|
+
for (const li of findChildrenNs(cbEl, "listItem")) {
|
|
1896
|
+
const item = { value: attrVal(li, "value") ?? "" };
|
|
1897
|
+
const dt = attrVal(li, "displayText");
|
|
1898
|
+
if (dt) {
|
|
1899
|
+
item.displayText = dt;
|
|
1900
|
+
}
|
|
1901
|
+
items.push(item);
|
|
1902
|
+
}
|
|
1903
|
+
props.comboBox = items;
|
|
1904
|
+
}
|
|
1905
|
+
// Date picker
|
|
1906
|
+
const dateEl = findChildNs(sdtPrEl, "date");
|
|
1907
|
+
if (dateEl) {
|
|
1908
|
+
const dateProp = {};
|
|
1909
|
+
const fullDate = attrVal(dateEl, "fullDate");
|
|
1910
|
+
if (fullDate) {
|
|
1911
|
+
dateProp.fullDate = fullDate;
|
|
1912
|
+
}
|
|
1913
|
+
const dfEl = findChildNs(dateEl, "dateFormat");
|
|
1914
|
+
if (dfEl) {
|
|
1915
|
+
dateProp.dateFormat = attrVal(dfEl, "val");
|
|
1916
|
+
}
|
|
1917
|
+
const lidEl = findChildNs(dateEl, "lid");
|
|
1918
|
+
if (lidEl) {
|
|
1919
|
+
dateProp.lid = attrVal(lidEl, "val");
|
|
1920
|
+
}
|
|
1921
|
+
const storeEl = findChildNs(dateEl, "storeMappedDataAs");
|
|
1922
|
+
if (storeEl) {
|
|
1923
|
+
dateProp.storeMappedDataAs = attrVal(storeEl, "val");
|
|
1924
|
+
}
|
|
1925
|
+
props.date = dateProp;
|
|
1926
|
+
}
|
|
1927
|
+
// ID
|
|
1928
|
+
const idEl = findChildNs(sdtPrEl, "id");
|
|
1929
|
+
if (idEl) {
|
|
1930
|
+
const v = attrInt(idEl, "val");
|
|
1931
|
+
if (v !== undefined) {
|
|
1932
|
+
props.id = v;
|
|
1933
|
+
}
|
|
1934
|
+
}
|
|
1935
|
+
// Data binding
|
|
1936
|
+
const dbEl = findChildNs(sdtPrEl, "dataBinding");
|
|
1937
|
+
if (dbEl) {
|
|
1938
|
+
const xpath = attrVal(dbEl, "xpath");
|
|
1939
|
+
const storeItemId = attrVal(dbEl, "storeItemID");
|
|
1940
|
+
if (xpath && storeItemId) {
|
|
1941
|
+
const binding = { xpath, storeItemId };
|
|
1942
|
+
const prefixMappings = attrVal(dbEl, "prefixMappings");
|
|
1943
|
+
if (prefixMappings) {
|
|
1944
|
+
binding.prefixMappings = prefixMappings;
|
|
1945
|
+
}
|
|
1946
|
+
props.dataBinding = binding;
|
|
1947
|
+
}
|
|
1948
|
+
}
|
|
1949
|
+
// Placeholder
|
|
1950
|
+
const phEl = findChildNs(sdtPrEl, "placeholder");
|
|
1951
|
+
if (phEl) {
|
|
1952
|
+
const docPartEl = findChildNs(phEl, "docPart");
|
|
1953
|
+
if (docPartEl) {
|
|
1954
|
+
props.placeholder = attrVal(docPartEl, "val");
|
|
1955
|
+
}
|
|
1956
|
+
}
|
|
1957
|
+
// Boolean marker elements
|
|
1958
|
+
if (findChildNs(sdtPrEl, "richText")) {
|
|
1959
|
+
props.richText = true;
|
|
1960
|
+
}
|
|
1961
|
+
if (findChildNs(sdtPrEl, "picture")) {
|
|
1962
|
+
props.picture = true;
|
|
1963
|
+
}
|
|
1964
|
+
if (findChildNs(sdtPrEl, "group")) {
|
|
1965
|
+
props.group = true;
|
|
1966
|
+
}
|
|
1967
|
+
if (findChildNs(sdtPrEl, "equation")) {
|
|
1968
|
+
props.equation = true;
|
|
1969
|
+
}
|
|
1970
|
+
if (findChildNs(sdtPrEl, "citation")) {
|
|
1971
|
+
props.citation = true;
|
|
1972
|
+
}
|
|
1973
|
+
if (findChildNs(sdtPrEl, "bibliography")) {
|
|
1974
|
+
props.bibliography = true;
|
|
1975
|
+
}
|
|
1976
|
+
if (findChildNs(sdtPrEl, "temporary")) {
|
|
1977
|
+
props.temporary = true;
|
|
1978
|
+
}
|
|
1979
|
+
// w15: repeating section
|
|
1980
|
+
const rsEl = (0, dom_1.findChild)(sdtPrEl, "w15:repeatingSection");
|
|
1981
|
+
if (rsEl) {
|
|
1982
|
+
const rs = {};
|
|
1983
|
+
// Read from child elements (correct per schema)
|
|
1984
|
+
const titleEl = (0, dom_1.findChild)(rsEl, "w15:sectionTitle");
|
|
1985
|
+
if (titleEl) {
|
|
1986
|
+
const v = titleEl.attributes["w15:val"] ?? titleEl.attributes["val"];
|
|
1987
|
+
if (v !== undefined) {
|
|
1988
|
+
rs.sectionTitle = v;
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
if ((0, dom_1.findChild)(rsEl, "w15:doNotAllowInsertDeleteSection")) {
|
|
1992
|
+
rs.allowInsertDelete = false;
|
|
1993
|
+
}
|
|
1994
|
+
// Also accept attribute form for backwards compatibility
|
|
1995
|
+
const stAttr = rsEl.attributes["w15:sectionTitle"];
|
|
1996
|
+
if (stAttr !== undefined && rs.sectionTitle === undefined) {
|
|
1997
|
+
rs.sectionTitle = stAttr;
|
|
1998
|
+
}
|
|
1999
|
+
const noInsDelAttr = rsEl.attributes["w15:doNotAllowInsertDeleteSection"];
|
|
2000
|
+
if (noInsDelAttr !== undefined && rs.allowInsertDelete === undefined) {
|
|
2001
|
+
rs.allowInsertDelete = noInsDelAttr === "0";
|
|
2002
|
+
}
|
|
2003
|
+
props.repeatingSection = rs;
|
|
2004
|
+
}
|
|
2005
|
+
if ((0, dom_1.findChild)(sdtPrEl, "w15:repeatingSectionItem")) {
|
|
2006
|
+
props.repeatingSectionItem = true;
|
|
2007
|
+
}
|
|
2008
|
+
}
|
|
2009
|
+
const content = [];
|
|
2010
|
+
if (sdtContentEl) {
|
|
2011
|
+
for (const child of sdtContentEl.children) {
|
|
2012
|
+
if (child.type !== "element") {
|
|
2013
|
+
continue;
|
|
2014
|
+
}
|
|
2015
|
+
const n = child.name.replace(/^w:/, "");
|
|
2016
|
+
if (n === "p") {
|
|
2017
|
+
content.push(parseParagraph(child));
|
|
2018
|
+
}
|
|
2019
|
+
else if (n === "tbl") {
|
|
2020
|
+
content.push(parseTable(child));
|
|
2021
|
+
}
|
|
2022
|
+
else if (n === "r") {
|
|
2023
|
+
content.push(parseRun(child));
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
return { type: "sdt", properties: props, content };
|
|
2028
|
+
}
|
|
2029
|
+
function parseCheckBox(checkBoxEl) {
|
|
2030
|
+
const cb = { type: "checkBox" };
|
|
2031
|
+
const checkedEl = (0, dom_1.findChild)(checkBoxEl, "w14:checked");
|
|
2032
|
+
if (checkedEl) {
|
|
2033
|
+
const v = checkedEl.attributes["w14:val"] ?? checkedEl.attributes["val"];
|
|
2034
|
+
cb.checked = v === "1" || v === "true";
|
|
2035
|
+
}
|
|
2036
|
+
const checkedStateEl = (0, dom_1.findChild)(checkBoxEl, "w14:checkedState");
|
|
2037
|
+
if (checkedStateEl) {
|
|
2038
|
+
cb.checkedState = {
|
|
2039
|
+
value: checkedStateEl.attributes["w14:val"] ?? checkedStateEl.attributes["val"] ?? "",
|
|
2040
|
+
font: checkedStateEl.attributes["w14:font"] ?? checkedStateEl.attributes["font"]
|
|
2041
|
+
};
|
|
2042
|
+
}
|
|
2043
|
+
const uncheckedStateEl = (0, dom_1.findChild)(checkBoxEl, "w14:uncheckedState");
|
|
2044
|
+
if (uncheckedStateEl) {
|
|
2045
|
+
cb.uncheckedState = {
|
|
2046
|
+
value: uncheckedStateEl.attributes["w14:val"] ?? uncheckedStateEl.attributes["val"] ?? "",
|
|
2047
|
+
font: uncheckedStateEl.attributes["w14:font"] ?? uncheckedStateEl.attributes["font"]
|
|
2048
|
+
};
|
|
2049
|
+
}
|
|
2050
|
+
return cb;
|
|
2051
|
+
}
|
|
2052
|
+
function parseTocFromSdt(sdtContentEl) {
|
|
2053
|
+
const toc = { type: "tableOfContents" };
|
|
2054
|
+
const cachedParagraphs = [];
|
|
2055
|
+
if (sdtContentEl) {
|
|
2056
|
+
// Collect all instrText to assemble the complete TOC field instruction
|
|
2057
|
+
let instrText = "";
|
|
2058
|
+
const collectInstr = (el) => {
|
|
2059
|
+
for (const child of el.children) {
|
|
2060
|
+
if (child.type !== "element") {
|
|
2061
|
+
continue;
|
|
2062
|
+
}
|
|
2063
|
+
const name = child.name.replace(/^w:/, "");
|
|
2064
|
+
if (name === "instrText") {
|
|
2065
|
+
instrText += (0, dom_1.textContent)(child);
|
|
2066
|
+
}
|
|
2067
|
+
else {
|
|
2068
|
+
collectInstr(child);
|
|
2069
|
+
}
|
|
2070
|
+
}
|
|
2071
|
+
};
|
|
2072
|
+
collectInstr(sdtContentEl);
|
|
2073
|
+
if (instrText.trim()) {
|
|
2074
|
+
parseTocInstruction(instrText, toc);
|
|
2075
|
+
}
|
|
2076
|
+
for (const child of sdtContentEl.children) {
|
|
2077
|
+
if (child.type !== "element") {
|
|
2078
|
+
continue;
|
|
2079
|
+
}
|
|
2080
|
+
const n = child.name.replace(/^w:/, "");
|
|
2081
|
+
if (n === "p") {
|
|
2082
|
+
cachedParagraphs.push(parseParagraph(child));
|
|
2083
|
+
}
|
|
2084
|
+
}
|
|
2085
|
+
}
|
|
2086
|
+
if (cachedParagraphs.length > 0) {
|
|
2087
|
+
toc.cachedParagraphs = cachedParagraphs;
|
|
2088
|
+
}
|
|
2089
|
+
return toc;
|
|
2090
|
+
}
|
|
2091
|
+
/** Parse a TOC field instruction string (e.g. `TOC \o "1-3" \h \t "Style,1" \c "Figure"`). */
|
|
2092
|
+
function parseTocInstruction(instr, toc) {
|
|
2093
|
+
const trimmed = instr.trim();
|
|
2094
|
+
if (!/^TOC\b/i.test(trimmed)) {
|
|
2095
|
+
return;
|
|
2096
|
+
}
|
|
2097
|
+
// Match switches: \<letter> followed by either "quoted" or non-quoted non-switch token.
|
|
2098
|
+
// The next-switch boundary must be respected: an unquoted value cannot start with \.
|
|
2099
|
+
const switchRe = /\\(\w)(?:\s+"([^"]*)"|\s+([^\\\s][^\s]*))?/g;
|
|
2100
|
+
let match;
|
|
2101
|
+
while ((match = switchRe.exec(trimmed)) !== null) {
|
|
2102
|
+
const switchName = match[1].toLowerCase();
|
|
2103
|
+
const value = match[2] ?? match[3];
|
|
2104
|
+
switch (switchName) {
|
|
2105
|
+
case "o": // Heading level range e.g. "1-3"
|
|
2106
|
+
if (value) {
|
|
2107
|
+
toc.headingStyleRange = value;
|
|
2108
|
+
}
|
|
2109
|
+
break;
|
|
2110
|
+
case "h": // Hyperlinks
|
|
2111
|
+
toc.hyperlink = true;
|
|
2112
|
+
break;
|
|
2113
|
+
case "c": // Caption label (table of figures)
|
|
2114
|
+
if (value) {
|
|
2115
|
+
toc.captionLabel = value;
|
|
2116
|
+
}
|
|
2117
|
+
break;
|
|
2118
|
+
case "s": // Sequence field identifier
|
|
2119
|
+
if (value) {
|
|
2120
|
+
toc.sequenceFieldIdentifier = value;
|
|
2121
|
+
}
|
|
2122
|
+
break;
|
|
2123
|
+
case "p": // Page-number leader or style separator
|
|
2124
|
+
// In real TOC fields, \p is sometimes used for tab leader.
|
|
2125
|
+
// Common values: "." "-" "_"
|
|
2126
|
+
if (value === "." || value === "-" || value === "_") {
|
|
2127
|
+
toc.leader = "dot";
|
|
2128
|
+
if (value === "-") {
|
|
2129
|
+
toc.leader = "hyphen";
|
|
2130
|
+
}
|
|
2131
|
+
else if (value === "_") {
|
|
2132
|
+
toc.leader = "underscore";
|
|
2133
|
+
}
|
|
2134
|
+
}
|
|
2135
|
+
break;
|
|
2136
|
+
case "t": {
|
|
2137
|
+
// Styles with levels: "StyleName1,Level1;StyleName2,Level2;..."
|
|
2138
|
+
if (!value) {
|
|
2139
|
+
break;
|
|
2140
|
+
}
|
|
2141
|
+
const items = [];
|
|
2142
|
+
for (const part of value.split(";")) {
|
|
2143
|
+
const [styleName, levelStr] = part.split(",");
|
|
2144
|
+
if (styleName && levelStr) {
|
|
2145
|
+
items.push({ styleName: styleName.trim(), level: parseInt(levelStr, 10) });
|
|
2146
|
+
}
|
|
2147
|
+
}
|
|
2148
|
+
if (items.length > 0) {
|
|
2149
|
+
toc.stylesWithLevels = items;
|
|
2150
|
+
}
|
|
2151
|
+
break;
|
|
2152
|
+
}
|
|
2153
|
+
}
|
|
2154
|
+
}
|
|
2155
|
+
}
|
|
2156
|
+
// =============================================================================
|
|
2157
|
+
// Paragraph Parser
|
|
2158
|
+
// =============================================================================
|
|
2159
|
+
function parseRun(el) {
|
|
2160
|
+
const rPrEl = findChildNs(el, "rPr");
|
|
2161
|
+
return {
|
|
2162
|
+
properties: rPrEl ? parseRunProperties(rPrEl) : undefined,
|
|
2163
|
+
content: parseRunContent(el)
|
|
2164
|
+
};
|
|
2165
|
+
}
|
|
2166
|
+
function parseParagraph(pEl) {
|
|
2167
|
+
const pPrEl = findChildNs(pEl, "pPr");
|
|
2168
|
+
const children = [];
|
|
2169
|
+
// fldChar state machine: tracks field code assembly across runs
|
|
2170
|
+
let fieldState = "none";
|
|
2171
|
+
let fieldInstr = "";
|
|
2172
|
+
let fieldCached = "";
|
|
2173
|
+
let fieldRunProps;
|
|
2174
|
+
let fieldFormField;
|
|
2175
|
+
for (const child of pEl.children) {
|
|
2176
|
+
if (child.type !== "element") {
|
|
2177
|
+
continue;
|
|
2178
|
+
}
|
|
2179
|
+
// Handle mc:AlternateContent — pick mc:Choice, fall back to mc:Fallback
|
|
2180
|
+
let resolved = child;
|
|
2181
|
+
if (child.name === "mc:AlternateContent") {
|
|
2182
|
+
const choice = (0, dom_1.findChild)(child, "mc:Choice");
|
|
2183
|
+
const fallback = (0, dom_1.findChild)(child, "mc:Fallback");
|
|
2184
|
+
const chosen = choice ?? fallback;
|
|
2185
|
+
if (chosen && chosen.children.length > 0) {
|
|
2186
|
+
// The first element child inside Choice/Fallback is the real element
|
|
2187
|
+
const inner = chosen.children.find(c => c.type === "element");
|
|
2188
|
+
if (inner) {
|
|
2189
|
+
resolved = inner;
|
|
2190
|
+
}
|
|
2191
|
+
else {
|
|
2192
|
+
continue;
|
|
2193
|
+
}
|
|
2194
|
+
}
|
|
2195
|
+
else {
|
|
2196
|
+
continue;
|
|
2197
|
+
}
|
|
2198
|
+
}
|
|
2199
|
+
const name = resolved.name.replace(/^w:/, "");
|
|
2200
|
+
switch (name) {
|
|
2201
|
+
case "r": {
|
|
2202
|
+
// Check for fldChar and instrText inside the run
|
|
2203
|
+
let hasFldChar = false;
|
|
2204
|
+
for (const rc of resolved.children) {
|
|
2205
|
+
if (rc.type !== "element") {
|
|
2206
|
+
continue;
|
|
2207
|
+
}
|
|
2208
|
+
const rcName = rc.name.replace(/^w:/, "");
|
|
2209
|
+
if (rcName === "fldChar") {
|
|
2210
|
+
hasFldChar = true;
|
|
2211
|
+
const fldCharType = attrVal(rc, "fldCharType");
|
|
2212
|
+
if (fldCharType === "begin") {
|
|
2213
|
+
fieldState = "instrText";
|
|
2214
|
+
fieldInstr = "";
|
|
2215
|
+
fieldCached = "";
|
|
2216
|
+
// Capture run properties from this run for the field
|
|
2217
|
+
const rPrEl = findChildNs(resolved, "rPr");
|
|
2218
|
+
fieldRunProps = rPrEl ? parseRunProperties(rPrEl) : undefined;
|
|
2219
|
+
// Parse ffData for legacy form fields
|
|
2220
|
+
const ffDataEl = findChildNs(rc, "ffData");
|
|
2221
|
+
if (ffDataEl) {
|
|
2222
|
+
fieldFormField = parseFfData(ffDataEl);
|
|
2223
|
+
}
|
|
2224
|
+
else {
|
|
2225
|
+
fieldFormField = undefined;
|
|
2226
|
+
}
|
|
2227
|
+
}
|
|
2228
|
+
else if (fldCharType === "separate") {
|
|
2229
|
+
fieldState = "cached";
|
|
2230
|
+
}
|
|
2231
|
+
else if (fldCharType === "end") {
|
|
2232
|
+
// Emit the assembled field as a Run with FieldContent
|
|
2233
|
+
const fc = {
|
|
2234
|
+
type: "field",
|
|
2235
|
+
instruction: fieldInstr.trim(),
|
|
2236
|
+
cachedValue: fieldCached || undefined,
|
|
2237
|
+
formField: fieldFormField
|
|
2238
|
+
};
|
|
2239
|
+
children.push({
|
|
2240
|
+
properties: fieldRunProps,
|
|
2241
|
+
content: [fc]
|
|
2242
|
+
});
|
|
2243
|
+
fieldState = "none";
|
|
2244
|
+
fieldInstr = "";
|
|
2245
|
+
fieldCached = "";
|
|
2246
|
+
fieldRunProps = undefined;
|
|
2247
|
+
}
|
|
2248
|
+
}
|
|
2249
|
+
else if (rcName === "instrText" && fieldState === "instrText") {
|
|
2250
|
+
hasFldChar = true;
|
|
2251
|
+
fieldInstr += (0, dom_1.textContent)(rc);
|
|
2252
|
+
}
|
|
2253
|
+
}
|
|
2254
|
+
if (fieldState === "cached") {
|
|
2255
|
+
// Collect cached text from this run
|
|
2256
|
+
for (const rc of resolved.children) {
|
|
2257
|
+
if (rc.type !== "element") {
|
|
2258
|
+
continue;
|
|
2259
|
+
}
|
|
2260
|
+
const rcName = rc.name.replace(/^w:/, "");
|
|
2261
|
+
if (rcName === "t") {
|
|
2262
|
+
fieldCached += (0, dom_1.textContent)(rc);
|
|
2263
|
+
}
|
|
2264
|
+
else if (rcName === "fldChar") {
|
|
2265
|
+
// Already handled above
|
|
2266
|
+
}
|
|
2267
|
+
}
|
|
2268
|
+
if (!hasFldChar) {
|
|
2269
|
+
continue; // Skip adding this run normally
|
|
2270
|
+
}
|
|
2271
|
+
}
|
|
2272
|
+
if (fieldState === "instrText" && hasFldChar) {
|
|
2273
|
+
continue; // Don't add begin/instrText runs as normal content
|
|
2274
|
+
}
|
|
2275
|
+
if (fieldState === "none" && !hasFldChar) {
|
|
2276
|
+
children.push(parseRun(resolved));
|
|
2277
|
+
}
|
|
2278
|
+
break;
|
|
2279
|
+
}
|
|
2280
|
+
case "fldSimple": {
|
|
2281
|
+
// Simple field: <w:fldSimple w:instr=" PAGE "><w:r>...</w:r></w:fldSimple>
|
|
2282
|
+
const instr = attrVal(resolved, "instr") ?? "";
|
|
2283
|
+
let cached = "";
|
|
2284
|
+
for (const fc of resolved.children) {
|
|
2285
|
+
if (fc.type === "element" && fc.name.replace(/^w:/, "") === "r") {
|
|
2286
|
+
for (const rc of fc.children) {
|
|
2287
|
+
if (rc.type === "element" && rc.name.replace(/^w:/, "") === "t") {
|
|
2288
|
+
cached += (0, dom_1.textContent)(rc);
|
|
2289
|
+
}
|
|
2290
|
+
}
|
|
2291
|
+
}
|
|
2292
|
+
}
|
|
2293
|
+
const fc = {
|
|
2294
|
+
type: "field",
|
|
2295
|
+
instruction: instr.trim(),
|
|
2296
|
+
cachedValue: cached || undefined
|
|
2297
|
+
};
|
|
2298
|
+
children.push({
|
|
2299
|
+
properties: undefined,
|
|
2300
|
+
content: [fc]
|
|
2301
|
+
});
|
|
2302
|
+
break;
|
|
2303
|
+
}
|
|
2304
|
+
case "hyperlink": {
|
|
2305
|
+
const rId = resolved.attributes["r:id"];
|
|
2306
|
+
const anchor = resolved.attributes["w:anchor"] ?? resolved.attributes["anchor"];
|
|
2307
|
+
const tooltip = resolved.attributes["w:tooltip"] ?? resolved.attributes["tooltip"];
|
|
2308
|
+
const historyAttr = resolved.attributes["w:history"] ?? resolved.attributes["history"];
|
|
2309
|
+
const tgtFrame = resolved.attributes["w:tgtFrame"] ?? resolved.attributes["tgtFrame"];
|
|
2310
|
+
const docLocation = resolved.attributes["w:docLocation"] ?? resolved.attributes["docLocation"];
|
|
2311
|
+
const hRuns = [];
|
|
2312
|
+
for (const hChild of resolved.children) {
|
|
2313
|
+
if (hChild.type === "element" && hChild.name.replace(/^w:/, "") === "r") {
|
|
2314
|
+
hRuns.push(parseRun(hChild));
|
|
2315
|
+
}
|
|
2316
|
+
}
|
|
2317
|
+
// Resolve URL from relMap
|
|
2318
|
+
let url;
|
|
2319
|
+
if (rId) {
|
|
2320
|
+
const rel = _parseRelMap.get(rId);
|
|
2321
|
+
if (rel && rel.targetMode === "External") {
|
|
2322
|
+
url = rel.target;
|
|
2323
|
+
}
|
|
2324
|
+
}
|
|
2325
|
+
const hyperlink = {
|
|
2326
|
+
type: "hyperlink",
|
|
2327
|
+
rId,
|
|
2328
|
+
anchor,
|
|
2329
|
+
url,
|
|
2330
|
+
tooltip,
|
|
2331
|
+
children: hRuns
|
|
2332
|
+
};
|
|
2333
|
+
if (historyAttr === "1" || historyAttr === "true") {
|
|
2334
|
+
hyperlink.history = true;
|
|
2335
|
+
}
|
|
2336
|
+
if (tgtFrame) {
|
|
2337
|
+
hyperlink.tgtFrame = tgtFrame;
|
|
2338
|
+
}
|
|
2339
|
+
if (docLocation) {
|
|
2340
|
+
hyperlink.docLocation = docLocation;
|
|
2341
|
+
}
|
|
2342
|
+
children.push(hyperlink);
|
|
2343
|
+
break;
|
|
2344
|
+
}
|
|
2345
|
+
case "bookmarkStart": {
|
|
2346
|
+
const bm = {
|
|
2347
|
+
type: "bookmarkStart",
|
|
2348
|
+
id: parseInt(resolved.attributes["w:id"] ?? resolved.attributes["id"] ?? "0", 10),
|
|
2349
|
+
name: resolved.attributes["w:name"] ?? resolved.attributes["name"] ?? ""
|
|
2350
|
+
};
|
|
2351
|
+
const colFirst = resolved.attributes["w:colFirst"] ?? resolved.attributes["colFirst"];
|
|
2352
|
+
if (colFirst !== undefined) {
|
|
2353
|
+
bm.colFirst = parseInt(colFirst, 10);
|
|
2354
|
+
}
|
|
2355
|
+
const colLast = resolved.attributes["w:colLast"] ?? resolved.attributes["colLast"];
|
|
2356
|
+
if (colLast !== undefined) {
|
|
2357
|
+
bm.colLast = parseInt(colLast, 10);
|
|
2358
|
+
}
|
|
2359
|
+
const dcx = resolved.attributes["w:displacedByCustomXml"] ??
|
|
2360
|
+
resolved.attributes["displacedByCustomXml"];
|
|
2361
|
+
if (dcx === "next" || dcx === "prev") {
|
|
2362
|
+
bm.displacedByCustomXml = dcx;
|
|
2363
|
+
}
|
|
2364
|
+
children.push(bm);
|
|
2365
|
+
break;
|
|
2366
|
+
}
|
|
2367
|
+
case "bookmarkEnd":
|
|
2368
|
+
children.push({
|
|
2369
|
+
type: "bookmarkEnd",
|
|
2370
|
+
id: parseInt(resolved.attributes["w:id"] ?? resolved.attributes["id"] ?? "0", 10)
|
|
2371
|
+
});
|
|
2372
|
+
break;
|
|
2373
|
+
case "commentRangeStart":
|
|
2374
|
+
children.push({
|
|
2375
|
+
type: "commentRangeStart",
|
|
2376
|
+
id: parseInt(resolved.attributes["w:id"] ?? resolved.attributes["id"] ?? "0", 10)
|
|
2377
|
+
});
|
|
2378
|
+
break;
|
|
2379
|
+
case "commentRangeEnd":
|
|
2380
|
+
children.push({
|
|
2381
|
+
type: "commentRangeEnd",
|
|
2382
|
+
id: parseInt(resolved.attributes["w:id"] ?? resolved.attributes["id"] ?? "0", 10)
|
|
2383
|
+
});
|
|
2384
|
+
break;
|
|
2385
|
+
case "commentReference":
|
|
2386
|
+
children.push({
|
|
2387
|
+
type: "commentReference",
|
|
2388
|
+
id: parseInt(resolved.attributes["w:id"] ?? resolved.attributes["id"] ?? "0", 10)
|
|
2389
|
+
});
|
|
2390
|
+
break;
|
|
2391
|
+
case "ins": {
|
|
2392
|
+
// Inserted run (track changes)
|
|
2393
|
+
const rev = parseRevisionInfo(resolved);
|
|
2394
|
+
if (rev) {
|
|
2395
|
+
for (const insChild of resolved.children) {
|
|
2396
|
+
if (insChild.type === "element" && insChild.name.replace(/^w:/, "") === "r") {
|
|
2397
|
+
children.push({
|
|
2398
|
+
type: "insertedRun",
|
|
2399
|
+
revision: rev,
|
|
2400
|
+
run: parseRun(insChild)
|
|
2401
|
+
});
|
|
2402
|
+
}
|
|
2403
|
+
}
|
|
2404
|
+
}
|
|
2405
|
+
break;
|
|
2406
|
+
}
|
|
2407
|
+
case "del": {
|
|
2408
|
+
// Deleted run (track changes)
|
|
2409
|
+
const rev = parseRevisionInfo(resolved);
|
|
2410
|
+
if (rev) {
|
|
2411
|
+
for (const delChild of resolved.children) {
|
|
2412
|
+
if (delChild.type === "element" && delChild.name.replace(/^w:/, "") === "r") {
|
|
2413
|
+
children.push({
|
|
2414
|
+
type: "deletedRun",
|
|
2415
|
+
revision: rev,
|
|
2416
|
+
run: parseDeletedRun(delChild)
|
|
2417
|
+
});
|
|
2418
|
+
}
|
|
2419
|
+
}
|
|
2420
|
+
}
|
|
2421
|
+
break;
|
|
2422
|
+
}
|
|
2423
|
+
case "moveFrom": {
|
|
2424
|
+
const rev = parseRevisionInfo(resolved);
|
|
2425
|
+
if (rev) {
|
|
2426
|
+
for (const mfChild of resolved.children) {
|
|
2427
|
+
if (mfChild.type === "element" && mfChild.name.replace(/^w:/, "") === "r") {
|
|
2428
|
+
children.push({
|
|
2429
|
+
type: "movedFromRun",
|
|
2430
|
+
revision: rev,
|
|
2431
|
+
run: parseRun(mfChild)
|
|
2432
|
+
});
|
|
2433
|
+
}
|
|
2434
|
+
}
|
|
2435
|
+
}
|
|
2436
|
+
break;
|
|
2437
|
+
}
|
|
2438
|
+
case "moveTo": {
|
|
2439
|
+
const rev = parseRevisionInfo(resolved);
|
|
2440
|
+
if (rev) {
|
|
2441
|
+
for (const mtChild of resolved.children) {
|
|
2442
|
+
if (mtChild.type === "element" && mtChild.name.replace(/^w:/, "") === "r") {
|
|
2443
|
+
children.push({
|
|
2444
|
+
type: "movedToRun",
|
|
2445
|
+
revision: rev,
|
|
2446
|
+
run: parseRun(mtChild)
|
|
2447
|
+
});
|
|
2448
|
+
}
|
|
2449
|
+
}
|
|
2450
|
+
}
|
|
2451
|
+
break;
|
|
2452
|
+
}
|
|
2453
|
+
case "moveFromRangeStart":
|
|
2454
|
+
case "moveFromRangeEnd":
|
|
2455
|
+
case "moveToRangeStart":
|
|
2456
|
+
case "moveToRangeEnd": {
|
|
2457
|
+
const id = attrInt(resolved, "id");
|
|
2458
|
+
if (id !== undefined) {
|
|
2459
|
+
const marker = {
|
|
2460
|
+
type: name,
|
|
2461
|
+
id
|
|
2462
|
+
};
|
|
2463
|
+
const author = attrVal(resolved, "author");
|
|
2464
|
+
if (author) {
|
|
2465
|
+
marker.author = author;
|
|
2466
|
+
}
|
|
2467
|
+
const date = attrVal(resolved, "date");
|
|
2468
|
+
if (date) {
|
|
2469
|
+
marker.date = date;
|
|
2470
|
+
}
|
|
2471
|
+
const mName = attrVal(resolved, "name");
|
|
2472
|
+
if (mName) {
|
|
2473
|
+
marker.name = mName;
|
|
2474
|
+
}
|
|
2475
|
+
children.push(marker);
|
|
2476
|
+
}
|
|
2477
|
+
break;
|
|
2478
|
+
}
|
|
2479
|
+
case "customXmlInsRangeStart":
|
|
2480
|
+
case "customXmlInsRangeEnd":
|
|
2481
|
+
case "customXmlDelRangeStart":
|
|
2482
|
+
case "customXmlDelRangeEnd":
|
|
2483
|
+
case "customXmlMoveFromRangeStart":
|
|
2484
|
+
case "customXmlMoveFromRangeEnd":
|
|
2485
|
+
case "customXmlMoveToRangeStart":
|
|
2486
|
+
case "customXmlMoveToRangeEnd": {
|
|
2487
|
+
const id = attrInt(resolved, "id");
|
|
2488
|
+
if (id !== undefined) {
|
|
2489
|
+
const marker = { type: name, id };
|
|
2490
|
+
const author = attrVal(resolved, "author");
|
|
2491
|
+
if (author) {
|
|
2492
|
+
marker.author = author;
|
|
2493
|
+
}
|
|
2494
|
+
const date = attrVal(resolved, "date");
|
|
2495
|
+
if (date) {
|
|
2496
|
+
marker.date = date;
|
|
2497
|
+
}
|
|
2498
|
+
children.push(marker);
|
|
2499
|
+
}
|
|
2500
|
+
break;
|
|
2501
|
+
}
|
|
2502
|
+
case "smartTag":
|
|
2503
|
+
case "customXml":
|
|
2504
|
+
case "dir": {
|
|
2505
|
+
// Semantic wrappers: flatten their children into the current paragraph.
|
|
2506
|
+
// A smartTag/customXml/dir can contain runs, hyperlinks, nested wrappers, etc.
|
|
2507
|
+
// Re-use parseParagraph to recursively parse the contained children.
|
|
2508
|
+
const subPara = parseParagraph(resolved);
|
|
2509
|
+
for (const sub of subPara.children) {
|
|
2510
|
+
children.push(sub);
|
|
2511
|
+
}
|
|
2512
|
+
break;
|
|
2513
|
+
}
|
|
2514
|
+
case "proofErr":
|
|
2515
|
+
case "permStart":
|
|
2516
|
+
case "permEnd":
|
|
2517
|
+
case "lastRenderedPageBreak":
|
|
2518
|
+
// Non-semantic markers; safely ignored
|
|
2519
|
+
break;
|
|
2520
|
+
}
|
|
2521
|
+
}
|
|
2522
|
+
const paraId = pEl.attributes["w14:paraId"];
|
|
2523
|
+
const textId = pEl.attributes["w14:textId"];
|
|
2524
|
+
const result = {
|
|
2525
|
+
type: "paragraph",
|
|
2526
|
+
properties: pPrEl ? parseParagraphProperties(pPrEl) : undefined,
|
|
2527
|
+
children
|
|
2528
|
+
};
|
|
2529
|
+
if (paraId) {
|
|
2530
|
+
result.paraId = paraId;
|
|
2531
|
+
}
|
|
2532
|
+
if (textId) {
|
|
2533
|
+
result.textId = textId;
|
|
2534
|
+
}
|
|
2535
|
+
return result;
|
|
2536
|
+
}
|
|
2537
|
+
/** Parse a deleted run (w:delText instead of w:t). */
|
|
2538
|
+
function parseDeletedRun(el) {
|
|
2539
|
+
const rPrEl = findChildNs(el, "rPr");
|
|
2540
|
+
const content = [];
|
|
2541
|
+
for (const child of el.children) {
|
|
2542
|
+
if (child.type !== "element") {
|
|
2543
|
+
continue;
|
|
2544
|
+
}
|
|
2545
|
+
const name = child.name.replace(/^w:/, "");
|
|
2546
|
+
if (name === "delText") {
|
|
2547
|
+
content.push({ type: "text", text: (0, dom_1.textContent)(child) });
|
|
2548
|
+
}
|
|
2549
|
+
else if (name === "t") {
|
|
2550
|
+
content.push({ type: "text", text: (0, dom_1.textContent)(child) });
|
|
2551
|
+
}
|
|
2552
|
+
else if (name === "br") {
|
|
2553
|
+
content.push({ type: "break", breakType: attrVal(child, "type") });
|
|
2554
|
+
}
|
|
2555
|
+
else if (name === "tab") {
|
|
2556
|
+
content.push({ type: "tab" });
|
|
2557
|
+
}
|
|
2558
|
+
}
|
|
2559
|
+
return {
|
|
2560
|
+
properties: rPrEl ? parseRunProperties(rPrEl) : undefined,
|
|
2561
|
+
content
|
|
2562
|
+
};
|
|
2563
|
+
}
|
|
2564
|
+
// =============================================================================
|
|
2565
|
+
// Table Parser
|
|
2566
|
+
// =============================================================================
|
|
2567
|
+
function parseTableBorders(el) {
|
|
2568
|
+
const borders = {};
|
|
2569
|
+
for (const side of [
|
|
2570
|
+
"top",
|
|
2571
|
+
"left",
|
|
2572
|
+
"bottom",
|
|
2573
|
+
"right",
|
|
2574
|
+
"insideH",
|
|
2575
|
+
"insideV",
|
|
2576
|
+
"start",
|
|
2577
|
+
"end",
|
|
2578
|
+
"tl2br",
|
|
2579
|
+
"tr2bl"
|
|
2580
|
+
]) {
|
|
2581
|
+
const sideEl = findChildNs(el, side);
|
|
2582
|
+
if (sideEl) {
|
|
2583
|
+
borders[side] = parseBorder(sideEl);
|
|
2584
|
+
}
|
|
2585
|
+
}
|
|
2586
|
+
return borders;
|
|
2587
|
+
}
|
|
2588
|
+
function parseTableCellMargins(el) {
|
|
2589
|
+
const margins = {};
|
|
2590
|
+
for (const side of ["top", "left", "bottom", "right", "start", "end"]) {
|
|
2591
|
+
const sideEl = findChildNs(el, side);
|
|
2592
|
+
if (sideEl) {
|
|
2593
|
+
margins[side] = parseTableWidth(sideEl);
|
|
2594
|
+
}
|
|
2595
|
+
}
|
|
2596
|
+
return margins;
|
|
2597
|
+
}
|
|
2598
|
+
function parseTableProperties(el) {
|
|
2599
|
+
const props = {};
|
|
2600
|
+
const styleEl = findChildNs(el, "tblStyle");
|
|
2601
|
+
if (styleEl) {
|
|
2602
|
+
props.style = attrVal(styleEl, "val");
|
|
2603
|
+
}
|
|
2604
|
+
const wEl = findChildNs(el, "tblW");
|
|
2605
|
+
if (wEl) {
|
|
2606
|
+
props.width = parseTableWidth(wEl);
|
|
2607
|
+
}
|
|
2608
|
+
const jcEl = findChildNs(el, "jc");
|
|
2609
|
+
if (jcEl) {
|
|
2610
|
+
props.alignment = attrVal(jcEl, "val");
|
|
2611
|
+
}
|
|
2612
|
+
const indEl = findChildNs(el, "tblInd");
|
|
2613
|
+
if (indEl) {
|
|
2614
|
+
props.indent = parseInt(indEl.attributes["w:w"] ?? indEl.attributes["w"] ?? "0", 10);
|
|
2615
|
+
}
|
|
2616
|
+
const bordersEl = findChildNs(el, "tblBorders");
|
|
2617
|
+
if (bordersEl) {
|
|
2618
|
+
props.borders = parseTableBorders(bordersEl);
|
|
2619
|
+
}
|
|
2620
|
+
const layoutEl = findChildNs(el, "tblLayout");
|
|
2621
|
+
if (layoutEl) {
|
|
2622
|
+
props.layout = attrVal(layoutEl, "type");
|
|
2623
|
+
}
|
|
2624
|
+
const cellMarEl = findChildNs(el, "tblCellMar");
|
|
2625
|
+
if (cellMarEl) {
|
|
2626
|
+
props.cellMargins = parseTableCellMargins(cellMarEl);
|
|
2627
|
+
}
|
|
2628
|
+
// TableLook
|
|
2629
|
+
const lookEl = findChildNs(el, "tblLook");
|
|
2630
|
+
if (lookEl) {
|
|
2631
|
+
const look = {};
|
|
2632
|
+
// Read individual attributes first (authoritative when explicit "0"/"1")
|
|
2633
|
+
const readFlag = (name) => {
|
|
2634
|
+
const v = attrVal(lookEl, name);
|
|
2635
|
+
if (v === "1" || v === "true") {
|
|
2636
|
+
return true;
|
|
2637
|
+
}
|
|
2638
|
+
if (v === "0" || v === "false") {
|
|
2639
|
+
return false;
|
|
2640
|
+
}
|
|
2641
|
+
return undefined;
|
|
2642
|
+
};
|
|
2643
|
+
const firstRow = readFlag("firstRow");
|
|
2644
|
+
const lastRow = readFlag("lastRow");
|
|
2645
|
+
const firstColumn = readFlag("firstColumn");
|
|
2646
|
+
const lastColumn = readFlag("lastColumn");
|
|
2647
|
+
const noHBand = readFlag("noHBand");
|
|
2648
|
+
const noVBand = readFlag("noVBand");
|
|
2649
|
+
if (firstRow !== undefined) {
|
|
2650
|
+
look.firstRow = firstRow;
|
|
2651
|
+
}
|
|
2652
|
+
if (lastRow !== undefined) {
|
|
2653
|
+
look.lastRow = lastRow;
|
|
2654
|
+
}
|
|
2655
|
+
if (firstColumn !== undefined) {
|
|
2656
|
+
look.firstColumn = firstColumn;
|
|
2657
|
+
}
|
|
2658
|
+
if (lastColumn !== undefined) {
|
|
2659
|
+
look.lastColumn = lastColumn;
|
|
2660
|
+
}
|
|
2661
|
+
if (noHBand !== undefined) {
|
|
2662
|
+
look.noHBand = noHBand;
|
|
2663
|
+
}
|
|
2664
|
+
if (noVBand !== undefined) {
|
|
2665
|
+
look.noVBand = noVBand;
|
|
2666
|
+
}
|
|
2667
|
+
// Fall back to w:val bitmask ONLY if no individual attrs were specified
|
|
2668
|
+
if (Object.keys(look).length === 0) {
|
|
2669
|
+
const val = attrVal(lookEl, "val");
|
|
2670
|
+
if (val) {
|
|
2671
|
+
const v = parseInt(val, 16);
|
|
2672
|
+
if (v & 0x0020) {
|
|
2673
|
+
look.firstRow = true;
|
|
2674
|
+
}
|
|
2675
|
+
if (v & 0x0040) {
|
|
2676
|
+
look.lastRow = true;
|
|
2677
|
+
}
|
|
2678
|
+
if (v & 0x0080) {
|
|
2679
|
+
look.firstColumn = true;
|
|
2680
|
+
}
|
|
2681
|
+
if (v & 0x0100) {
|
|
2682
|
+
look.lastColumn = true;
|
|
2683
|
+
}
|
|
2684
|
+
if (v & 0x0200) {
|
|
2685
|
+
look.noHBand = true;
|
|
2686
|
+
}
|
|
2687
|
+
if (v & 0x0400) {
|
|
2688
|
+
look.noVBand = true;
|
|
2689
|
+
}
|
|
2690
|
+
}
|
|
2691
|
+
}
|
|
2692
|
+
if (Object.keys(look).length > 0) {
|
|
2693
|
+
props.look = look;
|
|
2694
|
+
}
|
|
2695
|
+
}
|
|
2696
|
+
// TableFloat
|
|
2697
|
+
const tblpPrEl = findChildNs(el, "tblpPr");
|
|
2698
|
+
if (tblpPrEl) {
|
|
2699
|
+
const tf = {};
|
|
2700
|
+
const f = tf;
|
|
2701
|
+
const hAnchor = attrVal(tblpPrEl, "horzAnchor");
|
|
2702
|
+
if (hAnchor) {
|
|
2703
|
+
f.horizontalAnchor = hAnchor;
|
|
2704
|
+
}
|
|
2705
|
+
const vAnchor = attrVal(tblpPrEl, "vertAnchor");
|
|
2706
|
+
if (vAnchor) {
|
|
2707
|
+
f.verticalAnchor = vAnchor;
|
|
2708
|
+
}
|
|
2709
|
+
const tblpX = attrInt(tblpPrEl, "tblpX");
|
|
2710
|
+
if (tblpX !== undefined) {
|
|
2711
|
+
f.absoluteHorizontalPosition = tblpX;
|
|
2712
|
+
}
|
|
2713
|
+
const tblpY = attrInt(tblpPrEl, "tblpY");
|
|
2714
|
+
if (tblpY !== undefined) {
|
|
2715
|
+
f.absoluteVerticalPosition = tblpY;
|
|
2716
|
+
}
|
|
2717
|
+
const tblpXSpec = attrVal(tblpPrEl, "tblpXSpec");
|
|
2718
|
+
if (tblpXSpec) {
|
|
2719
|
+
f.relativeHorizontalPosition = tblpXSpec;
|
|
2720
|
+
}
|
|
2721
|
+
const tblpYSpec = attrVal(tblpPrEl, "tblpYSpec");
|
|
2722
|
+
if (tblpYSpec) {
|
|
2723
|
+
f.relativeVerticalPosition = tblpYSpec;
|
|
2724
|
+
}
|
|
2725
|
+
const topFromText = attrInt(tblpPrEl, "topFromText");
|
|
2726
|
+
if (topFromText !== undefined) {
|
|
2727
|
+
f.topFromText = topFromText;
|
|
2728
|
+
}
|
|
2729
|
+
const bottomFromText = attrInt(tblpPrEl, "bottomFromText");
|
|
2730
|
+
if (bottomFromText !== undefined) {
|
|
2731
|
+
f.bottomFromText = bottomFromText;
|
|
2732
|
+
}
|
|
2733
|
+
const leftFromText = attrInt(tblpPrEl, "leftFromText");
|
|
2734
|
+
if (leftFromText !== undefined) {
|
|
2735
|
+
f.leftFromText = leftFromText;
|
|
2736
|
+
}
|
|
2737
|
+
const rightFromText = attrInt(tblpPrEl, "rightFromText");
|
|
2738
|
+
if (rightFromText !== undefined) {
|
|
2739
|
+
f.rightFromText = rightFromText;
|
|
2740
|
+
}
|
|
2741
|
+
const overlap = attrVal(tblpPrEl, "overlap");
|
|
2742
|
+
if (overlap) {
|
|
2743
|
+
f.overlap = overlap;
|
|
2744
|
+
}
|
|
2745
|
+
props.float = tf;
|
|
2746
|
+
}
|
|
2747
|
+
// w:tblOverlap is a separate sibling element of w:tblpPr (value "never"|"overlap")
|
|
2748
|
+
const tblOverlapEl = findChildNs(el, "tblOverlap");
|
|
2749
|
+
if (tblOverlapEl && props.float) {
|
|
2750
|
+
const v = attrVal(tblOverlapEl, "val");
|
|
2751
|
+
if (v === "never" || v === "overlap") {
|
|
2752
|
+
props.float.overlap = v;
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
// Cell spacing
|
|
2756
|
+
const csEl = findChildNs(el, "tblCellSpacing");
|
|
2757
|
+
if (csEl) {
|
|
2758
|
+
props.cellSpacing = parseTableWidth(csEl);
|
|
2759
|
+
}
|
|
2760
|
+
// Bidi visual
|
|
2761
|
+
if (findChildNs(el, "bidiVisual")) {
|
|
2762
|
+
props.visuallyRightToLeft = true;
|
|
2763
|
+
}
|
|
2764
|
+
// Shading
|
|
2765
|
+
const shdEl = findChildNs(el, "shd");
|
|
2766
|
+
if (shdEl) {
|
|
2767
|
+
props.shading = parseShading(shdEl);
|
|
2768
|
+
}
|
|
2769
|
+
// Accessibility: caption and description
|
|
2770
|
+
const captionEl = findChildNs(el, "tblCaption");
|
|
2771
|
+
if (captionEl) {
|
|
2772
|
+
props.caption = attrVal(captionEl, "val");
|
|
2773
|
+
}
|
|
2774
|
+
const descEl = findChildNs(el, "tblDescription");
|
|
2775
|
+
if (descEl) {
|
|
2776
|
+
props.description = attrVal(descEl, "val");
|
|
2777
|
+
}
|
|
2778
|
+
// Table property change
|
|
2779
|
+
const tblPrChangeEl = findChildNs(el, "tblPrChange");
|
|
2780
|
+
if (tblPrChangeEl) {
|
|
2781
|
+
const rev = parseRevisionInfo(tblPrChangeEl);
|
|
2782
|
+
if (rev) {
|
|
2783
|
+
const prev = findChildNs(tblPrChangeEl, "tblPr");
|
|
2784
|
+
props.propertyChange = {
|
|
2785
|
+
revision: rev,
|
|
2786
|
+
previousProperties: prev ? parseTableProperties(prev) : undefined
|
|
2787
|
+
};
|
|
2788
|
+
}
|
|
2789
|
+
}
|
|
2790
|
+
return props;
|
|
2791
|
+
}
|
|
2792
|
+
function parseTableCell(el) {
|
|
2793
|
+
const tcPrEl = findChildNs(el, "tcPr");
|
|
2794
|
+
const content = [];
|
|
2795
|
+
for (const child of el.children) {
|
|
2796
|
+
if (child.type !== "element") {
|
|
2797
|
+
continue;
|
|
2798
|
+
}
|
|
2799
|
+
const name = child.name.replace(/^w:/, "");
|
|
2800
|
+
if (name === "p") {
|
|
2801
|
+
content.push(parseParagraph(child));
|
|
2802
|
+
}
|
|
2803
|
+
else if (name === "tbl") {
|
|
2804
|
+
content.push(parseTable(child));
|
|
2805
|
+
}
|
|
2806
|
+
}
|
|
2807
|
+
let props;
|
|
2808
|
+
if (tcPrEl) {
|
|
2809
|
+
const p = {};
|
|
2810
|
+
const wEl = findChildNs(tcPrEl, "tcW");
|
|
2811
|
+
if (wEl) {
|
|
2812
|
+
p.width = parseTableWidth(wEl);
|
|
2813
|
+
}
|
|
2814
|
+
const gsEl = findChildNs(tcPrEl, "gridSpan");
|
|
2815
|
+
if (gsEl) {
|
|
2816
|
+
p.gridSpan = attrInt(gsEl, "val");
|
|
2817
|
+
}
|
|
2818
|
+
const vmEl = findChildNs(tcPrEl, "vMerge");
|
|
2819
|
+
if (vmEl) {
|
|
2820
|
+
p.verticalMerge = attrVal(vmEl, "val") ?? "continue";
|
|
2821
|
+
}
|
|
2822
|
+
const bordersEl = findChildNs(tcPrEl, "tcBorders");
|
|
2823
|
+
if (bordersEl) {
|
|
2824
|
+
p.borders = parseTableBorders(bordersEl);
|
|
2825
|
+
}
|
|
2826
|
+
const shdEl = findChildNs(tcPrEl, "shd");
|
|
2827
|
+
if (shdEl) {
|
|
2828
|
+
p.shading = parseShading(shdEl);
|
|
2829
|
+
}
|
|
2830
|
+
const vAlignEl = findChildNs(tcPrEl, "vAlign");
|
|
2831
|
+
if (vAlignEl) {
|
|
2832
|
+
p.verticalAlign = attrVal(vAlignEl, "val");
|
|
2833
|
+
}
|
|
2834
|
+
if (findChildNs(tcPrEl, "noWrap")) {
|
|
2835
|
+
p.noWrap = true;
|
|
2836
|
+
}
|
|
2837
|
+
const textDirEl = findChildNs(tcPrEl, "textDirection");
|
|
2838
|
+
if (textDirEl) {
|
|
2839
|
+
p.textDirection = attrVal(textDirEl, "val");
|
|
2840
|
+
}
|
|
2841
|
+
const marginsEl = findChildNs(tcPrEl, "tcMar");
|
|
2842
|
+
if (marginsEl) {
|
|
2843
|
+
p.margins = parseTableCellMargins(marginsEl);
|
|
2844
|
+
}
|
|
2845
|
+
// Conditional formatting
|
|
2846
|
+
const cnfEl = findChildNs(tcPrEl, "cnfStyle");
|
|
2847
|
+
if (cnfEl) {
|
|
2848
|
+
p.cnfStyle = attrVal(cnfEl, "val");
|
|
2849
|
+
}
|
|
2850
|
+
// Hide cell end-of-cell marker
|
|
2851
|
+
if (findChildNs(tcPrEl, "hideMark")) {
|
|
2852
|
+
p.hideMark = true;
|
|
2853
|
+
}
|
|
2854
|
+
// Fit text
|
|
2855
|
+
if (findChildNs(tcPrEl, "tcFitText")) {
|
|
2856
|
+
p.fitText = true;
|
|
2857
|
+
}
|
|
2858
|
+
// Cell-level revisions
|
|
2859
|
+
const cellInsEl = findChildNs(tcPrEl, "cellIns");
|
|
2860
|
+
if (cellInsEl) {
|
|
2861
|
+
const rev = parseRevisionInfo(cellInsEl);
|
|
2862
|
+
if (rev) {
|
|
2863
|
+
p.inserted = { revision: rev };
|
|
2864
|
+
}
|
|
2865
|
+
}
|
|
2866
|
+
const cellDelEl = findChildNs(tcPrEl, "cellDel");
|
|
2867
|
+
if (cellDelEl) {
|
|
2868
|
+
const rev = parseRevisionInfo(cellDelEl);
|
|
2869
|
+
if (rev) {
|
|
2870
|
+
p.deleted = { revision: rev };
|
|
2871
|
+
}
|
|
2872
|
+
}
|
|
2873
|
+
const cellMergeEl = findChildNs(tcPrEl, "cellMerge");
|
|
2874
|
+
if (cellMergeEl) {
|
|
2875
|
+
const vMerge = attrVal(cellMergeEl, "vMerge");
|
|
2876
|
+
const rev = parseRevisionInfo(cellMergeEl);
|
|
2877
|
+
if (rev && (vMerge === "cont" || vMerge === "rest")) {
|
|
2878
|
+
p.cellMerge = { vMerge, revision: rev };
|
|
2879
|
+
}
|
|
2880
|
+
}
|
|
2881
|
+
// tcPrChange
|
|
2882
|
+
const tcPrChangeEl = findChildNs(tcPrEl, "tcPrChange");
|
|
2883
|
+
if (tcPrChangeEl) {
|
|
2884
|
+
const rev = parseRevisionInfo(tcPrChangeEl);
|
|
2885
|
+
if (rev) {
|
|
2886
|
+
const prev = findChildNs(tcPrChangeEl, "tcPr");
|
|
2887
|
+
p.propertyChange = { revision: rev };
|
|
2888
|
+
if (prev) {
|
|
2889
|
+
// Minimal: previousProperties won't recurse (avoid infinite recursion).
|
|
2890
|
+
// Just capture the presence of the change marker here.
|
|
2891
|
+
}
|
|
2892
|
+
}
|
|
2893
|
+
}
|
|
2894
|
+
props = p;
|
|
2895
|
+
}
|
|
2896
|
+
return { properties: props, content };
|
|
2897
|
+
}
|
|
2898
|
+
function parseTableRow(el) {
|
|
2899
|
+
const trPrEl = findChildNs(el, "trPr");
|
|
2900
|
+
const tblPrExEl = findChildNs(el, "tblPrEx");
|
|
2901
|
+
const cells = [];
|
|
2902
|
+
for (const child of el.children) {
|
|
2903
|
+
if (child.type === "element" && child.name.replace(/^w:/, "") === "tc") {
|
|
2904
|
+
cells.push(parseTableCell(child));
|
|
2905
|
+
}
|
|
2906
|
+
}
|
|
2907
|
+
let props;
|
|
2908
|
+
if (trPrEl || tblPrExEl) {
|
|
2909
|
+
const p = {};
|
|
2910
|
+
if (tblPrExEl) {
|
|
2911
|
+
p.tblPrEx = parseTableProperties(tblPrExEl);
|
|
2912
|
+
}
|
|
2913
|
+
if (trPrEl) {
|
|
2914
|
+
const heightEl = findChildNs(trPrEl, "trHeight");
|
|
2915
|
+
if (heightEl) {
|
|
2916
|
+
p.height = {
|
|
2917
|
+
value: attrInt(heightEl, "val") ?? 0,
|
|
2918
|
+
rule: attrVal(heightEl, "hRule")
|
|
2919
|
+
};
|
|
2920
|
+
}
|
|
2921
|
+
if (findChildNs(trPrEl, "tblHeader")) {
|
|
2922
|
+
p.tableHeader = true;
|
|
2923
|
+
}
|
|
2924
|
+
if (findChildNs(trPrEl, "cantSplit")) {
|
|
2925
|
+
p.cantSplit = true;
|
|
2926
|
+
}
|
|
2927
|
+
if (findChildNs(trPrEl, "hidden")) {
|
|
2928
|
+
p.hidden = true;
|
|
2929
|
+
}
|
|
2930
|
+
const csEl = findChildNs(trPrEl, "tblCellSpacing");
|
|
2931
|
+
if (csEl) {
|
|
2932
|
+
p.cellSpacing = parseTableWidth(csEl);
|
|
2933
|
+
}
|
|
2934
|
+
const insEl = findChildNs(trPrEl, "ins");
|
|
2935
|
+
if (insEl) {
|
|
2936
|
+
const rev = parseRevisionInfo(insEl);
|
|
2937
|
+
if (rev) {
|
|
2938
|
+
p.inserted = { revision: rev };
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
const delEl = findChildNs(trPrEl, "del");
|
|
2942
|
+
if (delEl) {
|
|
2943
|
+
const rev = parseRevisionInfo(delEl);
|
|
2944
|
+
if (rev) {
|
|
2945
|
+
p.deleted = { revision: rev };
|
|
2946
|
+
}
|
|
2947
|
+
}
|
|
2948
|
+
const gbEl = findChildNs(trPrEl, "gridBefore");
|
|
2949
|
+
if (gbEl) {
|
|
2950
|
+
p.gridBefore = attrInt(gbEl, "val");
|
|
2951
|
+
}
|
|
2952
|
+
const gaEl = findChildNs(trPrEl, "gridAfter");
|
|
2953
|
+
if (gaEl) {
|
|
2954
|
+
p.gridAfter = attrInt(gaEl, "val");
|
|
2955
|
+
}
|
|
2956
|
+
const wbEl = findChildNs(trPrEl, "wBefore");
|
|
2957
|
+
if (wbEl) {
|
|
2958
|
+
p.widthBefore = parseTableWidth(wbEl);
|
|
2959
|
+
}
|
|
2960
|
+
const waEl = findChildNs(trPrEl, "wAfter");
|
|
2961
|
+
if (waEl) {
|
|
2962
|
+
p.widthAfter = parseTableWidth(waEl);
|
|
2963
|
+
}
|
|
2964
|
+
const cnfEl = findChildNs(trPrEl, "cnfStyle");
|
|
2965
|
+
if (cnfEl) {
|
|
2966
|
+
p.cnfStyle = attrVal(cnfEl, "val");
|
|
2967
|
+
}
|
|
2968
|
+
const trPrChangeEl = findChildNs(trPrEl, "trPrChange");
|
|
2969
|
+
if (trPrChangeEl) {
|
|
2970
|
+
const rev = parseRevisionInfo(trPrChangeEl);
|
|
2971
|
+
if (rev) {
|
|
2972
|
+
const prevTrPr = findChildNs(trPrChangeEl, "trPr");
|
|
2973
|
+
p.propertyChange = {
|
|
2974
|
+
revision: rev,
|
|
2975
|
+
previousProperties: prevTrPr ? parseRowPrInner(prevTrPr) : undefined
|
|
2976
|
+
};
|
|
2977
|
+
}
|
|
2978
|
+
}
|
|
2979
|
+
}
|
|
2980
|
+
props = p;
|
|
2981
|
+
}
|
|
2982
|
+
return { properties: props, cells };
|
|
2983
|
+
}
|
|
2984
|
+
/** Inner parse for row properties content (used by propertyChange recursion). */
|
|
2985
|
+
function parseRowPrInner(trPrEl) {
|
|
2986
|
+
const p = {};
|
|
2987
|
+
const heightEl = findChildNs(trPrEl, "trHeight");
|
|
2988
|
+
if (heightEl) {
|
|
2989
|
+
p.height = { value: attrInt(heightEl, "val") ?? 0, rule: attrVal(heightEl, "hRule") };
|
|
2990
|
+
}
|
|
2991
|
+
if (findChildNs(trPrEl, "tblHeader")) {
|
|
2992
|
+
p.tableHeader = true;
|
|
2993
|
+
}
|
|
2994
|
+
if (findChildNs(trPrEl, "cantSplit")) {
|
|
2995
|
+
p.cantSplit = true;
|
|
2996
|
+
}
|
|
2997
|
+
return p;
|
|
2998
|
+
}
|
|
2999
|
+
function parseTable(tblEl) {
|
|
3000
|
+
const tblPrEl = findChildNs(tblEl, "tblPr");
|
|
3001
|
+
const gridEl = findChildNs(tblEl, "tblGrid");
|
|
3002
|
+
const rows = [];
|
|
3003
|
+
for (const child of tblEl.children) {
|
|
3004
|
+
if (child.type === "element" && child.name.replace(/^w:/, "") === "tr") {
|
|
3005
|
+
rows.push(parseTableRow(child));
|
|
3006
|
+
}
|
|
3007
|
+
}
|
|
3008
|
+
let columnWidths;
|
|
3009
|
+
if (gridEl) {
|
|
3010
|
+
columnWidths = [];
|
|
3011
|
+
for (const col of findChildrenNs(gridEl, "gridCol")) {
|
|
3012
|
+
columnWidths.push(parseInt(col.attributes["w:w"] ?? col.attributes["w"] ?? "0", 10));
|
|
3013
|
+
}
|
|
3014
|
+
}
|
|
3015
|
+
return {
|
|
3016
|
+
type: "table",
|
|
3017
|
+
properties: tblPrEl ? parseTableProperties(tblPrEl) : undefined,
|
|
3018
|
+
columnWidths,
|
|
3019
|
+
rows
|
|
3020
|
+
};
|
|
3021
|
+
}
|
|
3022
|
+
// =============================================================================
|
|
3023
|
+
// Section Properties Parser
|
|
3024
|
+
// =============================================================================
|
|
3025
|
+
function parseSectionProperties(sectPrEl) {
|
|
3026
|
+
const sect = {};
|
|
3027
|
+
const pgSzEl = findChildNs(sectPrEl, "pgSz");
|
|
3028
|
+
if (pgSzEl) {
|
|
3029
|
+
// Per ECMA-376, w:orient defaults to "portrait" when absent
|
|
3030
|
+
const orient = attrVal(pgSzEl, "orient");
|
|
3031
|
+
sect.pageSize = {
|
|
3032
|
+
width: attrInt(pgSzEl, "w"),
|
|
3033
|
+
height: attrInt(pgSzEl, "h"),
|
|
3034
|
+
orientation: (orient === "landscape" ? "landscape" : "portrait")
|
|
3035
|
+
};
|
|
3036
|
+
}
|
|
3037
|
+
const pgMarEl = findChildNs(sectPrEl, "pgMar");
|
|
3038
|
+
if (pgMarEl) {
|
|
3039
|
+
sect.margins = {
|
|
3040
|
+
top: attrInt(pgMarEl, "top"),
|
|
3041
|
+
right: attrInt(pgMarEl, "right"),
|
|
3042
|
+
bottom: attrInt(pgMarEl, "bottom"),
|
|
3043
|
+
left: attrInt(pgMarEl, "left"),
|
|
3044
|
+
header: attrInt(pgMarEl, "header"),
|
|
3045
|
+
footer: attrInt(pgMarEl, "footer"),
|
|
3046
|
+
gutter: attrInt(pgMarEl, "gutter")
|
|
3047
|
+
};
|
|
3048
|
+
}
|
|
3049
|
+
const typeEl = findChildNs(sectPrEl, "type");
|
|
3050
|
+
if (typeEl) {
|
|
3051
|
+
sect.breakType = attrVal(typeEl, "val");
|
|
3052
|
+
}
|
|
3053
|
+
const colsEl = findChildNs(sectPrEl, "cols");
|
|
3054
|
+
if (colsEl) {
|
|
3055
|
+
const cols = {};
|
|
3056
|
+
cols.space = attrInt(colsEl, "space");
|
|
3057
|
+
cols.count = attrInt(colsEl, "num");
|
|
3058
|
+
const eqw = attrVal(colsEl, "equalWidth");
|
|
3059
|
+
if (eqw !== undefined) {
|
|
3060
|
+
cols.equalWidth = eqw === "1";
|
|
3061
|
+
}
|
|
3062
|
+
const sep = attrVal(colsEl, "sep");
|
|
3063
|
+
if (sep === "1" || sep === "true") {
|
|
3064
|
+
cols.separator = true;
|
|
3065
|
+
}
|
|
3066
|
+
const colDefs = findChildrenNs(colsEl, "col");
|
|
3067
|
+
if (colDefs.length > 0) {
|
|
3068
|
+
cols.columns = colDefs.map(c => ({
|
|
3069
|
+
width: attrInt(c, "w") ?? 0,
|
|
3070
|
+
space: attrInt(c, "space")
|
|
3071
|
+
}));
|
|
3072
|
+
}
|
|
3073
|
+
sect.columns = cols;
|
|
3074
|
+
}
|
|
3075
|
+
if (findChildNs(sectPrEl, "titlePg")) {
|
|
3076
|
+
sect.titlePage = true;
|
|
3077
|
+
}
|
|
3078
|
+
const pgNumEl = findChildNs(sectPrEl, "pgNumType");
|
|
3079
|
+
if (pgNumEl) {
|
|
3080
|
+
sect.pageNumbering = {
|
|
3081
|
+
start: attrInt(pgNumEl, "start"),
|
|
3082
|
+
format: attrVal(pgNumEl, "fmt")
|
|
3083
|
+
};
|
|
3084
|
+
}
|
|
3085
|
+
// Page borders
|
|
3086
|
+
const pgBordersEl = findChildNs(sectPrEl, "pgBorders");
|
|
3087
|
+
if (pgBordersEl) {
|
|
3088
|
+
const pb = {};
|
|
3089
|
+
const p = pb;
|
|
3090
|
+
for (const side of ["top", "left", "bottom", "right"]) {
|
|
3091
|
+
const sideEl = findChildNs(pgBordersEl, side);
|
|
3092
|
+
if (sideEl) {
|
|
3093
|
+
p[side] = parseBorder(sideEl);
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
const display = attrVal(pgBordersEl, "display");
|
|
3097
|
+
if (display) {
|
|
3098
|
+
p.display = display;
|
|
3099
|
+
}
|
|
3100
|
+
const offsetFrom = attrVal(pgBordersEl, "offsetFrom");
|
|
3101
|
+
if (offsetFrom) {
|
|
3102
|
+
p.offsetFrom = offsetFrom;
|
|
3103
|
+
}
|
|
3104
|
+
const zOrder = attrVal(pgBordersEl, "zOrder");
|
|
3105
|
+
if (zOrder) {
|
|
3106
|
+
p.zOrder = zOrder;
|
|
3107
|
+
}
|
|
3108
|
+
sect.pageBorders = pb;
|
|
3109
|
+
}
|
|
3110
|
+
// Vertical alignment
|
|
3111
|
+
const vAlignEl = findChildNs(sectPrEl, "vAlign");
|
|
3112
|
+
if (vAlignEl) {
|
|
3113
|
+
sect.verticalAlign = attrVal(vAlignEl, "val");
|
|
3114
|
+
}
|
|
3115
|
+
// Text direction
|
|
3116
|
+
const textDirEl = findChildNs(sectPrEl, "textDirection");
|
|
3117
|
+
if (textDirEl) {
|
|
3118
|
+
sect.textDirection = attrVal(textDirEl, "val");
|
|
3119
|
+
}
|
|
3120
|
+
// Bidi
|
|
3121
|
+
const bidiToggle = boolToggle(sectPrEl, "bidi");
|
|
3122
|
+
if (bidiToggle !== undefined) {
|
|
3123
|
+
sect.bidi = bidiToggle;
|
|
3124
|
+
}
|
|
3125
|
+
// RTL gutter
|
|
3126
|
+
const rtlGutterEl = findChildNs(sectPrEl, "rtlGutter");
|
|
3127
|
+
if (rtlGutterEl) {
|
|
3128
|
+
sect.rtlGutter = true;
|
|
3129
|
+
}
|
|
3130
|
+
// Form protection
|
|
3131
|
+
const formProtEl = findChildNs(sectPrEl, "formProt");
|
|
3132
|
+
if (formProtEl) {
|
|
3133
|
+
const v = attrVal(formProtEl, "val");
|
|
3134
|
+
sect.formProtection = v === "1" || v === "true";
|
|
3135
|
+
}
|
|
3136
|
+
// Document grid
|
|
3137
|
+
const docGridEl = findChildNs(sectPrEl, "docGrid");
|
|
3138
|
+
if (docGridEl) {
|
|
3139
|
+
const dg = {};
|
|
3140
|
+
const linePitch = attrInt(docGridEl, "linePitch");
|
|
3141
|
+
if (linePitch !== undefined) {
|
|
3142
|
+
dg.linePitch = linePitch;
|
|
3143
|
+
}
|
|
3144
|
+
const charSpace = attrInt(docGridEl, "charSpace");
|
|
3145
|
+
if (charSpace !== undefined) {
|
|
3146
|
+
dg.charSpace = charSpace;
|
|
3147
|
+
}
|
|
3148
|
+
const gridType = attrVal(docGridEl, "type");
|
|
3149
|
+
if (gridType) {
|
|
3150
|
+
dg.type = gridType;
|
|
3151
|
+
}
|
|
3152
|
+
sect.docGrid = dg;
|
|
3153
|
+
}
|
|
3154
|
+
// Line numbers
|
|
3155
|
+
const lnNumEl = findChildNs(sectPrEl, "lnNumType");
|
|
3156
|
+
if (lnNumEl) {
|
|
3157
|
+
const ln = {};
|
|
3158
|
+
const countBy = attrInt(lnNumEl, "countBy");
|
|
3159
|
+
if (countBy !== undefined) {
|
|
3160
|
+
ln.countBy = countBy;
|
|
3161
|
+
}
|
|
3162
|
+
const start = attrInt(lnNumEl, "start");
|
|
3163
|
+
if (start !== undefined) {
|
|
3164
|
+
ln.start = start;
|
|
3165
|
+
}
|
|
3166
|
+
const restart = attrVal(lnNumEl, "restart");
|
|
3167
|
+
if (restart) {
|
|
3168
|
+
ln.restart = restart;
|
|
3169
|
+
}
|
|
3170
|
+
const distance = attrInt(lnNumEl, "distance");
|
|
3171
|
+
if (distance !== undefined) {
|
|
3172
|
+
ln.distance = distance;
|
|
3173
|
+
}
|
|
3174
|
+
sect.lineNumbers = ln;
|
|
3175
|
+
}
|
|
3176
|
+
// Footnote properties
|
|
3177
|
+
const fnPrEl = findChildNs(sectPrEl, "footnotePr");
|
|
3178
|
+
if (fnPrEl) {
|
|
3179
|
+
sect.footnoteProperties = parseNoteProperties(fnPrEl);
|
|
3180
|
+
}
|
|
3181
|
+
// Endnote properties
|
|
3182
|
+
const enPrEl = findChildNs(sectPrEl, "endnotePr");
|
|
3183
|
+
if (enPrEl) {
|
|
3184
|
+
sect.endnoteProperties = parseNoteProperties(enPrEl);
|
|
3185
|
+
}
|
|
3186
|
+
// Headers/Footers refs
|
|
3187
|
+
const headerRefs = [];
|
|
3188
|
+
for (const hRef of findChildrenNs(sectPrEl, "headerReference")) {
|
|
3189
|
+
headerRefs.push({
|
|
3190
|
+
type: (attrVal(hRef, "type") ?? "default"),
|
|
3191
|
+
rId: hRef.attributes["r:id"] ?? ""
|
|
3192
|
+
});
|
|
3193
|
+
}
|
|
3194
|
+
if (headerRefs.length > 0) {
|
|
3195
|
+
sect.headers = headerRefs;
|
|
3196
|
+
}
|
|
3197
|
+
const footerRefs = [];
|
|
3198
|
+
for (const fRef of findChildrenNs(sectPrEl, "footerReference")) {
|
|
3199
|
+
footerRefs.push({
|
|
3200
|
+
type: (attrVal(fRef, "type") ?? "default"),
|
|
3201
|
+
rId: fRef.attributes["r:id"] ?? ""
|
|
3202
|
+
});
|
|
3203
|
+
}
|
|
3204
|
+
if (footerRefs.length > 0) {
|
|
3205
|
+
sect.footers = footerRefs;
|
|
3206
|
+
}
|
|
3207
|
+
// sectPrChange (track changes for section properties)
|
|
3208
|
+
const sectPrChangeEl = findChildNs(sectPrEl, "sectPrChange");
|
|
3209
|
+
if (sectPrChangeEl) {
|
|
3210
|
+
const rev = parseRevisionInfo(sectPrChangeEl);
|
|
3211
|
+
if (rev) {
|
|
3212
|
+
const prevSectPrEl = findChildNs(sectPrChangeEl, "sectPr");
|
|
3213
|
+
const change = {
|
|
3214
|
+
revision: rev,
|
|
3215
|
+
previousProperties: prevSectPrEl ? parseSectionProperties(prevSectPrEl) : undefined
|
|
3216
|
+
};
|
|
3217
|
+
sect.propertyChange = change;
|
|
3218
|
+
}
|
|
3219
|
+
}
|
|
3220
|
+
return sect;
|
|
3221
|
+
}
|
|
3222
|
+
// =============================================================================
|
|
3223
|
+
// Styles Parser
|
|
3224
|
+
// =============================================================================
|
|
3225
|
+
function parseStyles(xmlStr) {
|
|
3226
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3227
|
+
const root = doc.root;
|
|
3228
|
+
let docDefaults;
|
|
3229
|
+
const styles = [];
|
|
3230
|
+
const ddEl = findChildNs(root, "docDefaults");
|
|
3231
|
+
if (ddEl) {
|
|
3232
|
+
const dd = {};
|
|
3233
|
+
const rPrDefaultEl = findChildNs(ddEl, "rPrDefault");
|
|
3234
|
+
if (rPrDefaultEl) {
|
|
3235
|
+
const rPrEl = findChildNs(rPrDefaultEl, "rPr");
|
|
3236
|
+
if (rPrEl) {
|
|
3237
|
+
dd.runProperties = parseRunProperties(rPrEl);
|
|
3238
|
+
}
|
|
3239
|
+
}
|
|
3240
|
+
const pPrDefaultEl = findChildNs(ddEl, "pPrDefault");
|
|
3241
|
+
if (pPrDefaultEl) {
|
|
3242
|
+
const pPrEl = findChildNs(pPrDefaultEl, "pPr");
|
|
3243
|
+
if (pPrEl) {
|
|
3244
|
+
dd.paragraphProperties = parseParagraphProperties(pPrEl);
|
|
3245
|
+
}
|
|
3246
|
+
}
|
|
3247
|
+
docDefaults = dd;
|
|
3248
|
+
}
|
|
3249
|
+
for (const styleEl of findChildrenNs(root, "style")) {
|
|
3250
|
+
const s = {};
|
|
3251
|
+
s.type = attrVal(styleEl, "type");
|
|
3252
|
+
s.styleId = attrVal(styleEl, "styleId");
|
|
3253
|
+
s.isDefault = attrVal(styleEl, "default") === "1";
|
|
3254
|
+
if (attrVal(styleEl, "customStyle") === "1") {
|
|
3255
|
+
s.customStyle = true;
|
|
3256
|
+
}
|
|
3257
|
+
const nameEl = findChildNs(styleEl, "name");
|
|
3258
|
+
s.name = nameEl ? (attrVal(nameEl, "val") ?? "") : "";
|
|
3259
|
+
const basedOnEl = findChildNs(styleEl, "basedOn");
|
|
3260
|
+
if (basedOnEl) {
|
|
3261
|
+
s.basedOn = attrVal(basedOnEl, "val");
|
|
3262
|
+
}
|
|
3263
|
+
const nextEl = findChildNs(styleEl, "next");
|
|
3264
|
+
if (nextEl) {
|
|
3265
|
+
s.next = attrVal(nextEl, "val");
|
|
3266
|
+
}
|
|
3267
|
+
const linkEl = findChildNs(styleEl, "link");
|
|
3268
|
+
if (linkEl) {
|
|
3269
|
+
s.link = attrVal(linkEl, "val");
|
|
3270
|
+
}
|
|
3271
|
+
const uiPrEl = findChildNs(styleEl, "uiPriority");
|
|
3272
|
+
if (uiPrEl) {
|
|
3273
|
+
s.uiPriority = attrInt(uiPrEl, "val");
|
|
3274
|
+
}
|
|
3275
|
+
if (findChildNs(styleEl, "qFormat")) {
|
|
3276
|
+
s.qFormat = true;
|
|
3277
|
+
}
|
|
3278
|
+
if (findChildNs(styleEl, "semiHidden")) {
|
|
3279
|
+
s.semiHidden = true;
|
|
3280
|
+
}
|
|
3281
|
+
if (findChildNs(styleEl, "unhideWhenUsed")) {
|
|
3282
|
+
s.unhideWhenUsed = true;
|
|
3283
|
+
}
|
|
3284
|
+
if (findChildNs(styleEl, "hidden")) {
|
|
3285
|
+
s.hidden = true;
|
|
3286
|
+
}
|
|
3287
|
+
if (findChildNs(styleEl, "locked")) {
|
|
3288
|
+
s.locked = true;
|
|
3289
|
+
}
|
|
3290
|
+
if (findChildNs(styleEl, "autoRedefine")) {
|
|
3291
|
+
s.autoRedefine = true;
|
|
3292
|
+
}
|
|
3293
|
+
const pPrEl = findChildNs(styleEl, "pPr");
|
|
3294
|
+
if (pPrEl) {
|
|
3295
|
+
s.paragraphProperties = parseParagraphProperties(pPrEl);
|
|
3296
|
+
}
|
|
3297
|
+
const rPrEl = findChildNs(styleEl, "rPr");
|
|
3298
|
+
if (rPrEl) {
|
|
3299
|
+
s.runProperties = parseRunProperties(rPrEl);
|
|
3300
|
+
}
|
|
3301
|
+
// Table properties for table styles
|
|
3302
|
+
const tblPrEl = findChildNs(styleEl, "tblPr");
|
|
3303
|
+
if (tblPrEl) {
|
|
3304
|
+
s.tableProperties = parseTableProperties(tblPrEl);
|
|
3305
|
+
}
|
|
3306
|
+
// Table style conditional formats
|
|
3307
|
+
const tblStylePrs = findChildrenNs(styleEl, "tblStylePr");
|
|
3308
|
+
if (tblStylePrs.length > 0) {
|
|
3309
|
+
const conditions = [];
|
|
3310
|
+
for (const tsp of tblStylePrs) {
|
|
3311
|
+
const cond = { type: attrVal(tsp, "type") };
|
|
3312
|
+
const cpPr = findChildNs(tsp, "pPr");
|
|
3313
|
+
if (cpPr) {
|
|
3314
|
+
cond.paragraphProperties = parseParagraphProperties(cpPr);
|
|
3315
|
+
}
|
|
3316
|
+
const crPr = findChildNs(tsp, "rPr");
|
|
3317
|
+
if (crPr) {
|
|
3318
|
+
cond.runProperties = parseRunProperties(crPr);
|
|
3319
|
+
}
|
|
3320
|
+
const ctblPr = findChildNs(tsp, "tblPr");
|
|
3321
|
+
if (ctblPr) {
|
|
3322
|
+
cond.tableProperties = parseTableProperties(ctblPr);
|
|
3323
|
+
}
|
|
3324
|
+
const ctrPr = findChildNs(tsp, "trPr");
|
|
3325
|
+
if (ctrPr) {
|
|
3326
|
+
const rp = {};
|
|
3327
|
+
const hEl = findChildNs(ctrPr, "trHeight");
|
|
3328
|
+
if (hEl) {
|
|
3329
|
+
rp.height = { value: attrInt(hEl, "val") ?? 0, rule: attrVal(hEl, "hRule") };
|
|
3330
|
+
}
|
|
3331
|
+
cond.rowProperties = rp;
|
|
3332
|
+
}
|
|
3333
|
+
const ctcPr = findChildNs(tsp, "tcPr");
|
|
3334
|
+
if (ctcPr) {
|
|
3335
|
+
const cp = {};
|
|
3336
|
+
const bEl = findChildNs(ctcPr, "tcBorders");
|
|
3337
|
+
if (bEl) {
|
|
3338
|
+
cp.borders = parseTableBorders(bEl);
|
|
3339
|
+
}
|
|
3340
|
+
const shd = findChildNs(ctcPr, "shd");
|
|
3341
|
+
if (shd) {
|
|
3342
|
+
cp.shading = parseShading(shd);
|
|
3343
|
+
}
|
|
3344
|
+
cond.cellProperties = cp;
|
|
3345
|
+
}
|
|
3346
|
+
conditions.push(cond);
|
|
3347
|
+
}
|
|
3348
|
+
s.tableStyleConditions = conditions;
|
|
3349
|
+
}
|
|
3350
|
+
styles.push(s);
|
|
3351
|
+
}
|
|
3352
|
+
return { docDefaults, styles };
|
|
3353
|
+
}
|
|
3354
|
+
// =============================================================================
|
|
3355
|
+
// Numbering Parser
|
|
3356
|
+
// =============================================================================
|
|
3357
|
+
function parseNumberingXml(xmlStr) {
|
|
3358
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3359
|
+
const root = doc.root;
|
|
3360
|
+
const abstractNums = [];
|
|
3361
|
+
const instances = [];
|
|
3362
|
+
const numPicBullets = [];
|
|
3363
|
+
// Parse picture bullets
|
|
3364
|
+
for (const pbEl of findChildrenNs(root, "numPicBullet")) {
|
|
3365
|
+
const id = attrInt(pbEl, "numPicBulletId");
|
|
3366
|
+
if (id === undefined) {
|
|
3367
|
+
continue;
|
|
3368
|
+
}
|
|
3369
|
+
const pb = { id };
|
|
3370
|
+
// Try to extract VML shape info
|
|
3371
|
+
const pictEl = findChildNs(pbEl, "pict");
|
|
3372
|
+
if (pictEl) {
|
|
3373
|
+
// Preserve raw VML for complete fidelity
|
|
3374
|
+
let rawVml = "";
|
|
3375
|
+
for (const child of pictEl.children) {
|
|
3376
|
+
if (child.type === "element") {
|
|
3377
|
+
rawVml += serializeElement(child);
|
|
3378
|
+
}
|
|
3379
|
+
}
|
|
3380
|
+
if (rawVml) {
|
|
3381
|
+
pb.rawVmlXml = rawVml;
|
|
3382
|
+
}
|
|
3383
|
+
// Extract rId from v:imagedata
|
|
3384
|
+
const shapeEl = (0, dom_1.findChild)(pictEl, "v:shape");
|
|
3385
|
+
if (shapeEl) {
|
|
3386
|
+
const imgDataEl = (0, dom_1.findChild)(shapeEl, "v:imagedata");
|
|
3387
|
+
if (imgDataEl) {
|
|
3388
|
+
const rId = imgDataEl.attributes["r:id"] ?? imgDataEl.attributes["r:pict"];
|
|
3389
|
+
if (rId) {
|
|
3390
|
+
pb.rId = rId;
|
|
3391
|
+
}
|
|
3392
|
+
}
|
|
3393
|
+
// Extract width/height from style
|
|
3394
|
+
const style = shapeEl.attributes["style"];
|
|
3395
|
+
if (style) {
|
|
3396
|
+
const wMatch = /width:([\d.]+)pt/i.exec(style);
|
|
3397
|
+
const hMatch = /height:([\d.]+)pt/i.exec(style);
|
|
3398
|
+
if (wMatch) {
|
|
3399
|
+
pb.width = Math.round(parseFloat(wMatch[1]) * 12700);
|
|
3400
|
+
}
|
|
3401
|
+
if (hMatch) {
|
|
3402
|
+
pb.height = Math.round(parseFloat(hMatch[1]) * 12700);
|
|
3403
|
+
}
|
|
3404
|
+
}
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
numPicBullets.push(pb);
|
|
3408
|
+
}
|
|
3409
|
+
for (const absEl of findChildrenNs(root, "abstractNum")) {
|
|
3410
|
+
const levels = [];
|
|
3411
|
+
for (const lvlEl of findChildrenNs(absEl, "lvl")) {
|
|
3412
|
+
levels.push(parseLevel(lvlEl));
|
|
3413
|
+
}
|
|
3414
|
+
const abs = {
|
|
3415
|
+
abstractNumId: attrInt(absEl, "abstractNumId") ?? 0,
|
|
3416
|
+
levels
|
|
3417
|
+
};
|
|
3418
|
+
const mltEl = findChildNs(absEl, "multiLevelType");
|
|
3419
|
+
if (mltEl) {
|
|
3420
|
+
abs.multiLevelType = attrVal(mltEl, "val");
|
|
3421
|
+
}
|
|
3422
|
+
const numStyleLinkEl = findChildNs(absEl, "numStyleLink");
|
|
3423
|
+
if (numStyleLinkEl) {
|
|
3424
|
+
abs.numStyleLink = attrVal(numStyleLinkEl, "val");
|
|
3425
|
+
}
|
|
3426
|
+
const styleLinkEl = findChildNs(absEl, "styleLink");
|
|
3427
|
+
if (styleLinkEl) {
|
|
3428
|
+
abs.styleLink = attrVal(styleLinkEl, "val");
|
|
3429
|
+
}
|
|
3430
|
+
abstractNums.push(abs);
|
|
3431
|
+
}
|
|
3432
|
+
for (const numEl of findChildrenNs(root, "num")) {
|
|
3433
|
+
const absIdEl = findChildNs(numEl, "abstractNumId");
|
|
3434
|
+
const overrides = [];
|
|
3435
|
+
for (const ovEl of findChildrenNs(numEl, "lvlOverride")) {
|
|
3436
|
+
const ov = { level: attrInt(ovEl, "ilvl") ?? 0 };
|
|
3437
|
+
const startOvEl = findChildNs(ovEl, "startOverride");
|
|
3438
|
+
if (startOvEl) {
|
|
3439
|
+
ov.startOverride = attrInt(startOvEl, "val");
|
|
3440
|
+
}
|
|
3441
|
+
// Level def override: parse full level definition
|
|
3442
|
+
const lvlEl = findChildNs(ovEl, "lvl");
|
|
3443
|
+
if (lvlEl) {
|
|
3444
|
+
ov.levelDef = parseLevel(lvlEl);
|
|
3445
|
+
// Inherit level index from parent if not specified
|
|
3446
|
+
if (ov.levelDef.level === undefined) {
|
|
3447
|
+
ov.levelDef.level = ov.level;
|
|
3448
|
+
}
|
|
3449
|
+
}
|
|
3450
|
+
overrides.push(ov);
|
|
3451
|
+
}
|
|
3452
|
+
instances.push({
|
|
3453
|
+
numId: attrInt(numEl, "numId") ?? 0,
|
|
3454
|
+
abstractNumId: absIdEl ? (attrInt(absIdEl, "val") ?? 0) : 0,
|
|
3455
|
+
overrides: overrides.length > 0 ? overrides : undefined
|
|
3456
|
+
});
|
|
3457
|
+
}
|
|
3458
|
+
return { abstractNums, instances, numPicBullets };
|
|
3459
|
+
}
|
|
3460
|
+
/** Parse a w:lvl element into a NumberingLevel (shared by abstractNum and lvlOverride). */
|
|
3461
|
+
function parseLevel(lvlEl) {
|
|
3462
|
+
const level = { level: attrInt(lvlEl, "ilvl") ?? 0 };
|
|
3463
|
+
const startEl = findChildNs(lvlEl, "start");
|
|
3464
|
+
if (startEl) {
|
|
3465
|
+
level.start = attrInt(startEl, "val");
|
|
3466
|
+
}
|
|
3467
|
+
const fmtEl = findChildNs(lvlEl, "numFmt");
|
|
3468
|
+
if (fmtEl) {
|
|
3469
|
+
level.format = attrVal(fmtEl, "val");
|
|
3470
|
+
}
|
|
3471
|
+
const textEl = findChildNs(lvlEl, "lvlText");
|
|
3472
|
+
if (textEl) {
|
|
3473
|
+
level.text = attrVal(textEl, "val") ?? "";
|
|
3474
|
+
}
|
|
3475
|
+
const pStyleEl = findChildNs(lvlEl, "pStyle");
|
|
3476
|
+
if (pStyleEl) {
|
|
3477
|
+
level.paragraphStyle = attrVal(pStyleEl, "val");
|
|
3478
|
+
}
|
|
3479
|
+
const jcEl = findChildNs(lvlEl, "lvlJc");
|
|
3480
|
+
if (jcEl) {
|
|
3481
|
+
level.justification = attrVal(jcEl, "val");
|
|
3482
|
+
}
|
|
3483
|
+
const pPrEl = findChildNs(lvlEl, "pPr");
|
|
3484
|
+
if (pPrEl) {
|
|
3485
|
+
level.paragraphProperties = parseParagraphProperties(pPrEl);
|
|
3486
|
+
}
|
|
3487
|
+
const rPrEl = findChildNs(lvlEl, "rPr");
|
|
3488
|
+
if (rPrEl) {
|
|
3489
|
+
level.runProperties = parseRunProperties(rPrEl);
|
|
3490
|
+
}
|
|
3491
|
+
const suffEl = findChildNs(lvlEl, "suff");
|
|
3492
|
+
if (suffEl) {
|
|
3493
|
+
level.suffix = attrVal(suffEl, "val");
|
|
3494
|
+
}
|
|
3495
|
+
if (findChildNs(lvlEl, "isLgl")) {
|
|
3496
|
+
level.isLegalNumberingStyle = true;
|
|
3497
|
+
}
|
|
3498
|
+
const lvlRestartEl = findChildNs(lvlEl, "lvlRestart");
|
|
3499
|
+
if (lvlRestartEl) {
|
|
3500
|
+
level.restartAfterLevel = attrInt(lvlRestartEl, "val");
|
|
3501
|
+
}
|
|
3502
|
+
const picBulletEl = findChildNs(lvlEl, "lvlPicBulletId");
|
|
3503
|
+
if (picBulletEl) {
|
|
3504
|
+
level.picBulletId = attrInt(picBulletEl, "val");
|
|
3505
|
+
}
|
|
3506
|
+
return level;
|
|
3507
|
+
}
|
|
3508
|
+
// =============================================================================
|
|
3509
|
+
// Footnotes/Endnotes Parser
|
|
3510
|
+
// =============================================================================
|
|
3511
|
+
function parseNotesXml(xmlStr, elementName) {
|
|
3512
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3513
|
+
const root = doc.root;
|
|
3514
|
+
const notes = [];
|
|
3515
|
+
for (const noteEl of findChildrenNs(root, elementName)) {
|
|
3516
|
+
const id = attrInt(noteEl, "id");
|
|
3517
|
+
const type = attrVal(noteEl, "type");
|
|
3518
|
+
// Skip auto-generated separator entries (default IDs -1 and 0)
|
|
3519
|
+
// Real separators/continuationSeparators are regenerated by the writer.
|
|
3520
|
+
if (type === "separator" || type === "continuationSeparator") {
|
|
3521
|
+
continue;
|
|
3522
|
+
}
|
|
3523
|
+
if (id === undefined) {
|
|
3524
|
+
continue;
|
|
3525
|
+
}
|
|
3526
|
+
const content = [];
|
|
3527
|
+
for (const child of noteEl.children) {
|
|
3528
|
+
if (child.type === "element" && child.name.replace(/^w:/, "") === "p") {
|
|
3529
|
+
content.push(parseParagraph(child));
|
|
3530
|
+
}
|
|
3531
|
+
}
|
|
3532
|
+
const note = { id, content };
|
|
3533
|
+
if (type === "continuationNotice" || type === "normal") {
|
|
3534
|
+
note.type = type;
|
|
3535
|
+
}
|
|
3536
|
+
notes.push(note);
|
|
3537
|
+
}
|
|
3538
|
+
return notes;
|
|
3539
|
+
}
|
|
3540
|
+
// =============================================================================
|
|
3541
|
+
// Header/Footer Parser
|
|
3542
|
+
// =============================================================================
|
|
3543
|
+
function parseHeaderFooterXml(xmlStr) {
|
|
3544
|
+
return parseHeaderFooterRoot((0, dom_1.parseXml)(xmlStr).root);
|
|
3545
|
+
}
|
|
3546
|
+
function parseHeaderFooterRoot(root) {
|
|
3547
|
+
const children = [];
|
|
3548
|
+
for (const child of root.children) {
|
|
3549
|
+
if (child.type !== "element") {
|
|
3550
|
+
continue;
|
|
3551
|
+
}
|
|
3552
|
+
const name = child.name.replace(/^w:/, "");
|
|
3553
|
+
if (name === "p") {
|
|
3554
|
+
children.push(parseParagraph(child));
|
|
3555
|
+
}
|
|
3556
|
+
else if (name === "tbl") {
|
|
3557
|
+
children.push(parseTable(child));
|
|
3558
|
+
}
|
|
3559
|
+
}
|
|
3560
|
+
return { children };
|
|
3561
|
+
}
|
|
3562
|
+
/** Detect watermark from a header's parsed XML root element. */
|
|
3563
|
+
function detectWatermarkFromRoot(root) {
|
|
3564
|
+
// Look for VML shape with id containing "WaterMark"
|
|
3565
|
+
for (const pEl of root.children) {
|
|
3566
|
+
if (pEl.type !== "element") {
|
|
3567
|
+
continue;
|
|
3568
|
+
}
|
|
3569
|
+
for (const rEl of pEl.children) {
|
|
3570
|
+
if (rEl.type !== "element") {
|
|
3571
|
+
continue;
|
|
3572
|
+
}
|
|
3573
|
+
// Look for w:pict or w:r > w:pict
|
|
3574
|
+
const pictEls = [];
|
|
3575
|
+
const rName = rEl.name.replace(/^w:/, "");
|
|
3576
|
+
if (rName === "pict") {
|
|
3577
|
+
pictEls.push(rEl);
|
|
3578
|
+
}
|
|
3579
|
+
else if (rName === "r") {
|
|
3580
|
+
for (const rc of rEl.children) {
|
|
3581
|
+
if (rc.type === "element" && rc.name.replace(/^w:/, "") === "pict") {
|
|
3582
|
+
pictEls.push(rc);
|
|
3583
|
+
}
|
|
3584
|
+
}
|
|
3585
|
+
}
|
|
3586
|
+
for (const pictEl of pictEls) {
|
|
3587
|
+
for (const shapeEl of pictEl.children) {
|
|
3588
|
+
if (shapeEl.type !== "element") {
|
|
3589
|
+
continue;
|
|
3590
|
+
}
|
|
3591
|
+
const shapeId = shapeEl.attributes["id"] ?? "";
|
|
3592
|
+
if (!shapeId.toLowerCase().includes("watermark")) {
|
|
3593
|
+
continue;
|
|
3594
|
+
}
|
|
3595
|
+
// Found watermark shape
|
|
3596
|
+
const shapeType = shapeEl.attributes["type"] ?? "";
|
|
3597
|
+
if (shapeType.includes("136")) {
|
|
3598
|
+
// WordArt text watermark (shapetype 136)
|
|
3599
|
+
return parseTextWatermark(shapeEl);
|
|
3600
|
+
}
|
|
3601
|
+
// Check for image watermark (has v:imagedata)
|
|
3602
|
+
const imgData = (0, dom_1.findChild)(shapeEl, "v:imagedata");
|
|
3603
|
+
if (imgData) {
|
|
3604
|
+
return parseImageWatermark(shapeEl, imgData);
|
|
3605
|
+
}
|
|
3606
|
+
}
|
|
3607
|
+
}
|
|
3608
|
+
}
|
|
3609
|
+
}
|
|
3610
|
+
return undefined;
|
|
3611
|
+
}
|
|
3612
|
+
function parseTextWatermark(shapeEl) {
|
|
3613
|
+
const fillColor = shapeEl.attributes["fillcolor"] ?? "#C0C0C0";
|
|
3614
|
+
const color = fillColor.replace(/^#/, "");
|
|
3615
|
+
// Parse rotation from style
|
|
3616
|
+
const style = shapeEl.attributes["style"] ?? "";
|
|
3617
|
+
let rotation = -45;
|
|
3618
|
+
const rotMatch = style.match(/rotation:\s*(-?\d+)/);
|
|
3619
|
+
if (rotMatch) {
|
|
3620
|
+
rotation = parseInt(rotMatch[1], 10);
|
|
3621
|
+
}
|
|
3622
|
+
// Get opacity from v:fill
|
|
3623
|
+
const fillEl = (0, dom_1.findChild)(shapeEl, "v:fill");
|
|
3624
|
+
const opacity = fillEl?.attributes["opacity"] ?? ".5";
|
|
3625
|
+
const semiTransparent = opacity !== "1";
|
|
3626
|
+
// Get text and font from v:textpath
|
|
3627
|
+
const textpathEl = (0, dom_1.findChild)(shapeEl, "v:textpath");
|
|
3628
|
+
const text = textpathEl?.attributes["string"] ?? "";
|
|
3629
|
+
const tpStyle = textpathEl?.attributes["style"] ?? "";
|
|
3630
|
+
let font;
|
|
3631
|
+
let fontSize;
|
|
3632
|
+
const fontMatch = tpStyle.match(/font-family:\s*"?([^";]+)"?/);
|
|
3633
|
+
if (fontMatch) {
|
|
3634
|
+
font = fontMatch[1].replace(/"/g, "");
|
|
3635
|
+
}
|
|
3636
|
+
const sizeMatch = tpStyle.match(/font-size:\s*(\d+(?:\.\d+)?)\s*pt/);
|
|
3637
|
+
if (sizeMatch) {
|
|
3638
|
+
fontSize = Math.round(parseFloat(sizeMatch[1]) * 2); // convert pt to half-points
|
|
3639
|
+
}
|
|
3640
|
+
return {
|
|
3641
|
+
type: "text",
|
|
3642
|
+
text,
|
|
3643
|
+
font,
|
|
3644
|
+
fontSize,
|
|
3645
|
+
color,
|
|
3646
|
+
semiTransparent,
|
|
3647
|
+
rotation
|
|
3648
|
+
};
|
|
3649
|
+
}
|
|
3650
|
+
function parseImageWatermark(shapeEl, imgDataEl) {
|
|
3651
|
+
const rId = imgDataEl.attributes["r:id"] ?? "";
|
|
3652
|
+
const gain = imgDataEl.attributes["gain"] ?? "";
|
|
3653
|
+
const washout = gain.startsWith("19661") || gain === "";
|
|
3654
|
+
return {
|
|
3655
|
+
type: "image",
|
|
3656
|
+
rId,
|
|
3657
|
+
washout
|
|
3658
|
+
};
|
|
3659
|
+
}
|
|
3660
|
+
// =============================================================================
|
|
3661
|
+
// Comments Parser
|
|
3662
|
+
// =============================================================================
|
|
3663
|
+
function parseCommentsXml(xmlStr) {
|
|
3664
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3665
|
+
const root = doc.root;
|
|
3666
|
+
const comments = [];
|
|
3667
|
+
for (const commentEl of findChildrenNs(root, "comment")) {
|
|
3668
|
+
const id = attrInt(commentEl, "id");
|
|
3669
|
+
const author = attrVal(commentEl, "author");
|
|
3670
|
+
if (id === undefined || !author) {
|
|
3671
|
+
continue;
|
|
3672
|
+
}
|
|
3673
|
+
const content = [];
|
|
3674
|
+
for (const child of commentEl.children) {
|
|
3675
|
+
if (child.type === "element" && child.name.replace(/^w:/, "") === "p") {
|
|
3676
|
+
content.push(parseParagraph(child));
|
|
3677
|
+
}
|
|
3678
|
+
}
|
|
3679
|
+
const comment = { id, author, content };
|
|
3680
|
+
const date = attrVal(commentEl, "date");
|
|
3681
|
+
if (date) {
|
|
3682
|
+
comment.date = date;
|
|
3683
|
+
}
|
|
3684
|
+
const initials = attrVal(commentEl, "initials");
|
|
3685
|
+
if (initials) {
|
|
3686
|
+
comment.initials = initials;
|
|
3687
|
+
}
|
|
3688
|
+
comments.push(comment);
|
|
3689
|
+
}
|
|
3690
|
+
return comments;
|
|
3691
|
+
}
|
|
3692
|
+
/** Parse word/commentsExtended.xml — map paraId → { done, parentId }. */
|
|
3693
|
+
function parseCommentsExtendedXml(xmlStr) {
|
|
3694
|
+
const map = new Map();
|
|
3695
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3696
|
+
const root = doc.root;
|
|
3697
|
+
for (const child of root.children) {
|
|
3698
|
+
if (child.type !== "element") {
|
|
3699
|
+
continue;
|
|
3700
|
+
}
|
|
3701
|
+
// w15:commentEx
|
|
3702
|
+
const name = child.name;
|
|
3703
|
+
if (!name.endsWith("commentEx")) {
|
|
3704
|
+
continue;
|
|
3705
|
+
}
|
|
3706
|
+
const paraId = child.attributes["w15:paraId"] ?? child.attributes["paraId"];
|
|
3707
|
+
if (!paraId) {
|
|
3708
|
+
continue;
|
|
3709
|
+
}
|
|
3710
|
+
const entry = {};
|
|
3711
|
+
const done = child.attributes["w15:done"] ?? child.attributes["done"];
|
|
3712
|
+
if (done === "1" || done === "true") {
|
|
3713
|
+
entry.done = true;
|
|
3714
|
+
}
|
|
3715
|
+
else if (done === "0" || done === "false") {
|
|
3716
|
+
entry.done = false;
|
|
3717
|
+
}
|
|
3718
|
+
const pid = child.attributes["w15:paraIdParent"] ?? child.attributes["paraIdParent"];
|
|
3719
|
+
if (pid) {
|
|
3720
|
+
entry.parentId = pid;
|
|
3721
|
+
}
|
|
3722
|
+
map.set(paraId, entry);
|
|
3723
|
+
}
|
|
3724
|
+
return map;
|
|
3725
|
+
}
|
|
3726
|
+
// =============================================================================
|
|
3727
|
+
// Core Properties Parser
|
|
3728
|
+
// =============================================================================
|
|
3729
|
+
function parseCoreProps(xmlStr) {
|
|
3730
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3731
|
+
const root = doc.root;
|
|
3732
|
+
const props = {};
|
|
3733
|
+
const fields = [
|
|
3734
|
+
["dc:title", "title"],
|
|
3735
|
+
["dc:subject", "subject"],
|
|
3736
|
+
["dc:creator", "creator"],
|
|
3737
|
+
["dc:description", "description"],
|
|
3738
|
+
["cp:keywords", "keywords"],
|
|
3739
|
+
["cp:lastModifiedBy", "lastModifiedBy"],
|
|
3740
|
+
["cp:revision", "revision"],
|
|
3741
|
+
["cp:category", "category"]
|
|
3742
|
+
];
|
|
3743
|
+
for (const [tag, prop] of fields) {
|
|
3744
|
+
const el = (0, dom_1.findChild)(root, tag);
|
|
3745
|
+
if (el) {
|
|
3746
|
+
const val = (0, dom_1.textContent)(el);
|
|
3747
|
+
if (val) {
|
|
3748
|
+
props[prop] = val;
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
const createdEl = (0, dom_1.findChild)(root, "dcterms:created");
|
|
3753
|
+
if (createdEl) {
|
|
3754
|
+
const val = (0, dom_1.textContent)(createdEl);
|
|
3755
|
+
if (val) {
|
|
3756
|
+
props.created = new Date(val);
|
|
3757
|
+
}
|
|
3758
|
+
}
|
|
3759
|
+
const modifiedEl = (0, dom_1.findChild)(root, "dcterms:modified");
|
|
3760
|
+
if (modifiedEl) {
|
|
3761
|
+
const val = (0, dom_1.textContent)(modifiedEl);
|
|
3762
|
+
if (val) {
|
|
3763
|
+
props.modified = new Date(val);
|
|
3764
|
+
}
|
|
3765
|
+
}
|
|
3766
|
+
return props;
|
|
3767
|
+
}
|
|
3768
|
+
// =============================================================================
|
|
3769
|
+
// App Properties Parser
|
|
3770
|
+
// =============================================================================
|
|
3771
|
+
function parseAppProps(xmlStr) {
|
|
3772
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3773
|
+
const root = doc.root;
|
|
3774
|
+
const props = {};
|
|
3775
|
+
const strFields = ["Application", "AppVersion", "Company", "Manager"];
|
|
3776
|
+
const intFields = ["Pages", "Words", "Characters", "Lines", "Paragraphs"];
|
|
3777
|
+
for (const field of strFields) {
|
|
3778
|
+
const el = (0, dom_1.findChild)(root, field);
|
|
3779
|
+
if (el) {
|
|
3780
|
+
const val = (0, dom_1.textContent)(el);
|
|
3781
|
+
if (val) {
|
|
3782
|
+
props[field.charAt(0).toLowerCase() + field.slice(1)] = val;
|
|
3783
|
+
}
|
|
3784
|
+
}
|
|
3785
|
+
}
|
|
3786
|
+
for (const field of intFields) {
|
|
3787
|
+
const el = (0, dom_1.findChild)(root, field);
|
|
3788
|
+
if (el) {
|
|
3789
|
+
const val = (0, dom_1.textContent)(el);
|
|
3790
|
+
if (val) {
|
|
3791
|
+
props[field.charAt(0).toLowerCase() + field.slice(1)] = parseInt(val, 10);
|
|
3792
|
+
}
|
|
3793
|
+
}
|
|
3794
|
+
}
|
|
3795
|
+
return props;
|
|
3796
|
+
}
|
|
3797
|
+
// =============================================================================
|
|
3798
|
+
// Theme Parser
|
|
3799
|
+
// =============================================================================
|
|
3800
|
+
const THEME_COLOR_NAMES = [
|
|
3801
|
+
"dk1",
|
|
3802
|
+
"lt1",
|
|
3803
|
+
"dk2",
|
|
3804
|
+
"lt2",
|
|
3805
|
+
"accent1",
|
|
3806
|
+
"accent2",
|
|
3807
|
+
"accent3",
|
|
3808
|
+
"accent4",
|
|
3809
|
+
"accent5",
|
|
3810
|
+
"accent6",
|
|
3811
|
+
"hlink",
|
|
3812
|
+
"folHlink"
|
|
3813
|
+
];
|
|
3814
|
+
function parseThemeXml(xmlStr) {
|
|
3815
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3816
|
+
const root = doc.root;
|
|
3817
|
+
// Find a:themeElements
|
|
3818
|
+
const themeElements = (0, dom_1.findChild)(root, "a:themeElements") ?? findChildNs(root, "themeElements");
|
|
3819
|
+
const defaultScheme = {
|
|
3820
|
+
name: "Office",
|
|
3821
|
+
colors: {
|
|
3822
|
+
dk1: "000000",
|
|
3823
|
+
lt1: "FFFFFF",
|
|
3824
|
+
dk2: "44546A",
|
|
3825
|
+
lt2: "E7E6E6",
|
|
3826
|
+
accent1: "4472C4",
|
|
3827
|
+
accent2: "ED7D31",
|
|
3828
|
+
accent3: "A5A5A5",
|
|
3829
|
+
accent4: "FFC000",
|
|
3830
|
+
accent5: "5B9BD5",
|
|
3831
|
+
accent6: "70AD47",
|
|
3832
|
+
hlink: "0563C1",
|
|
3833
|
+
folHlink: "954F72"
|
|
3834
|
+
}
|
|
3835
|
+
};
|
|
3836
|
+
const defaultFontScheme = { name: "Office", majorFont: "Calibri Light", minorFont: "Calibri" };
|
|
3837
|
+
if (!themeElements) {
|
|
3838
|
+
return {
|
|
3839
|
+
name: root.attributes["name"],
|
|
3840
|
+
colorScheme: defaultScheme,
|
|
3841
|
+
fontScheme: defaultFontScheme
|
|
3842
|
+
};
|
|
3843
|
+
}
|
|
3844
|
+
// Parse color scheme
|
|
3845
|
+
const clrSchemeEl = (0, dom_1.findChild)(themeElements, "a:clrScheme") ?? findChildNs(themeElements, "clrScheme");
|
|
3846
|
+
const colorScheme = { ...defaultScheme };
|
|
3847
|
+
if (clrSchemeEl) {
|
|
3848
|
+
colorScheme.name = clrSchemeEl.attributes["name"] ?? "Office";
|
|
3849
|
+
for (const colorName of THEME_COLOR_NAMES) {
|
|
3850
|
+
const colorEl = (0, dom_1.findChild)(clrSchemeEl, `a:${colorName}`) ?? findChildNs(clrSchemeEl, colorName);
|
|
3851
|
+
if (colorEl) {
|
|
3852
|
+
// Color can be sysClr (with lastClr) or srgbClr (with val)
|
|
3853
|
+
const srgb = (0, dom_1.findChild)(colorEl, "a:srgbClr") ?? findChildNs(colorEl, "srgbClr");
|
|
3854
|
+
if (srgb) {
|
|
3855
|
+
const val = srgb.attributes["val"];
|
|
3856
|
+
if (val) {
|
|
3857
|
+
colorScheme.colors[colorName] = val;
|
|
3858
|
+
}
|
|
3859
|
+
}
|
|
3860
|
+
else {
|
|
3861
|
+
const sys = (0, dom_1.findChild)(colorEl, "a:sysClr") ?? findChildNs(colorEl, "sysClr");
|
|
3862
|
+
if (sys) {
|
|
3863
|
+
const lastClr = sys.attributes["lastClr"];
|
|
3864
|
+
if (lastClr) {
|
|
3865
|
+
colorScheme.colors[colorName] = lastClr;
|
|
3866
|
+
}
|
|
3867
|
+
}
|
|
3868
|
+
}
|
|
3869
|
+
}
|
|
3870
|
+
}
|
|
3871
|
+
}
|
|
3872
|
+
// Parse font scheme
|
|
3873
|
+
const fontSchemeEl = (0, dom_1.findChild)(themeElements, "a:fontScheme") ?? findChildNs(themeElements, "fontScheme");
|
|
3874
|
+
const fontScheme = { ...defaultFontScheme };
|
|
3875
|
+
if (fontSchemeEl) {
|
|
3876
|
+
fontScheme.name = fontSchemeEl.attributes["name"] ?? "Office";
|
|
3877
|
+
const majorEl = (0, dom_1.findChild)(fontSchemeEl, "a:majorFont") ?? findChildNs(fontSchemeEl, "majorFont");
|
|
3878
|
+
if (majorEl) {
|
|
3879
|
+
const major = parseThemeFont(majorEl);
|
|
3880
|
+
fontScheme.major = major;
|
|
3881
|
+
if (major.latin) {
|
|
3882
|
+
fontScheme.majorFont = major.latin;
|
|
3883
|
+
}
|
|
3884
|
+
}
|
|
3885
|
+
const minorEl = (0, dom_1.findChild)(fontSchemeEl, "a:minorFont") ?? findChildNs(fontSchemeEl, "minorFont");
|
|
3886
|
+
if (minorEl) {
|
|
3887
|
+
const minor = parseThemeFont(minorEl);
|
|
3888
|
+
fontScheme.minor = minor;
|
|
3889
|
+
if (minor.latin) {
|
|
3890
|
+
fontScheme.minorFont = minor.latin;
|
|
3891
|
+
}
|
|
3892
|
+
}
|
|
3893
|
+
}
|
|
3894
|
+
// Parse format scheme (preserve raw XML of its children for round-trip)
|
|
3895
|
+
const fmtSchemeEl = (0, dom_1.findChild)(themeElements, "a:fmtScheme") ?? findChildNs(themeElements, "fmtScheme");
|
|
3896
|
+
let formatScheme;
|
|
3897
|
+
if (fmtSchemeEl) {
|
|
3898
|
+
let rawXml = "";
|
|
3899
|
+
for (const child of fmtSchemeEl.children) {
|
|
3900
|
+
if (child.type === "element") {
|
|
3901
|
+
rawXml += serializeElement(child);
|
|
3902
|
+
}
|
|
3903
|
+
}
|
|
3904
|
+
formatScheme = {
|
|
3905
|
+
name: fmtSchemeEl.attributes["name"] ?? "Office",
|
|
3906
|
+
rawXml: rawXml || undefined
|
|
3907
|
+
};
|
|
3908
|
+
}
|
|
3909
|
+
// Preserve extLst (theme extensions) as raw XML
|
|
3910
|
+
let extLstXml;
|
|
3911
|
+
const extLstEl = (0, dom_1.findChild)(root, "a:extLst") ?? findChildNs(root, "extLst");
|
|
3912
|
+
if (extLstEl) {
|
|
3913
|
+
extLstXml = serializeElement(extLstEl);
|
|
3914
|
+
}
|
|
3915
|
+
return {
|
|
3916
|
+
name: root.attributes["name"],
|
|
3917
|
+
colorScheme,
|
|
3918
|
+
fontScheme,
|
|
3919
|
+
formatScheme,
|
|
3920
|
+
extLstXml
|
|
3921
|
+
};
|
|
3922
|
+
}
|
|
3923
|
+
/** Parse a theme font (a:majorFont or a:minorFont). */
|
|
3924
|
+
function parseThemeFont(el) {
|
|
3925
|
+
const font = {};
|
|
3926
|
+
const latin = (0, dom_1.findChild)(el, "a:latin") ?? findChildNs(el, "latin");
|
|
3927
|
+
if (latin?.attributes["typeface"]) {
|
|
3928
|
+
font.latin = latin.attributes["typeface"];
|
|
3929
|
+
}
|
|
3930
|
+
const ea = (0, dom_1.findChild)(el, "a:ea") ?? findChildNs(el, "ea");
|
|
3931
|
+
if (ea?.attributes["typeface"]) {
|
|
3932
|
+
font.eastAsia = ea.attributes["typeface"];
|
|
3933
|
+
}
|
|
3934
|
+
const cs = (0, dom_1.findChild)(el, "a:cs") ?? findChildNs(el, "cs");
|
|
3935
|
+
if (cs?.attributes["typeface"]) {
|
|
3936
|
+
font.complexScript = cs.attributes["typeface"];
|
|
3937
|
+
}
|
|
3938
|
+
// Supplemental fonts (a:font script="..." typeface="...")
|
|
3939
|
+
const supplementalFonts = {};
|
|
3940
|
+
for (const child of el.children) {
|
|
3941
|
+
if (child.type === "element" && (child.name === "a:font" || child.name === "font")) {
|
|
3942
|
+
const script = child.attributes["script"];
|
|
3943
|
+
const typeface = child.attributes["typeface"];
|
|
3944
|
+
if (script && typeface) {
|
|
3945
|
+
supplementalFonts[script] = typeface;
|
|
3946
|
+
}
|
|
3947
|
+
}
|
|
3948
|
+
}
|
|
3949
|
+
if (Object.keys(supplementalFonts).length > 0) {
|
|
3950
|
+
font.supplementalFonts = supplementalFonts;
|
|
3951
|
+
}
|
|
3952
|
+
return font;
|
|
3953
|
+
}
|
|
3954
|
+
// =============================================================================
|
|
3955
|
+
// Settings Parser
|
|
3956
|
+
// =============================================================================
|
|
3957
|
+
/** Parse word/webSettings.xml. */
|
|
3958
|
+
function parseWebSettings(xmlStr) {
|
|
3959
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3960
|
+
const root = doc.root;
|
|
3961
|
+
const ws = {};
|
|
3962
|
+
const ofbEl = findChildNs(root, "optimizeForBrowser");
|
|
3963
|
+
if (ofbEl) {
|
|
3964
|
+
const ofb = {};
|
|
3965
|
+
const target = attrVal(ofbEl, "target");
|
|
3966
|
+
if (target) {
|
|
3967
|
+
ofb.target = target;
|
|
3968
|
+
}
|
|
3969
|
+
const mv = attrInt(ofbEl, "majorVersion");
|
|
3970
|
+
if (mv !== undefined) {
|
|
3971
|
+
ofb.majorVersion = mv;
|
|
3972
|
+
}
|
|
3973
|
+
ws.optimizeForBrowser = ofb;
|
|
3974
|
+
}
|
|
3975
|
+
if (findChildNs(root, "allowPNG")) {
|
|
3976
|
+
ws.allowPng = true;
|
|
3977
|
+
}
|
|
3978
|
+
if (findChildNs(root, "relyOnVML")) {
|
|
3979
|
+
ws.relyOnVml = true;
|
|
3980
|
+
}
|
|
3981
|
+
if (findChildNs(root, "doNotSaveAsSingleFile")) {
|
|
3982
|
+
ws.doNotSaveAsSingleFile = true;
|
|
3983
|
+
}
|
|
3984
|
+
if (findChildNs(root, "doNotOrganizeInFolder")) {
|
|
3985
|
+
ws.doNotOrganizeInFolder = true;
|
|
3986
|
+
}
|
|
3987
|
+
if (findChildNs(root, "useTargetMachineType")) {
|
|
3988
|
+
ws.useTargetMachineType = true;
|
|
3989
|
+
}
|
|
3990
|
+
return ws;
|
|
3991
|
+
}
|
|
3992
|
+
/** Parse word/people.xml. */
|
|
3993
|
+
function parsePeople(xmlStr) {
|
|
3994
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
3995
|
+
const root = doc.root;
|
|
3996
|
+
const people = [];
|
|
3997
|
+
for (const personEl of root.children) {
|
|
3998
|
+
if (personEl.type !== "element") {
|
|
3999
|
+
continue;
|
|
4000
|
+
}
|
|
4001
|
+
const author = personEl.attributes["w15:author"] ?? personEl.attributes["author"];
|
|
4002
|
+
if (!author) {
|
|
4003
|
+
continue;
|
|
4004
|
+
}
|
|
4005
|
+
const info = { author };
|
|
4006
|
+
// presenceInfo
|
|
4007
|
+
for (const child of personEl.children) {
|
|
4008
|
+
if (child.type === "element" && child.name.endsWith("presenceInfo")) {
|
|
4009
|
+
const pi = {};
|
|
4010
|
+
const providerId = child.attributes["w15:providerId"] ?? child.attributes["providerId"];
|
|
4011
|
+
if (providerId) {
|
|
4012
|
+
pi.providerId = providerId;
|
|
4013
|
+
}
|
|
4014
|
+
const userId = child.attributes["w15:userId"] ?? child.attributes["userId"];
|
|
4015
|
+
if (userId) {
|
|
4016
|
+
pi.userId = userId;
|
|
4017
|
+
}
|
|
4018
|
+
if (Object.keys(pi).length > 0) {
|
|
4019
|
+
info.presenceInfo = pi;
|
|
4020
|
+
}
|
|
4021
|
+
break;
|
|
4022
|
+
}
|
|
4023
|
+
}
|
|
4024
|
+
people.push(info);
|
|
4025
|
+
}
|
|
4026
|
+
return people;
|
|
4027
|
+
}
|
|
4028
|
+
function parseSettingsXml(xmlStr) {
|
|
4029
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
4030
|
+
const root = doc.root;
|
|
4031
|
+
const settings = {};
|
|
4032
|
+
const zoomEl = findChildNs(root, "zoom");
|
|
4033
|
+
if (zoomEl) {
|
|
4034
|
+
settings.zoom = attrInt(zoomEl, "percent");
|
|
4035
|
+
}
|
|
4036
|
+
const tabEl = findChildNs(root, "defaultTabStop");
|
|
4037
|
+
if (tabEl) {
|
|
4038
|
+
settings.defaultTabStop = attrInt(tabEl, "val");
|
|
4039
|
+
}
|
|
4040
|
+
const csControlEl = findChildNs(root, "characterSpacingControl");
|
|
4041
|
+
if (csControlEl) {
|
|
4042
|
+
const v = attrVal(csControlEl, "val");
|
|
4043
|
+
if (v === "doNotCompress" ||
|
|
4044
|
+
v === "compressPunctuation" ||
|
|
4045
|
+
v === "compressPunctuationAndJapaneseKana") {
|
|
4046
|
+
settings.characterSpacingControl = v;
|
|
4047
|
+
}
|
|
4048
|
+
}
|
|
4049
|
+
// Extended settings
|
|
4050
|
+
if (findChildNs(root, "doNotTrackMoves")) {
|
|
4051
|
+
settings.doNotTrackMoves = true;
|
|
4052
|
+
}
|
|
4053
|
+
if (findChildNs(root, "doNotTrackFormatting")) {
|
|
4054
|
+
settings.doNotTrackFormatting = true;
|
|
4055
|
+
}
|
|
4056
|
+
if (findChildNs(root, "doNotDemoteNonCombiningChars")) {
|
|
4057
|
+
settings.doNotDemoteAsianTextFirstLine = true;
|
|
4058
|
+
}
|
|
4059
|
+
const ssFontsEl = findChildNs(root, "saveSubsetFonts");
|
|
4060
|
+
if (ssFontsEl) {
|
|
4061
|
+
const v = attrVal(ssFontsEl, "val");
|
|
4062
|
+
settings.saveSubsetFonts = v !== "0" && v !== "false";
|
|
4063
|
+
}
|
|
4064
|
+
if (findChildNs(root, "noPunctuationKerning")) {
|
|
4065
|
+
settings.noPunctuationKerning = true;
|
|
4066
|
+
}
|
|
4067
|
+
if (findChildNs(root, "bordersDoNotSurroundHeader")) {
|
|
4068
|
+
settings.bordersDoNotSurroundHeader = true;
|
|
4069
|
+
}
|
|
4070
|
+
if (findChildNs(root, "bordersDoNotSurroundFooter")) {
|
|
4071
|
+
settings.bordersDoNotSurroundFooter = true;
|
|
4072
|
+
}
|
|
4073
|
+
const clickStyleEl = findChildNs(root, "clickAndTypeStyle");
|
|
4074
|
+
if (clickStyleEl) {
|
|
4075
|
+
settings.clickAndTypeStyle = attrVal(clickStyleEl, "val");
|
|
4076
|
+
}
|
|
4077
|
+
const spfEl = findChildNs(root, "stylePaneFormatFilter");
|
|
4078
|
+
if (spfEl) {
|
|
4079
|
+
settings.stylePaneFormatFilter = attrVal(spfEl, "val");
|
|
4080
|
+
}
|
|
4081
|
+
const spsEl = findChildNs(root, "stylePaneSortMethod");
|
|
4082
|
+
if (spsEl) {
|
|
4083
|
+
settings.stylePaneSortMethod = attrVal(spsEl, "val");
|
|
4084
|
+
}
|
|
4085
|
+
const tflEl = findChildNs(root, "themeFontLang");
|
|
4086
|
+
if (tflEl) {
|
|
4087
|
+
const tfl = {};
|
|
4088
|
+
const v = attrVal(tflEl, "val");
|
|
4089
|
+
if (v) {
|
|
4090
|
+
tfl.val = v;
|
|
4091
|
+
}
|
|
4092
|
+
const ea = attrVal(tflEl, "eastAsia");
|
|
4093
|
+
if (ea) {
|
|
4094
|
+
tfl.eastAsia = ea;
|
|
4095
|
+
}
|
|
4096
|
+
const bd = attrVal(tflEl, "bidi");
|
|
4097
|
+
if (bd) {
|
|
4098
|
+
tfl.bidi = bd;
|
|
4099
|
+
}
|
|
4100
|
+
if (Object.keys(tfl).length > 0) {
|
|
4101
|
+
settings.themeFontLang = tfl;
|
|
4102
|
+
}
|
|
4103
|
+
}
|
|
4104
|
+
const dsEl = findChildNs(root, "decimalSymbol");
|
|
4105
|
+
if (dsEl) {
|
|
4106
|
+
settings.decimalSymbol = attrVal(dsEl, "val");
|
|
4107
|
+
}
|
|
4108
|
+
const lsEl = findChildNs(root, "listSeparator");
|
|
4109
|
+
if (lsEl) {
|
|
4110
|
+
settings.listSeparator = attrVal(lsEl, "val");
|
|
4111
|
+
}
|
|
4112
|
+
// RSID list
|
|
4113
|
+
const rsidsEl = findChildNs(root, "rsids");
|
|
4114
|
+
if (rsidsEl) {
|
|
4115
|
+
const rsids = {};
|
|
4116
|
+
const rootEl = findChildNs(rsidsEl, "rsidRoot");
|
|
4117
|
+
if (rootEl) {
|
|
4118
|
+
rsids.rsidRoot = attrVal(rootEl, "val");
|
|
4119
|
+
}
|
|
4120
|
+
const rsidList = [];
|
|
4121
|
+
for (const rsidEl of findChildrenNs(rsidsEl, "rsid")) {
|
|
4122
|
+
const v = attrVal(rsidEl, "val");
|
|
4123
|
+
if (v) {
|
|
4124
|
+
rsidList.push(v);
|
|
4125
|
+
}
|
|
4126
|
+
}
|
|
4127
|
+
if (rsidList.length > 0) {
|
|
4128
|
+
rsids.rsid = rsidList;
|
|
4129
|
+
}
|
|
4130
|
+
if (Object.keys(rsids).length > 0) {
|
|
4131
|
+
settings.rsids = rsids;
|
|
4132
|
+
}
|
|
4133
|
+
}
|
|
4134
|
+
if (findChildNs(root, "evenAndOddHeaders")) {
|
|
4135
|
+
settings.evenAndOddHeaders = true;
|
|
4136
|
+
}
|
|
4137
|
+
if (findChildNs(root, "trackRevisions")) {
|
|
4138
|
+
settings.trackRevisions = true;
|
|
4139
|
+
}
|
|
4140
|
+
if (findChildNs(root, "mirrorMargins")) {
|
|
4141
|
+
settings.mirrorMargins = true;
|
|
4142
|
+
}
|
|
4143
|
+
if (findChildNs(root, "gutterAtTop")) {
|
|
4144
|
+
settings.gutterAtTop = true;
|
|
4145
|
+
}
|
|
4146
|
+
if (findChildNs(root, "displayBackgroundShape")) {
|
|
4147
|
+
settings.displayBackgroundShape = true;
|
|
4148
|
+
}
|
|
4149
|
+
if (findChildNs(root, "updateFields")) {
|
|
4150
|
+
settings.updateFieldsOnOpen = true;
|
|
4151
|
+
}
|
|
4152
|
+
// Hyphenation
|
|
4153
|
+
const autoHyphEl = findChildNs(root, "autoHyphenation");
|
|
4154
|
+
if (autoHyphEl) {
|
|
4155
|
+
settings.autoHyphenation = true;
|
|
4156
|
+
const hyph = { autoHyphenation: true };
|
|
4157
|
+
const hzEl = findChildNs(root, "hyphenationZone");
|
|
4158
|
+
if (hzEl) {
|
|
4159
|
+
hyph.hyphenationZone = attrInt(hzEl, "val");
|
|
4160
|
+
}
|
|
4161
|
+
const chlEl = findChildNs(root, "consecutiveHyphenLimit");
|
|
4162
|
+
if (chlEl) {
|
|
4163
|
+
hyph.consecutiveHyphenLimit = attrInt(chlEl, "val");
|
|
4164
|
+
}
|
|
4165
|
+
if (findChildNs(root, "doNotHyphenateCaps")) {
|
|
4166
|
+
hyph.doNotHyphenateCaps = true;
|
|
4167
|
+
}
|
|
4168
|
+
settings.hyphenation = hyph;
|
|
4169
|
+
}
|
|
4170
|
+
// Document protection
|
|
4171
|
+
const protEl = findChildNs(root, "documentProtection");
|
|
4172
|
+
if (protEl) {
|
|
4173
|
+
settings.documentProtection = {
|
|
4174
|
+
type: attrVal(protEl, "edit") ?? "none",
|
|
4175
|
+
enforcement: attrVal(protEl, "enforcement") === "1"
|
|
4176
|
+
};
|
|
4177
|
+
}
|
|
4178
|
+
const compatEl = findChildNs(root, "compat");
|
|
4179
|
+
if (compatEl) {
|
|
4180
|
+
const compatSettings = [];
|
|
4181
|
+
const compatFlags = [];
|
|
4182
|
+
for (const csEl of compatEl.children) {
|
|
4183
|
+
if (csEl.type !== "element") {
|
|
4184
|
+
continue;
|
|
4185
|
+
}
|
|
4186
|
+
const localName = csEl.name.replace(/^w:/, "");
|
|
4187
|
+
if (localName === "compatSetting") {
|
|
4188
|
+
const name = attrVal(csEl, "name");
|
|
4189
|
+
const uri = attrVal(csEl, "uri");
|
|
4190
|
+
const val = attrVal(csEl, "val");
|
|
4191
|
+
if (name === "compatibilityMode" && val !== undefined) {
|
|
4192
|
+
settings.compatibilityMode = parseInt(val, 10);
|
|
4193
|
+
}
|
|
4194
|
+
else if (name !== undefined && uri !== undefined && val !== undefined) {
|
|
4195
|
+
compatSettings.push({ name, uri, val });
|
|
4196
|
+
}
|
|
4197
|
+
}
|
|
4198
|
+
else {
|
|
4199
|
+
// Legacy compat flags (w:useFELayout, w:balanceSingleByteDoubleByteWidth, etc.)
|
|
4200
|
+
compatFlags.push({ name: localName, val: attrVal(csEl, "val") });
|
|
4201
|
+
}
|
|
4202
|
+
}
|
|
4203
|
+
if (compatSettings.length > 0) {
|
|
4204
|
+
settings.compatSettings = compatSettings;
|
|
4205
|
+
}
|
|
4206
|
+
if (compatFlags.length > 0) {
|
|
4207
|
+
settings.compatFlags = compatFlags;
|
|
4208
|
+
}
|
|
4209
|
+
}
|
|
4210
|
+
// Mail merge settings (preserve as raw XML)
|
|
4211
|
+
const mailMergeEl = findChildNs(root, "mailMerge");
|
|
4212
|
+
if (mailMergeEl) {
|
|
4213
|
+
settings.mailMergeRawXml = serializeElement(mailMergeEl);
|
|
4214
|
+
}
|
|
4215
|
+
// Write protection
|
|
4216
|
+
const writeProtectionEl = findChildNs(root, "writeProtection");
|
|
4217
|
+
if (writeProtectionEl) {
|
|
4218
|
+
const wp = {};
|
|
4219
|
+
const recommended = attrVal(writeProtectionEl, "recommended");
|
|
4220
|
+
if (recommended === "1" || recommended === "true") {
|
|
4221
|
+
wp.recommended = true;
|
|
4222
|
+
}
|
|
4223
|
+
const algName = attrVal(writeProtectionEl, "algorithmName");
|
|
4224
|
+
if (algName) {
|
|
4225
|
+
wp.algorithmName = algName;
|
|
4226
|
+
}
|
|
4227
|
+
const hashValue = attrVal(writeProtectionEl, "hashValue");
|
|
4228
|
+
if (hashValue) {
|
|
4229
|
+
wp.hashValue = hashValue;
|
|
4230
|
+
}
|
|
4231
|
+
const saltValue = attrVal(writeProtectionEl, "saltValue");
|
|
4232
|
+
if (saltValue) {
|
|
4233
|
+
wp.saltValue = saltValue;
|
|
4234
|
+
}
|
|
4235
|
+
const spinCount = attrInt(writeProtectionEl, "spinCount");
|
|
4236
|
+
if (spinCount !== undefined) {
|
|
4237
|
+
wp.spinCount = spinCount;
|
|
4238
|
+
}
|
|
4239
|
+
settings.writeProtection = wp;
|
|
4240
|
+
}
|
|
4241
|
+
// Document variables
|
|
4242
|
+
const docVarsEl = findChildNs(root, "docVars");
|
|
4243
|
+
if (docVarsEl) {
|
|
4244
|
+
const vars = new Map();
|
|
4245
|
+
for (const dvEl of findChildrenNs(docVarsEl, "docVar")) {
|
|
4246
|
+
const name = attrVal(dvEl, "name");
|
|
4247
|
+
const val = attrVal(dvEl, "val");
|
|
4248
|
+
if (name !== undefined && val !== undefined) {
|
|
4249
|
+
vars.set(name, val);
|
|
4250
|
+
}
|
|
4251
|
+
}
|
|
4252
|
+
if (vars.size > 0) {
|
|
4253
|
+
settings.docVars = vars;
|
|
4254
|
+
}
|
|
4255
|
+
}
|
|
4256
|
+
// Footnote/endnote properties at document level
|
|
4257
|
+
const fnPrEl = findChildNs(root, "footnotePr");
|
|
4258
|
+
if (fnPrEl) {
|
|
4259
|
+
const fnProps = parseNoteProperties(fnPrEl);
|
|
4260
|
+
if (fnProps) {
|
|
4261
|
+
settings.footnoteProperties = fnProps;
|
|
4262
|
+
}
|
|
4263
|
+
}
|
|
4264
|
+
const enPrEl = findChildNs(root, "endnotePr");
|
|
4265
|
+
if (enPrEl) {
|
|
4266
|
+
const enProps = parseNoteProperties(enPrEl);
|
|
4267
|
+
if (enProps) {
|
|
4268
|
+
settings.endnoteProperties = enProps;
|
|
4269
|
+
}
|
|
4270
|
+
}
|
|
4271
|
+
return settings;
|
|
4272
|
+
}
|
|
4273
|
+
// =============================================================================
|
|
4274
|
+
// Custom Properties Parser
|
|
4275
|
+
// =============================================================================
|
|
4276
|
+
function parseCustomPropsXml(xmlStr) {
|
|
4277
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
4278
|
+
const root = doc.root;
|
|
4279
|
+
const props = [];
|
|
4280
|
+
for (const propEl of root.children) {
|
|
4281
|
+
if (propEl.type !== "element" || propEl.name !== "property") {
|
|
4282
|
+
continue;
|
|
4283
|
+
}
|
|
4284
|
+
const name = propEl.attributes["name"];
|
|
4285
|
+
if (!name) {
|
|
4286
|
+
continue;
|
|
4287
|
+
}
|
|
4288
|
+
let value;
|
|
4289
|
+
for (const child of propEl.children) {
|
|
4290
|
+
if (child.type !== "element") {
|
|
4291
|
+
continue;
|
|
4292
|
+
}
|
|
4293
|
+
const tn = child.name;
|
|
4294
|
+
const tv = (0, dom_1.textContent)(child);
|
|
4295
|
+
if (tn === "vt:lpwstr") {
|
|
4296
|
+
value = { type: "string", value: tv };
|
|
4297
|
+
}
|
|
4298
|
+
else if (tn === "vt:i4") {
|
|
4299
|
+
value = { type: "number", value: parseInt(tv, 10) };
|
|
4300
|
+
}
|
|
4301
|
+
else if (tn === "vt:r8") {
|
|
4302
|
+
value = { type: "number", value: parseFloat(tv) };
|
|
4303
|
+
}
|
|
4304
|
+
else if (tn === "vt:bool") {
|
|
4305
|
+
value = { type: "boolean", value: tv === "true" };
|
|
4306
|
+
}
|
|
4307
|
+
else if (tn === "vt:filetime") {
|
|
4308
|
+
value = { type: "date", value: new Date(tv) };
|
|
4309
|
+
}
|
|
4310
|
+
}
|
|
4311
|
+
if (value) {
|
|
4312
|
+
props.push({ name, value });
|
|
4313
|
+
}
|
|
4314
|
+
}
|
|
4315
|
+
return props;
|
|
4316
|
+
}
|
|
4317
|
+
// =============================================================================
|
|
4318
|
+
// Font Table Parser
|
|
4319
|
+
// =============================================================================
|
|
4320
|
+
function parseFontTableXml(xmlStr) {
|
|
4321
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
4322
|
+
const root = doc.root;
|
|
4323
|
+
const fonts = [];
|
|
4324
|
+
for (const fontEl of findChildrenNs(root, "font")) {
|
|
4325
|
+
const f = { name: attrVal(fontEl, "name") ?? "" };
|
|
4326
|
+
const p1 = findChildNs(fontEl, "panose1");
|
|
4327
|
+
if (p1) {
|
|
4328
|
+
f.panose1 = attrVal(p1, "val");
|
|
4329
|
+
}
|
|
4330
|
+
const cs = findChildNs(fontEl, "charset");
|
|
4331
|
+
if (cs) {
|
|
4332
|
+
f.charset = attrVal(cs, "val");
|
|
4333
|
+
}
|
|
4334
|
+
const fam = findChildNs(fontEl, "family");
|
|
4335
|
+
if (fam) {
|
|
4336
|
+
f.family = attrVal(fam, "val");
|
|
4337
|
+
}
|
|
4338
|
+
const pitch = findChildNs(fontEl, "pitch");
|
|
4339
|
+
if (pitch) {
|
|
4340
|
+
f.pitch = attrVal(pitch, "val");
|
|
4341
|
+
}
|
|
4342
|
+
// Signature
|
|
4343
|
+
const sigEl = findChildNs(fontEl, "sig");
|
|
4344
|
+
if (sigEl) {
|
|
4345
|
+
const sig = {};
|
|
4346
|
+
for (const key of ["usb0", "usb1", "usb2", "usb3", "csb0", "csb1"]) {
|
|
4347
|
+
const v = attrVal(sigEl, key);
|
|
4348
|
+
if (v !== undefined) {
|
|
4349
|
+
sig[key] = v;
|
|
4350
|
+
}
|
|
4351
|
+
}
|
|
4352
|
+
if (Object.keys(sig).length > 0) {
|
|
4353
|
+
f.sig = sig;
|
|
4354
|
+
}
|
|
4355
|
+
}
|
|
4356
|
+
// Embedded fonts
|
|
4357
|
+
for (const [tag, rIdKey, keyKey] of [
|
|
4358
|
+
["embedRegular", "embedRegular", "embedRegularKey"],
|
|
4359
|
+
["embedBold", "embedBold", "embedBoldKey"],
|
|
4360
|
+
["embedItalic", "embedItalic", "embedItalicKey"],
|
|
4361
|
+
["embedBoldItalic", "embedBoldItalic", "embedBoldItalicKey"]
|
|
4362
|
+
]) {
|
|
4363
|
+
const el = findChildNs(fontEl, tag);
|
|
4364
|
+
if (el) {
|
|
4365
|
+
const rId = el.attributes["r:id"] ?? el.attributes["id"];
|
|
4366
|
+
if (rId) {
|
|
4367
|
+
f[rIdKey] = rId;
|
|
4368
|
+
const fontKey = attrVal(el, "fontKey");
|
|
4369
|
+
if (fontKey) {
|
|
4370
|
+
f[keyKey] = fontKey;
|
|
4371
|
+
}
|
|
4372
|
+
}
|
|
4373
|
+
}
|
|
4374
|
+
}
|
|
4375
|
+
fonts.push(f);
|
|
4376
|
+
}
|
|
4377
|
+
return fonts;
|
|
4378
|
+
}
|
|
4379
|
+
function parseRelationships(xmlStr) {
|
|
4380
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
4381
|
+
const rels = [];
|
|
4382
|
+
for (const child of doc.root.children) {
|
|
4383
|
+
if (child.type === "element" && child.name === "Relationship") {
|
|
4384
|
+
rels.push({
|
|
4385
|
+
id: child.attributes["Id"] ?? "",
|
|
4386
|
+
type: child.attributes["Type"] ?? "",
|
|
4387
|
+
target: child.attributes["Target"] ?? "",
|
|
4388
|
+
targetMode: child.attributes["TargetMode"]
|
|
4389
|
+
});
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
return rels;
|
|
4393
|
+
}
|
|
4394
|
+
// =============================================================================
|
|
4395
|
+
// Main Document Parser
|
|
4396
|
+
// =============================================================================
|
|
4397
|
+
/** Recursively extract floating images, drawing shapes, and opaque drawings from an element tree. */
|
|
4398
|
+
function extractFloatingContent(el, images, shapes, opaqueDrawings) {
|
|
4399
|
+
for (const child of el.children) {
|
|
4400
|
+
if (child.type !== "element") {
|
|
4401
|
+
continue;
|
|
4402
|
+
}
|
|
4403
|
+
if (child.name === "wp:anchor") {
|
|
4404
|
+
// Check if this is a pic (image) or wsp (shape)
|
|
4405
|
+
const graphicEl = (0, dom_1.findChild)(child, "a:graphic");
|
|
4406
|
+
const graphicDataEl = graphicEl ? (0, dom_1.findChild)(graphicEl, "a:graphicData") : undefined;
|
|
4407
|
+
const wspEl = graphicDataEl
|
|
4408
|
+
? ((0, dom_1.findChild)(graphicDataEl, "wps:wsp") ?? findChildNs(graphicDataEl, "wsp"))
|
|
4409
|
+
: undefined;
|
|
4410
|
+
if (wspEl) {
|
|
4411
|
+
const shape = parseDrawingShape(child, wspEl);
|
|
4412
|
+
if (shape) {
|
|
4413
|
+
shapes.push(shape);
|
|
4414
|
+
}
|
|
4415
|
+
}
|
|
4416
|
+
else {
|
|
4417
|
+
const fi = parseFloatingImage(child);
|
|
4418
|
+
if (fi) {
|
|
4419
|
+
images.push(fi);
|
|
4420
|
+
}
|
|
4421
|
+
else {
|
|
4422
|
+
// Unknown anchor content (chart, diagram, etc.) — preserve as opaque
|
|
4423
|
+
const drawingEl = findDrawingParent(child);
|
|
4424
|
+
if (drawingEl) {
|
|
4425
|
+
const rids = new Set();
|
|
4426
|
+
collectRIds(drawingEl, rids);
|
|
4427
|
+
opaqueDrawings.push({
|
|
4428
|
+
type: "opaqueDrawing",
|
|
4429
|
+
rawXml: serializeElement(drawingEl),
|
|
4430
|
+
referencedRIds: [...rids]
|
|
4431
|
+
});
|
|
4432
|
+
}
|
|
4433
|
+
}
|
|
4434
|
+
}
|
|
4435
|
+
}
|
|
4436
|
+
else if (child.name === "wp:inline") {
|
|
4437
|
+
// Inline drawings that aren't images — check for chart etc.
|
|
4438
|
+
const graphicEl = (0, dom_1.findChild)(child, "a:graphic");
|
|
4439
|
+
const graphicDataEl = graphicEl ? (0, dom_1.findChild)(graphicEl, "a:graphicData") : undefined;
|
|
4440
|
+
if (graphicDataEl) {
|
|
4441
|
+
const picEl = (0, dom_1.findChild)(graphicDataEl, "pic:pic") ?? findChildNs(graphicDataEl, "pic");
|
|
4442
|
+
if (!picEl) {
|
|
4443
|
+
// Not an image — opaque inline drawing
|
|
4444
|
+
// Find the w:drawing parent
|
|
4445
|
+
const rids = new Set();
|
|
4446
|
+
collectRIds(child, rids);
|
|
4447
|
+
// Serialize the wp:inline element wrapped in w:drawing
|
|
4448
|
+
const rawXml = `<w:drawing>${serializeElement(child)}</w:drawing>`;
|
|
4449
|
+
opaqueDrawings.push({
|
|
4450
|
+
type: "opaqueDrawing",
|
|
4451
|
+
rawXml,
|
|
4452
|
+
referencedRIds: [...rids]
|
|
4453
|
+
});
|
|
4454
|
+
}
|
|
4455
|
+
}
|
|
4456
|
+
}
|
|
4457
|
+
else {
|
|
4458
|
+
extractFloatingContent(child, images, shapes, opaqueDrawings);
|
|
4459
|
+
}
|
|
4460
|
+
}
|
|
4461
|
+
}
|
|
4462
|
+
/** Find the w:drawing ancestor element for serialization. */
|
|
4463
|
+
function findDrawingParent(anchorEl) {
|
|
4464
|
+
// We don't have parent refs, so we construct a synthetic w:drawing wrapper
|
|
4465
|
+
return {
|
|
4466
|
+
type: "element",
|
|
4467
|
+
name: "w:drawing",
|
|
4468
|
+
attributes: {},
|
|
4469
|
+
children: [anchorEl]
|
|
4470
|
+
};
|
|
4471
|
+
}
|
|
4472
|
+
function parseDocumentXml(xmlStr) {
|
|
4473
|
+
const doc = (0, dom_1.parseXml)(xmlStr);
|
|
4474
|
+
const root = doc.root;
|
|
4475
|
+
// Parse background
|
|
4476
|
+
let background;
|
|
4477
|
+
const bgEl = findChildNs(root, "background");
|
|
4478
|
+
if (bgEl) {
|
|
4479
|
+
const bg = {};
|
|
4480
|
+
const color = attrVal(bgEl, "color");
|
|
4481
|
+
if (color) {
|
|
4482
|
+
bg.color = color;
|
|
4483
|
+
}
|
|
4484
|
+
const themeColor = attrVal(bgEl, "themeColor");
|
|
4485
|
+
if (themeColor) {
|
|
4486
|
+
bg.themeColor = themeColor;
|
|
4487
|
+
}
|
|
4488
|
+
const themeShade = attrVal(bgEl, "themeShade");
|
|
4489
|
+
if (themeShade) {
|
|
4490
|
+
bg.themeShade = themeShade;
|
|
4491
|
+
}
|
|
4492
|
+
const themeTint = attrVal(bgEl, "themeTint");
|
|
4493
|
+
if (themeTint) {
|
|
4494
|
+
bg.themeTint = themeTint;
|
|
4495
|
+
}
|
|
4496
|
+
background = bg;
|
|
4497
|
+
}
|
|
4498
|
+
const bodyEl = findChildNs(root, "body") ?? (0, dom_1.findChild)(root, "w:body");
|
|
4499
|
+
if (!bodyEl) {
|
|
4500
|
+
throw new errors_1.DocxParseError("Missing w:body element in document.xml");
|
|
4501
|
+
}
|
|
4502
|
+
const body = [];
|
|
4503
|
+
let sectionProperties;
|
|
4504
|
+
// Collect floating images, drawing shapes, and opaque drawings from the whole body
|
|
4505
|
+
const floatingImages = [];
|
|
4506
|
+
const drawingShapes = [];
|
|
4507
|
+
const opaqueDrawings = [];
|
|
4508
|
+
extractFloatingContent(bodyEl, floatingImages, drawingShapes, opaqueDrawings);
|
|
4509
|
+
for (const child of bodyEl.children) {
|
|
4510
|
+
if (child.type !== "element") {
|
|
4511
|
+
continue;
|
|
4512
|
+
}
|
|
4513
|
+
const name = child.name.replace(/^w:/, "");
|
|
4514
|
+
switch (name) {
|
|
4515
|
+
case "p":
|
|
4516
|
+
body.push(parseParagraph(child));
|
|
4517
|
+
break;
|
|
4518
|
+
case "tbl":
|
|
4519
|
+
body.push(parseTable(child));
|
|
4520
|
+
break;
|
|
4521
|
+
case "sectPr":
|
|
4522
|
+
// Final section properties at the body level
|
|
4523
|
+
sectionProperties = parseSectionProperties(child);
|
|
4524
|
+
break;
|
|
4525
|
+
case "sdt": {
|
|
4526
|
+
const sdtResult = parseSdt(child);
|
|
4527
|
+
if (sdtResult) {
|
|
4528
|
+
body.push(sdtResult);
|
|
4529
|
+
}
|
|
4530
|
+
break;
|
|
4531
|
+
}
|
|
4532
|
+
case "altChunk": {
|
|
4533
|
+
const rId = child.attributes["r:id"] ?? child.attributes["id"];
|
|
4534
|
+
if (rId) {
|
|
4535
|
+
body.push({ type: "altChunk", rId });
|
|
4536
|
+
}
|
|
4537
|
+
break;
|
|
4538
|
+
}
|
|
4539
|
+
default: {
|
|
4540
|
+
// Check for math namespace
|
|
4541
|
+
if (child.name === "m:oMathPara") {
|
|
4542
|
+
body.push(parseMathBlock(child));
|
|
4543
|
+
}
|
|
4544
|
+
else if (child.name === "m:oMath") {
|
|
4545
|
+
body.push({ type: "math", content: parseMathContent(child) });
|
|
4546
|
+
}
|
|
4547
|
+
// Check for VML pict (textbox)
|
|
4548
|
+
if (name === "pict" || child.name === "w:pict") {
|
|
4549
|
+
const tb = parseTextBox(child);
|
|
4550
|
+
if (tb) {
|
|
4551
|
+
body.push(tb);
|
|
4552
|
+
}
|
|
4553
|
+
}
|
|
4554
|
+
break;
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
}
|
|
4558
|
+
// Append floating images as top-level body content
|
|
4559
|
+
for (const fi of floatingImages) {
|
|
4560
|
+
body.push(fi);
|
|
4561
|
+
}
|
|
4562
|
+
// Append drawing shapes as top-level body content
|
|
4563
|
+
for (const ds of drawingShapes) {
|
|
4564
|
+
body.push(ds);
|
|
4565
|
+
}
|
|
4566
|
+
// Append opaque drawings as top-level body content
|
|
4567
|
+
for (const od of opaqueDrawings) {
|
|
4568
|
+
body.push(od);
|
|
4569
|
+
}
|
|
4570
|
+
return { body, sectionProperties, background };
|
|
4571
|
+
}
|
|
4572
|
+
// =============================================================================
|
|
4573
|
+
// Public API - Read DOCX
|
|
4574
|
+
// =============================================================================
|
|
4575
|
+
/**
|
|
4576
|
+
* Read a DOCX file from a Uint8Array buffer and parse it into a DocxDocument model.
|
|
4577
|
+
*/
|
|
4578
|
+
async function readDocx(buffer) {
|
|
4579
|
+
try {
|
|
4580
|
+
return await _readDocxInner(buffer);
|
|
4581
|
+
}
|
|
4582
|
+
catch (e) {
|
|
4583
|
+
if (e instanceof errors_1.DocxError) {
|
|
4584
|
+
throw e;
|
|
4585
|
+
}
|
|
4586
|
+
const msg = e instanceof Error ? e.message : String(e);
|
|
4587
|
+
throw new errors_1.DocxParseError(`Failed to read DOCX: ${msg}`, { cause: e });
|
|
4588
|
+
}
|
|
4589
|
+
}
|
|
4590
|
+
async function _readDocxInner(buffer) {
|
|
4591
|
+
const reader = (0, read_archive_1.unzip)(buffer);
|
|
4592
|
+
const entries = new Map();
|
|
4593
|
+
for await (const entry of reader.entries()) {
|
|
4594
|
+
const data = await entry.bytes();
|
|
4595
|
+
// Normalize path: remove leading slash, normalize separators
|
|
4596
|
+
const path = entry.path.replace(/^\//, "").replace(/\\/g, "/");
|
|
4597
|
+
entries.set(path, data);
|
|
4598
|
+
}
|
|
4599
|
+
const decoder = new TextDecoder("utf-8");
|
|
4600
|
+
const consumedPaths = new Set(["[Content_Types].xml"]);
|
|
4601
|
+
const getText = (path) => {
|
|
4602
|
+
const data = entries.get(path);
|
|
4603
|
+
if (data) {
|
|
4604
|
+
consumedPaths.add(path);
|
|
4605
|
+
}
|
|
4606
|
+
return data ? decoder.decode(data) : undefined;
|
|
4607
|
+
};
|
|
4608
|
+
// Parse document relationships (must be before parseDocumentXml for hyperlink resolution)
|
|
4609
|
+
const docRelsXml = getText("word/_rels/document.xml.rels");
|
|
4610
|
+
const docRels = docRelsXml ? parseRelationships(docRelsXml) : [];
|
|
4611
|
+
const _relMap = new Map(docRels.map(r => [r.id, r]));
|
|
4612
|
+
// Set module-level context for parseParagraph hyperlink resolution
|
|
4613
|
+
_parseRelMap = _relMap;
|
|
4614
|
+
// Parse document.xml (required)
|
|
4615
|
+
const documentXml = getText("word/document.xml");
|
|
4616
|
+
if (!documentXml) {
|
|
4617
|
+
throw new errors_1.DocxMissingPartError("word/document.xml");
|
|
4618
|
+
}
|
|
4619
|
+
const { body, sectionProperties, background } = parseDocumentXml(documentXml);
|
|
4620
|
+
// Parse styles
|
|
4621
|
+
const stylesXml = getText("word/styles.xml");
|
|
4622
|
+
const stylesResult = stylesXml ? parseStyles(stylesXml) : undefined;
|
|
4623
|
+
// Parse numbering
|
|
4624
|
+
const numberingXml = getText("word/numbering.xml");
|
|
4625
|
+
const numberingResult = numberingXml ? parseNumberingXml(numberingXml) : undefined;
|
|
4626
|
+
// Parse footnotes/endnotes
|
|
4627
|
+
const footnotesXml = getText("word/footnotes.xml");
|
|
4628
|
+
const footnotes = footnotesXml ? parseNotesXml(footnotesXml, "footnote") : undefined;
|
|
4629
|
+
const endnotesXml = getText("word/endnotes.xml");
|
|
4630
|
+
const endnotes = endnotesXml ? parseNotesXml(endnotesXml, "endnote") : undefined;
|
|
4631
|
+
// Parse headers/footers + detect watermarks
|
|
4632
|
+
const headers = new Map();
|
|
4633
|
+
const footers = new Map();
|
|
4634
|
+
let watermark;
|
|
4635
|
+
for (const rel of docRels) {
|
|
4636
|
+
if (rel.type === constants_1.RelType.Header) {
|
|
4637
|
+
const xml = getText(resolvePartPath("word/document.xml", rel.target));
|
|
4638
|
+
if (xml) {
|
|
4639
|
+
// Parse XML once, re-use for both header content and watermark detection
|
|
4640
|
+
const headerRoot = (0, dom_1.parseXml)(xml).root;
|
|
4641
|
+
headers.set(rel.id, { content: parseHeaderFooterRoot(headerRoot), rId: rel.id });
|
|
4642
|
+
if (!watermark) {
|
|
4643
|
+
watermark = detectWatermarkFromRoot(headerRoot);
|
|
4644
|
+
}
|
|
4645
|
+
}
|
|
4646
|
+
}
|
|
4647
|
+
else if (rel.type === constants_1.RelType.Footer) {
|
|
4648
|
+
const xml = getText(resolvePartPath("word/document.xml", rel.target));
|
|
4649
|
+
if (xml) {
|
|
4650
|
+
footers.set(rel.id, { content: parseHeaderFooterXml(xml), rId: rel.id });
|
|
4651
|
+
}
|
|
4652
|
+
}
|
|
4653
|
+
}
|
|
4654
|
+
// Parse settings
|
|
4655
|
+
const settingsXml = getText("word/settings.xml");
|
|
4656
|
+
const settings = settingsXml ? parseSettingsXml(settingsXml) : undefined;
|
|
4657
|
+
// Parse web settings
|
|
4658
|
+
const webSettingsXml = getText("word/webSettings.xml");
|
|
4659
|
+
const webSettings = webSettingsXml ? parseWebSettings(webSettingsXml) : undefined;
|
|
4660
|
+
// Parse people
|
|
4661
|
+
const peopleXml = getText("word/people.xml");
|
|
4662
|
+
const people = peopleXml ? parsePeople(peopleXml) : undefined;
|
|
4663
|
+
// Parse thumbnail (from package rels)
|
|
4664
|
+
let thumbnail;
|
|
4665
|
+
const packageRelsXml = getText("_rels/.rels");
|
|
4666
|
+
if (packageRelsXml) {
|
|
4667
|
+
const pkgRels = parseRelationships(packageRelsXml);
|
|
4668
|
+
for (const rel of pkgRels) {
|
|
4669
|
+
if (rel.type.endsWith("/thumbnail")) {
|
|
4670
|
+
// Target in package rels is relative to package root; may include or exclude leading slash
|
|
4671
|
+
let target = rel.target;
|
|
4672
|
+
if (target.startsWith("/")) {
|
|
4673
|
+
target = target.substring(1);
|
|
4674
|
+
}
|
|
4675
|
+
// If the target doesn't include docProps/ prefix, add it (some writers emit bare filenames)
|
|
4676
|
+
const normalized = target.includes("/") ? target : `docProps/${target}`;
|
|
4677
|
+
consumedPaths.add(normalized);
|
|
4678
|
+
const thumbData = entries.get(normalized);
|
|
4679
|
+
if (thumbData) {
|
|
4680
|
+
const ext = normalized.split(".").pop()?.toLowerCase();
|
|
4681
|
+
const ct = ext === "jpeg" || ext === "jpg"
|
|
4682
|
+
? "image/jpeg"
|
|
4683
|
+
: ext === "png"
|
|
4684
|
+
? "image/png"
|
|
4685
|
+
: "image/x-wmf";
|
|
4686
|
+
thumbnail = { contentType: ct, data: thumbData };
|
|
4687
|
+
}
|
|
4688
|
+
break;
|
|
4689
|
+
}
|
|
4690
|
+
}
|
|
4691
|
+
}
|
|
4692
|
+
// Parse font table
|
|
4693
|
+
const fontTableXml = getText("word/fontTable.xml");
|
|
4694
|
+
const fonts = fontTableXml ? parseFontTableXml(fontTableXml) : undefined;
|
|
4695
|
+
// Parse embedded fonts
|
|
4696
|
+
let embeddedFonts;
|
|
4697
|
+
const fontTableRelsXml = getText("word/_rels/fontTable.xml.rels");
|
|
4698
|
+
if (fontTableRelsXml && fonts) {
|
|
4699
|
+
const fontRels = parseRelationships(fontTableRelsXml);
|
|
4700
|
+
const efs = [];
|
|
4701
|
+
// Build rId → { key } map from font table
|
|
4702
|
+
const rIdToKey = new Map();
|
|
4703
|
+
for (const f of fonts) {
|
|
4704
|
+
if (f.embedRegular && f.embedRegularKey) {
|
|
4705
|
+
rIdToKey.set(f.embedRegular, f.embedRegularKey);
|
|
4706
|
+
}
|
|
4707
|
+
if (f.embedBold && f.embedBoldKey) {
|
|
4708
|
+
rIdToKey.set(f.embedBold, f.embedBoldKey);
|
|
4709
|
+
}
|
|
4710
|
+
if (f.embedItalic && f.embedItalicKey) {
|
|
4711
|
+
rIdToKey.set(f.embedItalic, f.embedItalicKey);
|
|
4712
|
+
}
|
|
4713
|
+
if (f.embedBoldItalic && f.embedBoldItalicKey) {
|
|
4714
|
+
rIdToKey.set(f.embedBoldItalic, f.embedBoldItalicKey);
|
|
4715
|
+
}
|
|
4716
|
+
}
|
|
4717
|
+
for (const rel of fontRels) {
|
|
4718
|
+
if (rel.type === constants_1.RelType.Font) {
|
|
4719
|
+
const fontPath = resolvePartPath("word/fontTable.xml", rel.target);
|
|
4720
|
+
consumedPaths.add(fontPath);
|
|
4721
|
+
const data = entries.get(fontPath);
|
|
4722
|
+
if (data) {
|
|
4723
|
+
const fileName = rel.target.split("/").pop() ?? "";
|
|
4724
|
+
const fontKey = rIdToKey.get(rel.id);
|
|
4725
|
+
const ef = {
|
|
4726
|
+
rId: rel.id,
|
|
4727
|
+
data,
|
|
4728
|
+
fileName
|
|
4729
|
+
};
|
|
4730
|
+
if (fontKey) {
|
|
4731
|
+
ef.fontKey = fontKey;
|
|
4732
|
+
}
|
|
4733
|
+
efs.push(ef);
|
|
4734
|
+
}
|
|
4735
|
+
}
|
|
4736
|
+
}
|
|
4737
|
+
if (efs.length > 0) {
|
|
4738
|
+
embeddedFonts = efs;
|
|
4739
|
+
}
|
|
4740
|
+
}
|
|
4741
|
+
// Parse Custom XML parts (for SDT data binding)
|
|
4742
|
+
const customXmlParts = [];
|
|
4743
|
+
for (const rel of docRels) {
|
|
4744
|
+
if (rel.type === constants_1.RelType.CustomXml) {
|
|
4745
|
+
const targetPath = resolvePartPath("word/document.xml", rel.target);
|
|
4746
|
+
consumedPaths.add(targetPath);
|
|
4747
|
+
const xmlContent = getText(targetPath);
|
|
4748
|
+
if (!xmlContent) {
|
|
4749
|
+
continue;
|
|
4750
|
+
}
|
|
4751
|
+
// Parse itemProps*.xml to get storeItemID
|
|
4752
|
+
const fileName = targetPath.split("/").pop() ?? "";
|
|
4753
|
+
// itemProps file is typically at the same directory
|
|
4754
|
+
const dir = targetPath.substring(0, targetPath.lastIndexOf("/"));
|
|
4755
|
+
// Extract item number from fileName (e.g. "item1.xml" → "1")
|
|
4756
|
+
const match = fileName.match(/item(\d+)\.xml$/);
|
|
4757
|
+
let itemId = "";
|
|
4758
|
+
let schemaReferences;
|
|
4759
|
+
if (match) {
|
|
4760
|
+
const num = match[1];
|
|
4761
|
+
const propsPath = `${dir}/itemProps${num}.xml`;
|
|
4762
|
+
consumedPaths.add(propsPath);
|
|
4763
|
+
const propsXml = getText(propsPath);
|
|
4764
|
+
if (propsXml) {
|
|
4765
|
+
const propsDoc = (0, dom_1.parseXml)(propsXml);
|
|
4766
|
+
const dsItemEl = propsDoc.root;
|
|
4767
|
+
const id = dsItemEl.attributes["ds:itemID"];
|
|
4768
|
+
if (id) {
|
|
4769
|
+
itemId = id.replace(/[{}]/g, "");
|
|
4770
|
+
}
|
|
4771
|
+
// Schema references
|
|
4772
|
+
const refs = [];
|
|
4773
|
+
const schemaRefsEl = (0, dom_1.findChild)(dsItemEl, "ds:schemaRefs") ?? (0, dom_1.findChild)(dsItemEl, "schemaRefs");
|
|
4774
|
+
if (schemaRefsEl) {
|
|
4775
|
+
for (const srChild of schemaRefsEl.children) {
|
|
4776
|
+
if (srChild.type === "element") {
|
|
4777
|
+
const uri = srChild.attributes["ds:uri"] ?? srChild.attributes["uri"];
|
|
4778
|
+
if (uri) {
|
|
4779
|
+
refs.push(uri);
|
|
4780
|
+
}
|
|
4781
|
+
}
|
|
4782
|
+
}
|
|
4783
|
+
}
|
|
4784
|
+
if (refs.length > 0) {
|
|
4785
|
+
schemaReferences = refs;
|
|
4786
|
+
}
|
|
4787
|
+
}
|
|
4788
|
+
}
|
|
4789
|
+
customXmlParts.push({
|
|
4790
|
+
itemId,
|
|
4791
|
+
xmlContent,
|
|
4792
|
+
fileName,
|
|
4793
|
+
schemaReferences
|
|
4794
|
+
});
|
|
4795
|
+
}
|
|
4796
|
+
}
|
|
4797
|
+
// Parse core properties
|
|
4798
|
+
const corePropsXml = getText("docProps/core.xml");
|
|
4799
|
+
const coreProperties = corePropsXml ? parseCoreProps(corePropsXml) : undefined;
|
|
4800
|
+
// Parse app properties
|
|
4801
|
+
const appPropsXml = getText("docProps/app.xml");
|
|
4802
|
+
const appProperties = appPropsXml ? parseAppProps(appPropsXml) : undefined;
|
|
4803
|
+
// Parse comments
|
|
4804
|
+
const commentsXml = getText("word/comments.xml");
|
|
4805
|
+
let comments = commentsXml ? parseCommentsXml(commentsXml) : undefined;
|
|
4806
|
+
// Merge in commentsExtended.xml data if present
|
|
4807
|
+
const commentsExtXml = getText("word/commentsExtended.xml");
|
|
4808
|
+
if (commentsExtXml && comments) {
|
|
4809
|
+
const extMap = parseCommentsExtendedXml(commentsExtXml);
|
|
4810
|
+
comments = comments.map(c => {
|
|
4811
|
+
const firstPara = c.content[0];
|
|
4812
|
+
if (!firstPara?.paraId) {
|
|
4813
|
+
return c;
|
|
4814
|
+
}
|
|
4815
|
+
const ext = extMap.get(firstPara.paraId);
|
|
4816
|
+
if (!ext) {
|
|
4817
|
+
return c;
|
|
4818
|
+
}
|
|
4819
|
+
return {
|
|
4820
|
+
...c,
|
|
4821
|
+
...(ext.done !== undefined ? { done: ext.done } : {}),
|
|
4822
|
+
...(ext.parentId !== undefined ? { parentId: ext.parentId } : {})
|
|
4823
|
+
};
|
|
4824
|
+
});
|
|
4825
|
+
}
|
|
4826
|
+
// Parse custom properties
|
|
4827
|
+
const customPropsXml = getText("docProps/custom.xml");
|
|
4828
|
+
const customProperties = customPropsXml ? parseCustomPropsXml(customPropsXml) : undefined;
|
|
4829
|
+
// Parse theme
|
|
4830
|
+
const themeXml = getText("word/theme/theme1.xml");
|
|
4831
|
+
const theme = themeXml ? parseThemeXml(themeXml) : undefined;
|
|
4832
|
+
// Collect images
|
|
4833
|
+
const images = [];
|
|
4834
|
+
for (const rel of docRels) {
|
|
4835
|
+
if (rel.type === constants_1.RelType.Image) {
|
|
4836
|
+
const imgPath = resolvePartPath("word/document.xml", rel.target);
|
|
4837
|
+
consumedPaths.add(imgPath);
|
|
4838
|
+
const data = entries.get(imgPath);
|
|
4839
|
+
if (data) {
|
|
4840
|
+
const fileName = rel.target.split("/").pop() ?? "";
|
|
4841
|
+
const ext = fileName.split(".").pop()?.toLowerCase() ?? "png";
|
|
4842
|
+
images.push({
|
|
4843
|
+
data,
|
|
4844
|
+
mediaType: ext,
|
|
4845
|
+
fileName,
|
|
4846
|
+
rId: rel.id
|
|
4847
|
+
});
|
|
4848
|
+
}
|
|
4849
|
+
}
|
|
4850
|
+
}
|
|
4851
|
+
// Collect opaque (unrecognized) parts for round-trip preservation
|
|
4852
|
+
const opaqueParts = [];
|
|
4853
|
+
for (const [path, data] of entries) {
|
|
4854
|
+
// Skip consumed paths and all .rels files (structural)
|
|
4855
|
+
if (consumedPaths.has(path) || path.includes("_rels/")) {
|
|
4856
|
+
continue;
|
|
4857
|
+
}
|
|
4858
|
+
// Parse rels for this part if they exist
|
|
4859
|
+
const partRelsPath = getPartRelsPath(path);
|
|
4860
|
+
const partRelsData = entries.get(partRelsPath);
|
|
4861
|
+
let relationships;
|
|
4862
|
+
if (partRelsData) {
|
|
4863
|
+
const rels = parseRelationships(decoder.decode(partRelsData));
|
|
4864
|
+
relationships = rels.map(r => ({
|
|
4865
|
+
id: r.id,
|
|
4866
|
+
type: r.type,
|
|
4867
|
+
target: r.target,
|
|
4868
|
+
targetMode: r.targetMode === "External" ? "External" : undefined
|
|
4869
|
+
}));
|
|
4870
|
+
}
|
|
4871
|
+
opaqueParts.push({ path, data, relationships });
|
|
4872
|
+
}
|
|
4873
|
+
// Resolve altChunk data: body elements of type "altChunk" reference a rId.
|
|
4874
|
+
// The target file is stored in docRels + entries. Move target data from entries
|
|
4875
|
+
// (and remove from opaqueParts, since it's now part of the altChunk body element).
|
|
4876
|
+
for (const item of body) {
|
|
4877
|
+
if (item.type === "altChunk" && item.rId) {
|
|
4878
|
+
const rel = _relMap.get(item.rId);
|
|
4879
|
+
if (rel) {
|
|
4880
|
+
const target = resolvePartPath("word/document.xml", rel.target);
|
|
4881
|
+
const targetData = entries.get(target);
|
|
4882
|
+
if (targetData) {
|
|
4883
|
+
const fileName = target.split("/").pop();
|
|
4884
|
+
item.data = targetData;
|
|
4885
|
+
item.fileName = fileName;
|
|
4886
|
+
// Infer content type from extension
|
|
4887
|
+
const ext = fileName?.split(".").pop()?.toLowerCase();
|
|
4888
|
+
if (ext === "html" || ext === "htm") {
|
|
4889
|
+
item.contentType = "text/html";
|
|
4890
|
+
}
|
|
4891
|
+
else if (ext === "rtf") {
|
|
4892
|
+
item.contentType = "text/rtf";
|
|
4893
|
+
}
|
|
4894
|
+
else if (ext === "txt") {
|
|
4895
|
+
item.contentType = "text/plain";
|
|
4896
|
+
}
|
|
4897
|
+
}
|
|
4898
|
+
}
|
|
4899
|
+
}
|
|
4900
|
+
}
|
|
4901
|
+
return {
|
|
4902
|
+
body,
|
|
4903
|
+
sectionProperties,
|
|
4904
|
+
styles: stylesResult?.styles,
|
|
4905
|
+
docDefaults: stylesResult?.docDefaults,
|
|
4906
|
+
abstractNumberings: numberingResult?.abstractNums,
|
|
4907
|
+
numberingInstances: numberingResult?.instances,
|
|
4908
|
+
numPicBullets: numberingResult?.numPicBullets && numberingResult.numPicBullets.length > 0
|
|
4909
|
+
? numberingResult.numPicBullets
|
|
4910
|
+
: undefined,
|
|
4911
|
+
headers: headers.size > 0 ? headers : undefined,
|
|
4912
|
+
footers: footers.size > 0 ? footers : undefined,
|
|
4913
|
+
footnotes: footnotes && footnotes.length > 0 ? footnotes : undefined,
|
|
4914
|
+
endnotes: endnotes && endnotes.length > 0 ? endnotes : undefined,
|
|
4915
|
+
images: images.length > 0 ? images : undefined,
|
|
4916
|
+
fonts: fonts && fonts.length > 0 ? fonts : undefined,
|
|
4917
|
+
embeddedFonts: embeddedFonts && embeddedFonts.length > 0 ? embeddedFonts : undefined,
|
|
4918
|
+
customXmlParts: customXmlParts.length > 0 ? customXmlParts : undefined,
|
|
4919
|
+
webSettings,
|
|
4920
|
+
thumbnail,
|
|
4921
|
+
people: people && people.length > 0 ? people : undefined,
|
|
4922
|
+
settings,
|
|
4923
|
+
coreProperties,
|
|
4924
|
+
appProperties,
|
|
4925
|
+
comments: comments && comments.length > 0 ? comments : undefined,
|
|
4926
|
+
background,
|
|
4927
|
+
customProperties: customProperties && customProperties.length > 0 ? customProperties : undefined,
|
|
4928
|
+
theme,
|
|
4929
|
+
watermark,
|
|
4930
|
+
opaqueParts: opaqueParts.length > 0 ? opaqueParts : undefined
|
|
4931
|
+
};
|
|
4932
|
+
}
|