@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,1557 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shape property (spPr) and text property (txPr) utilities.
|
|
3
|
+
*
|
|
4
|
+
* During chart parsing, spPr and txPr elements are captured as raw XML strings
|
|
5
|
+
* for perfect round-trip fidelity. These utilities provide structured read/write
|
|
6
|
+
* access to the most commonly used properties:
|
|
7
|
+
*
|
|
8
|
+
* - Fill color (solid sRGB / theme)
|
|
9
|
+
* - Line/outline color and width
|
|
10
|
+
* - Font size, bold, italic, color, family
|
|
11
|
+
*
|
|
12
|
+
* The approach: parse raw XML on demand using regex extraction (no full DOM),
|
|
13
|
+
* and generate raw XML from structured models when creating new properties.
|
|
14
|
+
*/
|
|
15
|
+
// ============================================================================
|
|
16
|
+
// Raw XML access helpers
|
|
17
|
+
// ============================================================================
|
|
18
|
+
/** Get the raw XML string if the object was captured as raw XML. */
|
|
19
|
+
function getRawXml(obj) {
|
|
20
|
+
return obj?._rawXml;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Check if the object is purely a raw XML capture — `_rawXml` is set
|
|
24
|
+
* and NO structured fields have been populated. The parser produces
|
|
25
|
+
* dual-state objects (both `_rawXml` and structured) from raw bytes so
|
|
26
|
+
* downstream consumers get the best of both worlds: cheap byte-perfect
|
|
27
|
+
* round-trip PLUS typed access. Getters (`getSpPrFillColor` et al.)
|
|
28
|
+
* must prefer structured when present; setters must NOT reparse from
|
|
29
|
+
* `_rawXml` because doing so wipes any prior structured mutation.
|
|
30
|
+
*
|
|
31
|
+
* Writers must ALSO consult this predicate before short-circuiting to
|
|
32
|
+
* the raw bytes: if the model has been mutated through a direct
|
|
33
|
+
* property assignment (`spPr.fill = {...}` without routing through
|
|
34
|
+
* `setSpPrFill`), the raw bytes are stale and the structured path
|
|
35
|
+
* must win. Exported for use by `_renderSpPr` in both the classic
|
|
36
|
+
* chart-space xform and the ChartEx renderer.
|
|
37
|
+
*
|
|
38
|
+
* Previously `isRawXml` returned `true` whenever `_rawXml` was a
|
|
39
|
+
* string, which caused `setSpPrFill` → `parseSpPr` to re-read from
|
|
40
|
+
* raw and discard pending `line.width` / `fill.solid` assignments.
|
|
41
|
+
*/
|
|
42
|
+
export function isRawXmlShape(obj) {
|
|
43
|
+
return isRawXml(obj);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Whether a `ChartTextProperties` object is a pure raw-XML capture
|
|
47
|
+
* with no structured fields set. Analogous to {@link isRawXmlShape}
|
|
48
|
+
* for shape properties: when a caller directly assigns `txPr.color`,
|
|
49
|
+
* `txPr.size`, etc., the stale `_rawXml` must NOT win — the writer
|
|
50
|
+
* should fall through to the structured rendering path.
|
|
51
|
+
*/
|
|
52
|
+
export function isRawXmlTxPr(obj) {
|
|
53
|
+
if (!obj || typeof obj._rawXml !== "string") {
|
|
54
|
+
return false;
|
|
55
|
+
}
|
|
56
|
+
const structuredKeys = [
|
|
57
|
+
"size",
|
|
58
|
+
"bold",
|
|
59
|
+
"italic",
|
|
60
|
+
"underline",
|
|
61
|
+
"strike",
|
|
62
|
+
"color",
|
|
63
|
+
"fontFamily",
|
|
64
|
+
"eastAsianFamily",
|
|
65
|
+
"complexScriptFamily",
|
|
66
|
+
"rotation",
|
|
67
|
+
"baseline",
|
|
68
|
+
"kern",
|
|
69
|
+
"spacing",
|
|
70
|
+
"cap",
|
|
71
|
+
"lang"
|
|
72
|
+
];
|
|
73
|
+
for (const key of structuredKeys) {
|
|
74
|
+
if (obj[key] !== undefined) {
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
return true;
|
|
79
|
+
}
|
|
80
|
+
function isRawXml(obj) {
|
|
81
|
+
if (!obj || typeof obj._rawXml !== "string") {
|
|
82
|
+
return false;
|
|
83
|
+
}
|
|
84
|
+
// "Purely raw" when no structured field is present. Enumerate the
|
|
85
|
+
// fields we care about so adding new structured slots to
|
|
86
|
+
// `ShapeProperties` doesn't require touching this predicate —
|
|
87
|
+
// anything absent from this list is either raw-bytes-only (like
|
|
88
|
+
// `extLst`) or part of the raw payload itself.
|
|
89
|
+
const structuredKeys = [
|
|
90
|
+
"fill",
|
|
91
|
+
"line",
|
|
92
|
+
"effectList",
|
|
93
|
+
"scene3d",
|
|
94
|
+
"sp3d",
|
|
95
|
+
"transform",
|
|
96
|
+
"presetGeometry",
|
|
97
|
+
"customGeometry"
|
|
98
|
+
];
|
|
99
|
+
for (const key of structuredKeys) {
|
|
100
|
+
if (obj[key] !== undefined) {
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
return true;
|
|
105
|
+
}
|
|
106
|
+
// ============================================================================
|
|
107
|
+
// Color parsing from raw XML
|
|
108
|
+
// ============================================================================
|
|
109
|
+
// Pre-compiled regexes for parseColorFromXml (always called with "a" prefix)
|
|
110
|
+
const SRGB_CLR_RE = /<a:srgbClr\s+val="([0-9A-Fa-f]{6})"/i;
|
|
111
|
+
const SCHEME_CLR_RE = /<a:schemeClr\s+val="([^"]+)"/i;
|
|
112
|
+
// Pre-compiled regexes for parseShadowElement
|
|
113
|
+
const OUTER_SHDW_RE = /<a:outerShdw\s+([^>]*)>([\s\S]*?)<\/a:outerShdw>/;
|
|
114
|
+
const INNER_SHDW_RE = /<a:innerShdw\s+([^>]*)>([\s\S]*?)<\/a:innerShdw>/;
|
|
115
|
+
const SHADOW_RES = {
|
|
116
|
+
"a:outerShdw": OUTER_SHDW_RE,
|
|
117
|
+
"a:innerShdw": INNER_SHDW_RE
|
|
118
|
+
};
|
|
119
|
+
/**
|
|
120
|
+
* Extract a region from `xml` between the opening tag match and the corresponding
|
|
121
|
+
* closing tag (or a reasonable fallback for self-closing elements).
|
|
122
|
+
*/
|
|
123
|
+
function extractColorRegion(xml, openMatch, closeTag) {
|
|
124
|
+
const endIdx = xml.indexOf(closeTag, openMatch.index);
|
|
125
|
+
if (endIdx >= 0) {
|
|
126
|
+
// Stop at the close tag's `>` so the region never spills into the
|
|
127
|
+
// next sibling (which could itself have a colour element whose
|
|
128
|
+
// modifiers would then be misattributed).
|
|
129
|
+
const closeGt = xml.indexOf(">", endIdx);
|
|
130
|
+
return xml.slice(openMatch.index, closeGt >= 0 ? closeGt + 1 : endIdx + closeTag.length);
|
|
131
|
+
}
|
|
132
|
+
// No close tag — the element is self-closing (`<a:srgbClr val="FF0000"/>`)
|
|
133
|
+
// or truncated. DrawingML never nests modifiers inside a self-closing
|
|
134
|
+
// colour token, so return just the opening fragment up to the first
|
|
135
|
+
// `>` to avoid picking up modifiers that belong to a sibling colour.
|
|
136
|
+
const openEnd = xml.indexOf(">", openMatch.index);
|
|
137
|
+
return xml.slice(openMatch.index, openEnd >= 0 ? openEnd + 1 : openMatch.index + openMatch[0].length);
|
|
138
|
+
}
|
|
139
|
+
/**
|
|
140
|
+
* Parse all DrawingML color modifiers from a region of XML.
|
|
141
|
+
* Handles: alpha, tint, shade, satMod, lumMod, lumOff.
|
|
142
|
+
*
|
|
143
|
+
* Regexes accept `-?\d+(?:\.\d+)?` — negative and fractional values
|
|
144
|
+
* are legal in third-party exports (e.g. `<a:tint val="-5000"/>`,
|
|
145
|
+
* `<a:satMod val="123456.7"/>`); `\d+` alone dropped them silently.
|
|
146
|
+
* `parseFloat` with rounding preserves the intended semantics.
|
|
147
|
+
*/
|
|
148
|
+
function parseColorModifiers(region, color) {
|
|
149
|
+
const parseModifierValue = (m) => m ? Math.round(parseFloat(m[1])) : undefined;
|
|
150
|
+
const alphaMatch = /<a:alpha\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
151
|
+
const alphaVal = parseModifierValue(alphaMatch);
|
|
152
|
+
if (alphaVal !== undefined) {
|
|
153
|
+
color.alpha = alphaVal;
|
|
154
|
+
}
|
|
155
|
+
const tintMatch = /<a:tint\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
156
|
+
if (tintMatch) {
|
|
157
|
+
color.tint = parseFloat(tintMatch[1]) / 100000;
|
|
158
|
+
}
|
|
159
|
+
const shadeMatch = /<a:shade\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
160
|
+
const shadeVal = parseModifierValue(shadeMatch);
|
|
161
|
+
if (shadeVal !== undefined) {
|
|
162
|
+
color.shade = shadeVal;
|
|
163
|
+
}
|
|
164
|
+
const satModMatch = /<a:satMod\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
165
|
+
const satModVal = parseModifierValue(satModMatch);
|
|
166
|
+
if (satModVal !== undefined) {
|
|
167
|
+
color.satMod = satModVal;
|
|
168
|
+
}
|
|
169
|
+
const lumModMatch = /<a:lumMod\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
170
|
+
const lumModVal = parseModifierValue(lumModMatch);
|
|
171
|
+
if (lumModVal !== undefined) {
|
|
172
|
+
color.lumMod = lumModVal;
|
|
173
|
+
}
|
|
174
|
+
const lumOffMatch = /<a:lumOff\s+val="(-?\d+(?:\.\d+)?)"/.exec(region);
|
|
175
|
+
const lumOffVal = parseModifierValue(lumOffMatch);
|
|
176
|
+
if (lumOffVal !== undefined) {
|
|
177
|
+
color.lumOff = lumOffVal;
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
// Pre-compiled regexes for sysClr / prstClr
|
|
181
|
+
const SYS_CLR_RE = /<a:sysClr\s+val="([^"]+)"/i;
|
|
182
|
+
const PRST_CLR_RE = /<a:prstClr\s+val="([^"]+)"/i;
|
|
183
|
+
function parseColorFromXml(xml) {
|
|
184
|
+
// Try srgbClr
|
|
185
|
+
const srgbMatch = SRGB_CLR_RE.exec(xml);
|
|
186
|
+
if (srgbMatch) {
|
|
187
|
+
const color = { srgb: srgbMatch[1].toUpperCase() };
|
|
188
|
+
const region = extractColorRegion(xml, srgbMatch, `</a:srgbClr`);
|
|
189
|
+
parseColorModifiers(region, color);
|
|
190
|
+
return color;
|
|
191
|
+
}
|
|
192
|
+
// Try schemeClr (theme)
|
|
193
|
+
const schemeMatch = SCHEME_CLR_RE.exec(xml);
|
|
194
|
+
if (schemeMatch) {
|
|
195
|
+
// Theme index → canonical scheme name. `tx1/bg1/tx2/bg2` are
|
|
196
|
+
// "slide"-style aliases of `dk1/lt1/dk2/lt2` defined in ECMA-376
|
|
197
|
+
// §20.1.2.3.29, so we fold them into the same indices rather than
|
|
198
|
+
// dropping them as "unknown theme" (which used to silently return
|
|
199
|
+
// index 0 / `dk1` and corrupt the colour on round-trip).
|
|
200
|
+
const themeMap = {
|
|
201
|
+
dk1: 0,
|
|
202
|
+
tx1: 0,
|
|
203
|
+
lt1: 1,
|
|
204
|
+
bg1: 1,
|
|
205
|
+
dk2: 2,
|
|
206
|
+
tx2: 2,
|
|
207
|
+
lt2: 3,
|
|
208
|
+
bg2: 3,
|
|
209
|
+
accent1: 4,
|
|
210
|
+
accent2: 5,
|
|
211
|
+
accent3: 6,
|
|
212
|
+
accent4: 7,
|
|
213
|
+
accent5: 8,
|
|
214
|
+
accent6: 9,
|
|
215
|
+
hlink: 10,
|
|
216
|
+
folHlink: 11
|
|
217
|
+
};
|
|
218
|
+
const raw = schemeMatch[1];
|
|
219
|
+
const idx = themeMap[raw];
|
|
220
|
+
// When we can't map the name to a theme index (e.g. `phClr` — the
|
|
221
|
+
// DrawingML "placeholder colour" token — or a future addition),
|
|
222
|
+
// preserve it as a scheme-name token under `schemeName` so the
|
|
223
|
+
// writer re-emits `<a:schemeClr val="…">` on round-trip. The old
|
|
224
|
+
// code stored the raw token under `sysClr`, which caused the
|
|
225
|
+
// writer to emit `<a:sysClr>` instead — silently changing the
|
|
226
|
+
// DrawingML element type and breaking theme placeholder semantics.
|
|
227
|
+
const color = idx !== undefined ? { theme: idx } : { schemeName: raw };
|
|
228
|
+
const region = extractColorRegion(xml, schemeMatch, `</a:schemeClr`);
|
|
229
|
+
parseColorModifiers(region, color);
|
|
230
|
+
return color;
|
|
231
|
+
}
|
|
232
|
+
// Try sysClr (system color)
|
|
233
|
+
const sysMatch = SYS_CLR_RE.exec(xml);
|
|
234
|
+
if (sysMatch) {
|
|
235
|
+
const color = { sysClr: sysMatch[1] };
|
|
236
|
+
const region = extractColorRegion(xml, sysMatch, `</a:sysClr`);
|
|
237
|
+
parseColorModifiers(region, color);
|
|
238
|
+
return color;
|
|
239
|
+
}
|
|
240
|
+
// Try prstClr (preset color)
|
|
241
|
+
const prstMatch = PRST_CLR_RE.exec(xml);
|
|
242
|
+
if (prstMatch) {
|
|
243
|
+
const color = { prstClr: prstMatch[1] };
|
|
244
|
+
const region = extractColorRegion(xml, prstMatch, `</a:prstClr`);
|
|
245
|
+
parseColorModifiers(region, color);
|
|
246
|
+
return color;
|
|
247
|
+
}
|
|
248
|
+
return undefined;
|
|
249
|
+
}
|
|
250
|
+
// ============================================================================
|
|
251
|
+
// Gradient / pattern fill parsing from raw XML
|
|
252
|
+
// ============================================================================
|
|
253
|
+
function parseGradientFill(xml) {
|
|
254
|
+
const gradStart = xml.indexOf("<a:gradFill");
|
|
255
|
+
const gradEnd = xml.indexOf("</a:gradFill");
|
|
256
|
+
if (gradStart < 0 || gradEnd < 0) {
|
|
257
|
+
return undefined;
|
|
258
|
+
}
|
|
259
|
+
const region = xml.slice(gradStart, gradEnd + 20);
|
|
260
|
+
// Parse gradient stops. OOXML `<a:gs pos="N">` encodes `N` as
|
|
261
|
+
// hundredths of a percent (0–100000), NOT thousandths. The
|
|
262
|
+
// previous implementation divided by 1000 — producing `stop.position`
|
|
263
|
+
// values that were 100× too large (e.g. a 50% stop decoded as 50
|
|
264
|
+
// instead of 0.5). Paired with the equally-wrong writer multiplier
|
|
265
|
+
// of ×1000, round-trip byte-compared equal but any freshly-built
|
|
266
|
+
// gradient rendered in Excel at a wildly wrong position. See the
|
|
267
|
+
// companion fix in `chart-ex-renderer.ts:renderSpPr` gradient path.
|
|
268
|
+
const stops = [];
|
|
269
|
+
// Find each <a:gs pos="..."> ... </a:gs>
|
|
270
|
+
const gsListStart = region.indexOf("<a:gsLst");
|
|
271
|
+
const gsListEnd = region.indexOf("</a:gsLst");
|
|
272
|
+
if (gsListStart >= 0 && gsListEnd >= 0) {
|
|
273
|
+
const gsListRegion = region.slice(gsListStart, gsListEnd + 12);
|
|
274
|
+
// OOXML `ST_PositiveFixedPercentage` is `xsd:int` in [0, 100000]
|
|
275
|
+
// — integer by schema — but third-party authors sometimes emit
|
|
276
|
+
// fractional values (e.g. `pos="33333.33"`) that readers tolerate.
|
|
277
|
+
// The previous `\d+`-only regex silently dropped stops with
|
|
278
|
+
// fractional positions, truncating the whole gradient on parse.
|
|
279
|
+
// Match fractional too so we at least preserve the author's intent.
|
|
280
|
+
const gsPosRegex = /<a:gs\s+pos="(-?\d+(?:\.\d+)?)"/g;
|
|
281
|
+
let match;
|
|
282
|
+
const positions = [];
|
|
283
|
+
while ((match = gsPosRegex.exec(gsListRegion)) !== null) {
|
|
284
|
+
positions.push({ pos: parseFloat(match[1]), startIdx: match.index });
|
|
285
|
+
}
|
|
286
|
+
for (let i = 0; i < positions.length; i++) {
|
|
287
|
+
const start = positions[i].startIdx;
|
|
288
|
+
const end = i + 1 < positions.length ? positions[i + 1].startIdx : gsListRegion.length;
|
|
289
|
+
const gsRegion = gsListRegion.slice(start, end);
|
|
290
|
+
const color = parseColorFromXml(gsRegion);
|
|
291
|
+
if (color) {
|
|
292
|
+
stops.push({ position: positions[i].pos / 100000, color });
|
|
293
|
+
}
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
// A legal gradient requires at least two stops — `CT_GradientStopList`
|
|
297
|
+
// declares `minOccurs="2"`. Reject single-stop gradients at parse so
|
|
298
|
+
// the writer (which gates `g.stops.length >= 2`) doesn't silently
|
|
299
|
+
// drop the entire `<a:gradFill>` block on round-trip, producing a
|
|
300
|
+
// shape with no fill attribute at all. A user authoring a malformed
|
|
301
|
+
// single-stop gradient is better served by a missing fill that
|
|
302
|
+
// surfaces in testing than by silent truncation at save.
|
|
303
|
+
if (stops.length < 2) {
|
|
304
|
+
return undefined;
|
|
305
|
+
}
|
|
306
|
+
// Parse angle from <a:lin ang="..."> — OOXML stores 60000ths of a
|
|
307
|
+
// degree. The attribute is an xsd:int but we accept fractional
|
|
308
|
+
// values too so libraries that emit millidegrees don't lose data.
|
|
309
|
+
// `scaled` is a sibling boolean attribute on the same element; we
|
|
310
|
+
// capture it only when authored so a default-scaled gradient doesn't
|
|
311
|
+
// round-trip as an explicit `scaled="1"` (matching Excel's emission,
|
|
312
|
+
// which omits the attribute when the implicit default applies).
|
|
313
|
+
let angle;
|
|
314
|
+
let scaled;
|
|
315
|
+
let type;
|
|
316
|
+
const linMatch = /<a:lin\b([^/>]*)\/?>/.exec(region);
|
|
317
|
+
if (linMatch) {
|
|
318
|
+
const linAttrs = linMatch[1];
|
|
319
|
+
const angMatch = /\bang="(-?\d+(?:\.\d+)?)"/.exec(linAttrs);
|
|
320
|
+
if (angMatch) {
|
|
321
|
+
angle = parseFloat(angMatch[1]) / 60000;
|
|
322
|
+
}
|
|
323
|
+
const scaledMatch = /\bscaled="(1|true|0|false)"/.exec(linAttrs);
|
|
324
|
+
if (scaledMatch) {
|
|
325
|
+
scaled = scaledMatch[1] === "1" || scaledMatch[1] === "true";
|
|
326
|
+
}
|
|
327
|
+
type = "linear";
|
|
328
|
+
}
|
|
329
|
+
// Check for path gradient — `<a:path path="circle|rect|shape">`
|
|
330
|
+
// optionally wrapping `<a:fillToRect l t r b/>` focal rectangle
|
|
331
|
+
// (each component in hundredths of a percent).
|
|
332
|
+
const pathMatch = /<a:path\s+path="([^"]+)"/.exec(region);
|
|
333
|
+
let fillToRect;
|
|
334
|
+
if (pathMatch) {
|
|
335
|
+
type = pathMatch[1];
|
|
336
|
+
const fillRectMatch = /<a:fillToRect\b([^/>]*)/.exec(region);
|
|
337
|
+
if (fillRectMatch) {
|
|
338
|
+
const attrs = fillRectMatch[1];
|
|
339
|
+
const pick = (name) => {
|
|
340
|
+
const m = new RegExp(`\\b${name}="(-?\\d+(?:\\.\\d+)?)"`).exec(attrs);
|
|
341
|
+
return m ? parseFloat(m[1]) / 100000 : undefined;
|
|
342
|
+
};
|
|
343
|
+
fillToRect = {
|
|
344
|
+
left: pick("l"),
|
|
345
|
+
top: pick("t"),
|
|
346
|
+
right: pick("r"),
|
|
347
|
+
bottom: pick("b")
|
|
348
|
+
};
|
|
349
|
+
// Drop the object entirely when every component is missing so we
|
|
350
|
+
// don't carry an all-undefined placeholder through the model.
|
|
351
|
+
if (fillToRect.left === undefined &&
|
|
352
|
+
fillToRect.top === undefined &&
|
|
353
|
+
fillToRect.right === undefined &&
|
|
354
|
+
fillToRect.bottom === undefined) {
|
|
355
|
+
fillToRect = undefined;
|
|
356
|
+
}
|
|
357
|
+
}
|
|
358
|
+
}
|
|
359
|
+
return {
|
|
360
|
+
gradient: {
|
|
361
|
+
stops,
|
|
362
|
+
angle,
|
|
363
|
+
type,
|
|
364
|
+
...(scaled !== undefined ? { scaled } : {}),
|
|
365
|
+
...(fillToRect ? { fillToRect } : {})
|
|
366
|
+
}
|
|
367
|
+
};
|
|
368
|
+
}
|
|
369
|
+
function parsePatternFill(xml) {
|
|
370
|
+
const pattMatch = /<a:pattFill\s+prst="([^"]+)"/.exec(xml);
|
|
371
|
+
if (!pattMatch) {
|
|
372
|
+
return undefined;
|
|
373
|
+
}
|
|
374
|
+
const preset = pattMatch[1];
|
|
375
|
+
const pattStart = pattMatch.index;
|
|
376
|
+
const pattEnd = xml.indexOf("</a:pattFill", pattStart);
|
|
377
|
+
const region = xml.slice(pattStart, pattEnd > 0 ? pattEnd + 15 : undefined);
|
|
378
|
+
// Slice each colour region by pair-of-tags OR by the range from the
|
|
379
|
+
// current open up to the next known child — matches what a real XML
|
|
380
|
+
// parser would do, and doesn't over-read into the sibling colour
|
|
381
|
+
// when the element happens to be self-closing.
|
|
382
|
+
const sliceChildRegion = (open, close, stopBefore) => {
|
|
383
|
+
const start = region.indexOf(open);
|
|
384
|
+
if (start < 0) {
|
|
385
|
+
return "";
|
|
386
|
+
}
|
|
387
|
+
const end = region.indexOf(close, start);
|
|
388
|
+
if (end >= 0) {
|
|
389
|
+
return region.slice(start, end + close.length + 1);
|
|
390
|
+
}
|
|
391
|
+
// No close tag — element is self-closing or malformed. Stop at
|
|
392
|
+
// the next recognised sibling child so the slice never walks into
|
|
393
|
+
// the neighbouring colour block.
|
|
394
|
+
const nextSibling = region.indexOf(stopBefore, start + open.length);
|
|
395
|
+
return region.slice(start, nextSibling > 0 ? nextSibling : undefined);
|
|
396
|
+
};
|
|
397
|
+
const fgRegion = sliceChildRegion("<a:fgClr", "</a:fgClr", "<a:bgClr");
|
|
398
|
+
const bgRegion = sliceChildRegion("<a:bgClr", "</a:bgClr", "<a:fgClr");
|
|
399
|
+
const foreground = fgRegion ? parseColorFromXml(fgRegion) : undefined;
|
|
400
|
+
const background = bgRegion ? parseColorFromXml(bgRegion) : undefined;
|
|
401
|
+
return { pattern: { preset, foreground, background } };
|
|
402
|
+
}
|
|
403
|
+
/**
|
|
404
|
+
* Remove the FIRST matching `<tag …>…</tag>` (or self-closing
|
|
405
|
+
* `<tag …/>`) block from the input XML, returning the remainder. Used
|
|
406
|
+
* by {@link parseSpPr} to isolate shape-level children (fill / effects)
|
|
407
|
+
* from decorative children that nest inside `<a:ln>` — the line's own
|
|
408
|
+
* `<a:solidFill>` / `<a:noFill/>` / `<a:gradFill>` should not be
|
|
409
|
+
* harvested as the shape's fill.
|
|
410
|
+
*
|
|
411
|
+
* Strips ALL occurrences of `tag` (both self-closing and paired) in
|
|
412
|
+
* one pass. A previous version returned after the earliest match,
|
|
413
|
+
* which failed on inputs like `<a:ln/>…<a:ln>…</a:ln>` — the paired
|
|
414
|
+
* block survived and its inner `<a:solidFill>` was then mistakenly
|
|
415
|
+
* parsed as the shape's fill.
|
|
416
|
+
*
|
|
417
|
+
* Not a general-purpose XML tool — does not handle same-named nested
|
|
418
|
+
* occurrences. Sufficient for DrawingML spPr, where `<a:ln>` never
|
|
419
|
+
* nests another `<a:ln>`.
|
|
420
|
+
*/
|
|
421
|
+
function stripOuterElement(xml, tag) {
|
|
422
|
+
const selfCloseRe = new RegExp(`<${tag}\\b[^>]*/>`);
|
|
423
|
+
const openRe = new RegExp(`<${tag}\\b[^>]*(?<!/)>`);
|
|
424
|
+
const closeRe = new RegExp(`</${tag}>`);
|
|
425
|
+
let current = xml;
|
|
426
|
+
// Strip up to 8 occurrences. DrawingML spPr never has more than one
|
|
427
|
+
// `<a:ln>`, so the loop normally exits after the first iteration;
|
|
428
|
+
// the ceiling guards against pathological input causing infinite
|
|
429
|
+
// loops without changing the happy path.
|
|
430
|
+
for (let i = 0; i < 8; i++) {
|
|
431
|
+
const selfCloseMatch = selfCloseRe.exec(current);
|
|
432
|
+
const openMatch = openRe.exec(current);
|
|
433
|
+
const selfCloseIndex = selfCloseMatch ? selfCloseMatch.index : Infinity;
|
|
434
|
+
const openIndex = openMatch ? openMatch.index : Infinity;
|
|
435
|
+
if (selfCloseIndex === Infinity && openIndex === Infinity) {
|
|
436
|
+
break;
|
|
437
|
+
}
|
|
438
|
+
if (selfCloseIndex < openIndex && selfCloseMatch) {
|
|
439
|
+
current =
|
|
440
|
+
current.slice(0, selfCloseMatch.index) +
|
|
441
|
+
current.slice(selfCloseMatch.index + selfCloseMatch[0].length);
|
|
442
|
+
continue;
|
|
443
|
+
}
|
|
444
|
+
if (openMatch) {
|
|
445
|
+
// Find the close tag that pairs with this open — start searching
|
|
446
|
+
// after the open's end to avoid capturing `</tag>` that belongs
|
|
447
|
+
// to a prior unrelated (e.g. self-closing lookalike) open.
|
|
448
|
+
const openEnd = openMatch.index + openMatch[0].length;
|
|
449
|
+
const closeMatch = closeRe.exec(current.slice(openEnd));
|
|
450
|
+
if (!closeMatch) {
|
|
451
|
+
// Malformed — stop stripping to avoid further mutation of
|
|
452
|
+
// input we don't understand.
|
|
453
|
+
break;
|
|
454
|
+
}
|
|
455
|
+
const closeStart = openEnd + closeMatch.index;
|
|
456
|
+
const closeEnd = closeStart + closeMatch[0].length;
|
|
457
|
+
current = current.slice(0, openMatch.index) + current.slice(closeEnd);
|
|
458
|
+
continue;
|
|
459
|
+
}
|
|
460
|
+
break;
|
|
461
|
+
}
|
|
462
|
+
return current;
|
|
463
|
+
}
|
|
464
|
+
// ============================================================================
|
|
465
|
+
// spPr: Read structured properties from raw XML
|
|
466
|
+
// ============================================================================
|
|
467
|
+
/**
|
|
468
|
+
* Extract structured fill and line properties from a raw spPr XML string.
|
|
469
|
+
* Returns the structured ShapeProperties if extraction succeeds.
|
|
470
|
+
*/
|
|
471
|
+
export function parseSpPr(spPr) {
|
|
472
|
+
const rawXml = getRawXml(spPr);
|
|
473
|
+
if (!rawXml) {
|
|
474
|
+
return spPr; // already structured
|
|
475
|
+
}
|
|
476
|
+
const result = {};
|
|
477
|
+
// The fill parser searches for `<a:solidFill>` at the top level — but
|
|
478
|
+
// `<a:ln>…<a:solidFill>…</a:solidFill></a:ln>` is a common DrawingML
|
|
479
|
+
// pattern where the line itself carries a solid colour. Previously
|
|
480
|
+
// `rawXml.includes("<a:solidFill")` matched the line's inner fill,
|
|
481
|
+
// picked up its colour as `result.fill.solid`, and the writer then
|
|
482
|
+
// emitted a phantom `<a:solidFill>` as a shape fill — silently
|
|
483
|
+
// painting the entire chart area with the border colour on re-save.
|
|
484
|
+
// Excise any `<a:ln>…</a:ln>` block before searching for the shape
|
|
485
|
+
// fill. The line block is parsed separately below, so nothing is
|
|
486
|
+
// lost. Gradient / pattern / noFill have the same issue with respect
|
|
487
|
+
// to `<a:ln>/<a:noFill/>`.
|
|
488
|
+
const fillSearchXml = stripOuterElement(rawXml, "a:ln");
|
|
489
|
+
// Parse fill
|
|
490
|
+
//
|
|
491
|
+
// The open/close tag search must be done defensively: `indexOf` on a
|
|
492
|
+
// missing close tag returns `-1`, so the naïve
|
|
493
|
+
// `fillSearchXml.slice(openIdx, fillSearchXml.indexOf("</a:solidFill") + 20)`
|
|
494
|
+
// picks up position `19` as the upper bound — either truncating the
|
|
495
|
+
// slice to garbage or producing an empty string. Both shapes
|
|
496
|
+
// silently corrupted the fill parser when a `<a:solidFill/>` was
|
|
497
|
+
// self-closed or when the close tag was missing.
|
|
498
|
+
//
|
|
499
|
+
// Prefer the open-tag-or-self-closing form, then only try to capture
|
|
500
|
+
// a close tag when we've seen a proper open tag. If we do not find a
|
|
501
|
+
// valid solid-fill region, fall through to the other fill branches
|
|
502
|
+
// so a `<a:gradFill>` that coexists with a malformed solidFill still
|
|
503
|
+
// gets picked up.
|
|
504
|
+
let fillMatched = false;
|
|
505
|
+
const solidFillSelfClose = /<a:solidFill\s*\/>/.exec(fillSearchXml);
|
|
506
|
+
const solidFillOpenIdx = fillSearchXml.indexOf("<a:solidFill");
|
|
507
|
+
const solidFillNonSelfClose = solidFillOpenIdx >= 0 && !solidFillSelfClose;
|
|
508
|
+
if (solidFillNonSelfClose) {
|
|
509
|
+
const closeIdx = fillSearchXml.indexOf("</a:solidFill>", solidFillOpenIdx);
|
|
510
|
+
if (closeIdx >= 0) {
|
|
511
|
+
const color = parseColorFromXml(fillSearchXml.slice(solidFillOpenIdx, closeIdx + "</a:solidFill>".length));
|
|
512
|
+
if (color) {
|
|
513
|
+
result.fill = { solid: color };
|
|
514
|
+
fillMatched = true;
|
|
515
|
+
}
|
|
516
|
+
}
|
|
517
|
+
// else: malformed solidFill (no close tag) — fall through below.
|
|
518
|
+
}
|
|
519
|
+
else if (solidFillSelfClose) {
|
|
520
|
+
// `<a:solidFill/>` has no child colour; DrawingML schema does not
|
|
521
|
+
// allow this, but some legacy exports emit it. Treat as "unknown
|
|
522
|
+
// fill, do not record" and fall through.
|
|
523
|
+
}
|
|
524
|
+
if (!fillMatched) {
|
|
525
|
+
if (fillSearchXml.includes("<a:noFill")) {
|
|
526
|
+
result.fill = { noFill: true };
|
|
527
|
+
}
|
|
528
|
+
else if (fillSearchXml.includes("<a:gradFill")) {
|
|
529
|
+
result.fill = parseGradientFill(fillSearchXml);
|
|
530
|
+
}
|
|
531
|
+
else if (fillSearchXml.includes("<a:pattFill")) {
|
|
532
|
+
result.fill = parsePatternFill(fillSearchXml);
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
// Parse line
|
|
536
|
+
//
|
|
537
|
+
// Anchor the regex on a real `<a:ln ...>` / `<a:ln>` / `<a:ln/>` — the
|
|
538
|
+
// lookahead `(?=[\s/>])` ensures we don't match a neighbouring element
|
|
539
|
+
// like `<a:lnRef>` or `<a:lnB>` (both appear in DrawingML theme /
|
|
540
|
+
// styleLst blocks) and silently walk the wrong region when extracting
|
|
541
|
+
// the stroke colour. We then parse `w` / other attributes separately
|
|
542
|
+
// from the captured opening-tag body — the old `(?:\s+w="(\d+)")?`
|
|
543
|
+
// inline group only captured `w` when it was the FIRST attribute
|
|
544
|
+
// after `<a:ln`, so `<a:ln cap="flat" w="12700">` silently dropped
|
|
545
|
+
// the width.
|
|
546
|
+
const lnMatch = /<a:ln(?=[\s/>])([^>]*)/.exec(rawXml);
|
|
547
|
+
if (lnMatch) {
|
|
548
|
+
// Distinguish `<a:ln/>` (self-closing, no body) from `<a:ln …>…</a:ln>`.
|
|
549
|
+
// The greedy `[^>]*` in the regex captures everything up to (but not
|
|
550
|
+
// including) the closing `>`. For `<a:ln w="12700"/>` the captured
|
|
551
|
+
// group is ` w="12700"/` — the `/` is THE self-close marker. Earlier
|
|
552
|
+
// code walked `rawXml[tokenEnd]` looking for `/`, but `tokenEnd` points
|
|
553
|
+
// at `>`, not `/`, so `selfClosing` was always false and the parser
|
|
554
|
+
// fell through to `indexOf("</a:ln", …)` (which returns -1 for a
|
|
555
|
+
// self-closing tag). That made `lnRegion` span to the end of the
|
|
556
|
+
// rawXml, causing the shape's own `<a:solidFill>` to be picked up as
|
|
557
|
+
// the line colour. Detect self-close by inspecting what the regex
|
|
558
|
+
// already captured — ignore trailing whitespace before the `/`.
|
|
559
|
+
const selfClosing = /\/\s*$/.test(lnMatch[1]);
|
|
560
|
+
const tokenEnd = lnMatch.index + lnMatch[0].length;
|
|
561
|
+
// The match stopped at the byte BEFORE the closing `>`; advance one
|
|
562
|
+
// character so the close-tag-aware slice below includes the `>`.
|
|
563
|
+
const openTagEnd = tokenEnd + 1;
|
|
564
|
+
// Use the full `</a:ln>` terminator (with the trailing `>`) instead
|
|
565
|
+
// of the old `</a:ln` prefix — the prefix also matches `</a:lnRef>`
|
|
566
|
+
// and `</a:lnB>` inside DrawingML styleLst blocks, which would
|
|
567
|
+
// cause the region to stop short of the real line close.
|
|
568
|
+
const lnEnd = selfClosing ? -1 : rawXml.indexOf("</a:ln>", lnMatch.index);
|
|
569
|
+
const lnRegion = selfClosing
|
|
570
|
+
? rawXml.slice(lnMatch.index, openTagEnd)
|
|
571
|
+
: lnEnd >= 0
|
|
572
|
+
? rawXml.slice(lnMatch.index, lnEnd + "</a:ln>".length)
|
|
573
|
+
: // Malformed (open tag with no matching close) — clip to the
|
|
574
|
+
// open tag only so we don't walk into unrelated XML. Previous
|
|
575
|
+
// behaviour sliced to `undefined` (rest of the document), which
|
|
576
|
+
// was the root of this bug.
|
|
577
|
+
rawXml.slice(lnMatch.index, openTagEnd);
|
|
578
|
+
const line = {};
|
|
579
|
+
const widthMatch = /\bw="(\d+)"/.exec(lnMatch[1]);
|
|
580
|
+
if (widthMatch) {
|
|
581
|
+
line.width = parseInt(widthMatch[1], 10);
|
|
582
|
+
}
|
|
583
|
+
if (lnRegion.includes("<a:noFill")) {
|
|
584
|
+
line.noFill = true;
|
|
585
|
+
}
|
|
586
|
+
else if (lnRegion.includes("<a:solidFill")) {
|
|
587
|
+
// Scope the colour search to the `<a:solidFill>` body so a line
|
|
588
|
+
// that also carries a gradient / pattern fill (rare but legal —
|
|
589
|
+
// `<a:ln><a:gradFill>…</a:gradFill></a:ln>`) doesn't pollute
|
|
590
|
+
// `parseColorFromXml` with the gradient's first stop colour. The
|
|
591
|
+
// previous code passed the whole `lnRegion` — if the line had
|
|
592
|
+
// both fills `parseColorFromXml` picked up whichever colour it
|
|
593
|
+
// found first in document order, silently mis-rendering the
|
|
594
|
+
// line. For pure-solid lines the result is identical.
|
|
595
|
+
const solidFillMatch = /<a:solidFill>([\s\S]*?)<\/a:solidFill>/.exec(lnRegion);
|
|
596
|
+
line.color = parseColorFromXml(solidFillMatch ? solidFillMatch[1] : lnRegion);
|
|
597
|
+
}
|
|
598
|
+
const dashMatch = /<a:prstDash\s+val="([^"]+)"/.exec(lnRegion);
|
|
599
|
+
if (dashMatch) {
|
|
600
|
+
line.dash = dashMatch[1];
|
|
601
|
+
}
|
|
602
|
+
result.line = line;
|
|
603
|
+
}
|
|
604
|
+
// Parse effect list
|
|
605
|
+
if (rawXml.includes("<a:effectLst") || rawXml.includes("<a:effectDag")) {
|
|
606
|
+
const effects = parseEffectList(rawXml);
|
|
607
|
+
if (effects) {
|
|
608
|
+
result.effectList = effects;
|
|
609
|
+
}
|
|
610
|
+
}
|
|
611
|
+
// Parse 3D scene and shape properties
|
|
612
|
+
if (rawXml.includes("<a:scene3d")) {
|
|
613
|
+
const scene = parseScene3D(rawXml);
|
|
614
|
+
if (scene) {
|
|
615
|
+
result.scene3d = scene;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
if (rawXml.includes("<a:sp3d")) {
|
|
619
|
+
const sp3d = parseSp3D(rawXml);
|
|
620
|
+
if (sp3d) {
|
|
621
|
+
result.sp3d = sp3d;
|
|
622
|
+
}
|
|
623
|
+
}
|
|
624
|
+
// Transform (`a:xfrm`) — position, size, rotation, flips. The regex
|
|
625
|
+
// approach is a deliberate trade-off: a full XML walk would be more
|
|
626
|
+
// robust but also ~4x the code for a field Excel writes in a very
|
|
627
|
+
// constrained shape. If Excel ever nests `a:xfrm` with variants the
|
|
628
|
+
// round-trip raw-XML path still carries them.
|
|
629
|
+
if (rawXml.includes("<a:xfrm")) {
|
|
630
|
+
const transform = parseXfrm(rawXml);
|
|
631
|
+
if (transform) {
|
|
632
|
+
result.transform = transform;
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
if (rawXml.includes("<a:prstGeom")) {
|
|
636
|
+
const prst = parsePrstGeom(rawXml);
|
|
637
|
+
if (prst) {
|
|
638
|
+
result.presetGeometry = prst;
|
|
639
|
+
}
|
|
640
|
+
}
|
|
641
|
+
if (rawXml.includes("<a:custGeom")) {
|
|
642
|
+
const cust = parseCustGeom(rawXml);
|
|
643
|
+
if (cust) {
|
|
644
|
+
result.customGeometry = cust;
|
|
645
|
+
}
|
|
646
|
+
}
|
|
647
|
+
return result;
|
|
648
|
+
}
|
|
649
|
+
// ============================================================================
|
|
650
|
+
// Effect list parsing
|
|
651
|
+
// ============================================================================
|
|
652
|
+
// ============================================================================
|
|
653
|
+
/**
|
|
654
|
+
* Parse a single `<a:xfrm>` element out of the shape-properties raw
|
|
655
|
+
* XML blob. Returns `undefined` when the element is absent so callers
|
|
656
|
+
* can simply drop the result into a structural field.
|
|
657
|
+
*
|
|
658
|
+
* Shape: `<a:xfrm rot="…" flipH="1" flipV="1"><a:off x="…" y="…"/><a:ext cx="…" cy="…"/></a:xfrm>`.
|
|
659
|
+
* All five attributes and both children are optional; Excel omits
|
|
660
|
+
* `a:off`/`a:ext` when a shape inherits its parent's automatic
|
|
661
|
+
* layout.
|
|
662
|
+
*/
|
|
663
|
+
function parseXfrm(xml) {
|
|
664
|
+
const match = /<a:xfrm\b([^>]*)(?:\/>|>([\s\S]*?)<\/a:xfrm>)/.exec(xml);
|
|
665
|
+
if (!match) {
|
|
666
|
+
return undefined;
|
|
667
|
+
}
|
|
668
|
+
const attrs = match[1] ?? "";
|
|
669
|
+
const inner = match[2] ?? "";
|
|
670
|
+
const result = {};
|
|
671
|
+
const rotAttr = /\brot="(-?\d+)"/.exec(attrs);
|
|
672
|
+
if (rotAttr) {
|
|
673
|
+
result.rotation = parseInt(rotAttr[1], 10);
|
|
674
|
+
}
|
|
675
|
+
if (/\bflipH="1"/.test(attrs)) {
|
|
676
|
+
result.flipHorizontal = true;
|
|
677
|
+
}
|
|
678
|
+
if (/\bflipV="1"/.test(attrs)) {
|
|
679
|
+
result.flipVertical = true;
|
|
680
|
+
}
|
|
681
|
+
const off = /<a:off\b([^/>]*)\/>/.exec(inner);
|
|
682
|
+
if (off) {
|
|
683
|
+
const x = /\bx="(-?\d+)"/.exec(off[1]);
|
|
684
|
+
const y = /\by="(-?\d+)"/.exec(off[1]);
|
|
685
|
+
if (x) {
|
|
686
|
+
result.offsetX = parseInt(x[1], 10);
|
|
687
|
+
}
|
|
688
|
+
if (y) {
|
|
689
|
+
result.offsetY = parseInt(y[1], 10);
|
|
690
|
+
}
|
|
691
|
+
}
|
|
692
|
+
const ext = /<a:ext\b([^/>]*)\/>/.exec(inner);
|
|
693
|
+
if (ext) {
|
|
694
|
+
const cx = /\bcx="(\d+)"/.exec(ext[1]);
|
|
695
|
+
const cy = /\bcy="(\d+)"/.exec(ext[1]);
|
|
696
|
+
if (cx) {
|
|
697
|
+
result.width = parseInt(cx[1], 10);
|
|
698
|
+
}
|
|
699
|
+
if (cy) {
|
|
700
|
+
result.height = parseInt(cy[1], 10);
|
|
701
|
+
}
|
|
702
|
+
}
|
|
703
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
704
|
+
}
|
|
705
|
+
/**
|
|
706
|
+
* Parse `<a:prstGeom prst="…"><a:avLst>…</a:avLst></a:prstGeom>`.
|
|
707
|
+
* The `preset` name is mandatory; `adjustments` come from the
|
|
708
|
+
* optional `<a:avLst>` container whose children are `<a:gd name fmla>`
|
|
709
|
+
* triples. We read the raw `fmla` strings because they're a small
|
|
710
|
+
* OOXML sub-language (`"val 10000"` etc.) that callers rarely edit
|
|
711
|
+
* and would need a dedicated parser to structure further.
|
|
712
|
+
*/
|
|
713
|
+
function parsePrstGeom(xml) {
|
|
714
|
+
const match = /<a:prstGeom\b([^>]*)(?:\/>|>([\s\S]*?)<\/a:prstGeom>)/.exec(xml);
|
|
715
|
+
if (!match) {
|
|
716
|
+
return undefined;
|
|
717
|
+
}
|
|
718
|
+
const attrs = match[1] ?? "";
|
|
719
|
+
const inner = match[2] ?? "";
|
|
720
|
+
const prstMatch = /\bprst="([^"]+)"/.exec(attrs);
|
|
721
|
+
if (!prstMatch) {
|
|
722
|
+
return undefined;
|
|
723
|
+
}
|
|
724
|
+
const result = { preset: prstMatch[1] };
|
|
725
|
+
const adjustments = parseAdjustmentList(inner);
|
|
726
|
+
if (adjustments.length > 0) {
|
|
727
|
+
result.adjustments = adjustments;
|
|
728
|
+
}
|
|
729
|
+
return result;
|
|
730
|
+
}
|
|
731
|
+
/**
|
|
732
|
+
* Parse `<a:custGeom>` into a {@link CustomGeometry}. The path-data
|
|
733
|
+
* parser is the focal effort: `<a:pathLst><a:path w h fill stroke>…</a:path></a:pathLst>`
|
|
734
|
+
* children enumerate moveTo / lnTo / arcTo / cubicBezTo / quadBezTo /
|
|
735
|
+
* close commands in OOXML's drawing-language flavour.
|
|
736
|
+
*/
|
|
737
|
+
function parseCustGeom(xml) {
|
|
738
|
+
const match = /<a:custGeom\b[^>]*>([\s\S]*?)<\/a:custGeom>/.exec(xml);
|
|
739
|
+
if (!match) {
|
|
740
|
+
return undefined;
|
|
741
|
+
}
|
|
742
|
+
const body = match[1];
|
|
743
|
+
const result = {};
|
|
744
|
+
const adjustments = parseAdjustmentList(body);
|
|
745
|
+
if (adjustments.length > 0) {
|
|
746
|
+
result.adjustments = adjustments;
|
|
747
|
+
}
|
|
748
|
+
const paths = [];
|
|
749
|
+
const pathRe = /<a:path\b([^>]*)>([\s\S]*?)<\/a:path>/g;
|
|
750
|
+
let pm;
|
|
751
|
+
while ((pm = pathRe.exec(body)) !== null) {
|
|
752
|
+
const pAttrs = pm[1] ?? "";
|
|
753
|
+
const pBody = pm[2] ?? "";
|
|
754
|
+
const path = { commands: [] };
|
|
755
|
+
const wMatch = /\bw="(\d+)"/.exec(pAttrs);
|
|
756
|
+
const hMatch = /\bh="(\d+)"/.exec(pAttrs);
|
|
757
|
+
if (wMatch) {
|
|
758
|
+
path.w = parseInt(wMatch[1], 10);
|
|
759
|
+
}
|
|
760
|
+
if (hMatch) {
|
|
761
|
+
path.h = parseInt(hMatch[1], 10);
|
|
762
|
+
}
|
|
763
|
+
const fillMatch = /\bfill="([^"]+)"/.exec(pAttrs);
|
|
764
|
+
if (fillMatch) {
|
|
765
|
+
path.fill = fillMatch[1];
|
|
766
|
+
}
|
|
767
|
+
if (/\bstroke="1"/.test(pAttrs)) {
|
|
768
|
+
path.stroke = true;
|
|
769
|
+
}
|
|
770
|
+
else if (/\bstroke="0"/.test(pAttrs)) {
|
|
771
|
+
path.stroke = false;
|
|
772
|
+
}
|
|
773
|
+
path.commands = parseCustGeomCommands(pBody);
|
|
774
|
+
paths.push(path);
|
|
775
|
+
}
|
|
776
|
+
if (paths.length > 0) {
|
|
777
|
+
result.paths = paths;
|
|
778
|
+
}
|
|
779
|
+
return Object.keys(result).length > 0 ? result : undefined;
|
|
780
|
+
}
|
|
781
|
+
function parseAdjustmentList(xml) {
|
|
782
|
+
const avMatch = /<a:avLst\b[^>]*>([\s\S]*?)<\/a:avLst>/.exec(xml);
|
|
783
|
+
if (!avMatch) {
|
|
784
|
+
return [];
|
|
785
|
+
}
|
|
786
|
+
const out = [];
|
|
787
|
+
const gdRe = /<a:gd\b[^>]*\bname="([^"]+)"[^>]*\bfmla="([^"]+)"[^>]*\/>/g;
|
|
788
|
+
let m;
|
|
789
|
+
while ((m = gdRe.exec(avMatch[1])) !== null) {
|
|
790
|
+
out.push({ name: m[1], fmla: m[2] });
|
|
791
|
+
}
|
|
792
|
+
return out;
|
|
793
|
+
}
|
|
794
|
+
function parseCustGeomCommands(body) {
|
|
795
|
+
const commands = [];
|
|
796
|
+
// Walk commands in order — each `<a:moveTo>`/`<a:lnTo>`/… carries
|
|
797
|
+
// one or two `<a:pt x y>` children; `<a:arcTo>` carries explicit
|
|
798
|
+
// attributes instead. A greedy regex + lookahead captures the
|
|
799
|
+
// command block including the closing tag.
|
|
800
|
+
const cmdRe = /<a:(moveTo|lnTo|cubicBezTo|quadBezTo|arcTo|close)\b([^/>]*)(?:\/>|>([\s\S]*?)<\/a:\1>)/g;
|
|
801
|
+
let cm;
|
|
802
|
+
while ((cm = cmdRe.exec(body)) !== null) {
|
|
803
|
+
const kind = cm[1];
|
|
804
|
+
const cmdAttrs = cm[2] ?? "";
|
|
805
|
+
const cmdBody = cm[3] ?? "";
|
|
806
|
+
if (kind === "close") {
|
|
807
|
+
commands.push({ type: "close" });
|
|
808
|
+
continue;
|
|
809
|
+
}
|
|
810
|
+
if (kind === "arcTo") {
|
|
811
|
+
const wR = /\bwR="(-?\d+)"/.exec(cmdAttrs)?.[1];
|
|
812
|
+
const hR = /\bhR="(-?\d+)"/.exec(cmdAttrs)?.[1];
|
|
813
|
+
const stAng = /\bstAng="(-?\d+)"/.exec(cmdAttrs)?.[1];
|
|
814
|
+
const swAng = /\bswAng="(-?\d+)"/.exec(cmdAttrs)?.[1];
|
|
815
|
+
if (wR && hR && stAng && swAng) {
|
|
816
|
+
commands.push({
|
|
817
|
+
type: "arcTo",
|
|
818
|
+
arcParams: {
|
|
819
|
+
wR: parseInt(wR, 10),
|
|
820
|
+
hR: parseInt(hR, 10),
|
|
821
|
+
stAng: parseInt(stAng, 10),
|
|
822
|
+
swAng: parseInt(swAng, 10)
|
|
823
|
+
}
|
|
824
|
+
});
|
|
825
|
+
}
|
|
826
|
+
continue;
|
|
827
|
+
}
|
|
828
|
+
const points = [];
|
|
829
|
+
// Parse `<a:pt x="…" y="…"/>` without requiring a specific
|
|
830
|
+
// attribute order — some authors / writers emit
|
|
831
|
+
// `<a:pt y="100" x="200"/>` or interleave other attributes between
|
|
832
|
+
// `x` and `y`. The previous regex required `x` first, then only
|
|
833
|
+
// whitespace, then `y`, silently dropping all points on a
|
|
834
|
+
// legitimately-authored geometry that used the reversed order.
|
|
835
|
+
const ptRe = /<a:pt\b([^/>]*)\/>/g;
|
|
836
|
+
let pt;
|
|
837
|
+
while ((pt = ptRe.exec(cmdBody)) !== null) {
|
|
838
|
+
const attrs = pt[1];
|
|
839
|
+
const xAttr = /\bx="(-?\d+)"/.exec(attrs);
|
|
840
|
+
const yAttr = /\by="(-?\d+)"/.exec(attrs);
|
|
841
|
+
if (xAttr && yAttr) {
|
|
842
|
+
points.push({ x: parseInt(xAttr[1], 10), y: parseInt(yAttr[1], 10) });
|
|
843
|
+
}
|
|
844
|
+
}
|
|
845
|
+
commands.push({ type: kind, points });
|
|
846
|
+
}
|
|
847
|
+
return commands;
|
|
848
|
+
}
|
|
849
|
+
function parseEffectList(xml) {
|
|
850
|
+
const effStart = xml.indexOf("<a:effectLst");
|
|
851
|
+
const effEnd = xml.indexOf("</a:effectLst");
|
|
852
|
+
if (effStart < 0 || effEnd < 0) {
|
|
853
|
+
return undefined;
|
|
854
|
+
}
|
|
855
|
+
const region = xml.slice(effStart, effEnd + "</a:effectLst>".length);
|
|
856
|
+
const result = {};
|
|
857
|
+
// Blur
|
|
858
|
+
const blurMatch = /<a:blur(\s+[^/>]*)?\s*\/>/.exec(region);
|
|
859
|
+
if (blurMatch) {
|
|
860
|
+
const attrs = parseAttrs(blurMatch[0]);
|
|
861
|
+
result.blur = {};
|
|
862
|
+
if (attrs.rad) {
|
|
863
|
+
result.blur.radius = parseInt(attrs.rad, 10);
|
|
864
|
+
}
|
|
865
|
+
if (attrs.grow === "1") {
|
|
866
|
+
result.blur.grow = true;
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
// Outer shadow
|
|
870
|
+
const outerShadow = parseShadowElement(region, "a:outerShdw");
|
|
871
|
+
if (outerShadow) {
|
|
872
|
+
result.outerShadow = outerShadow;
|
|
873
|
+
}
|
|
874
|
+
// Inner shadow
|
|
875
|
+
const innerShadow = parseShadowElement(region, "a:innerShdw");
|
|
876
|
+
if (innerShadow) {
|
|
877
|
+
result.innerShadow = innerShadow;
|
|
878
|
+
}
|
|
879
|
+
// Preset shadow
|
|
880
|
+
const prstMatch = /<a:prstShdw\s+([^>]*)>([\s\S]*?)<\/a:prstShdw>/.exec(region);
|
|
881
|
+
if (prstMatch) {
|
|
882
|
+
const attrs = parseAttrs(prstMatch[0]);
|
|
883
|
+
const color = parseColorFromXml(prstMatch[2]);
|
|
884
|
+
if (attrs.prst && color) {
|
|
885
|
+
result.presetShadow = { preset: attrs.prst, color };
|
|
886
|
+
if (attrs.dist) {
|
|
887
|
+
result.presetShadow.distance = parseInt(attrs.dist, 10);
|
|
888
|
+
}
|
|
889
|
+
if (attrs.dir) {
|
|
890
|
+
result.presetShadow.direction = parseInt(attrs.dir, 10);
|
|
891
|
+
}
|
|
892
|
+
}
|
|
893
|
+
}
|
|
894
|
+
// Glow
|
|
895
|
+
const glowMatch = /<a:glow\s+([^>]*)>([\s\S]*?)<\/a:glow>/.exec(region);
|
|
896
|
+
if (glowMatch) {
|
|
897
|
+
const attrs = parseAttrs(glowMatch[0]);
|
|
898
|
+
const color = parseColorFromXml(glowMatch[2]);
|
|
899
|
+
if (attrs.rad && color) {
|
|
900
|
+
result.glow = { radius: parseInt(attrs.rad, 10), color };
|
|
901
|
+
}
|
|
902
|
+
}
|
|
903
|
+
// Soft edge
|
|
904
|
+
const softEdgeMatch = /<a:softEdge\s+([^/>]*)\s*\/>/.exec(region);
|
|
905
|
+
if (softEdgeMatch) {
|
|
906
|
+
const attrs = parseAttrs(softEdgeMatch[0]);
|
|
907
|
+
if (attrs.rad) {
|
|
908
|
+
result.softEdge = { radius: parseInt(attrs.rad, 10) };
|
|
909
|
+
}
|
|
910
|
+
}
|
|
911
|
+
// Reflection
|
|
912
|
+
const reflMatch = /<a:reflection\s+([^/>]*)\s*\/>/.exec(region);
|
|
913
|
+
if (reflMatch) {
|
|
914
|
+
const attrs = parseAttrs(reflMatch[0]);
|
|
915
|
+
const r = {};
|
|
916
|
+
if (attrs.blurRad) {
|
|
917
|
+
r.blurRadius = parseInt(attrs.blurRad, 10);
|
|
918
|
+
}
|
|
919
|
+
if (attrs.stA) {
|
|
920
|
+
r.startOpacity = parseInt(attrs.stA, 10);
|
|
921
|
+
}
|
|
922
|
+
if (attrs.stPos) {
|
|
923
|
+
r.startPosition = parseInt(attrs.stPos, 10);
|
|
924
|
+
}
|
|
925
|
+
if (attrs.endA) {
|
|
926
|
+
r.endOpacity = parseInt(attrs.endA, 10);
|
|
927
|
+
}
|
|
928
|
+
if (attrs.endPos) {
|
|
929
|
+
r.endPosition = parseInt(attrs.endPos, 10);
|
|
930
|
+
}
|
|
931
|
+
if (attrs.dist) {
|
|
932
|
+
r.distance = parseInt(attrs.dist, 10);
|
|
933
|
+
}
|
|
934
|
+
if (attrs.dir) {
|
|
935
|
+
r.direction = parseInt(attrs.dir, 10);
|
|
936
|
+
}
|
|
937
|
+
if (attrs.fadeDir) {
|
|
938
|
+
r.fadeDirection = parseInt(attrs.fadeDir, 10);
|
|
939
|
+
}
|
|
940
|
+
if (attrs.sx) {
|
|
941
|
+
r.scaleHorizontal = parseInt(attrs.sx, 10);
|
|
942
|
+
}
|
|
943
|
+
if (attrs.sy) {
|
|
944
|
+
r.scaleVertical = parseInt(attrs.sy, 10);
|
|
945
|
+
}
|
|
946
|
+
if (attrs.kx) {
|
|
947
|
+
r.skewHorizontal = parseInt(attrs.kx, 10);
|
|
948
|
+
}
|
|
949
|
+
if (attrs.ky) {
|
|
950
|
+
r.skewVertical = parseInt(attrs.ky, 10);
|
|
951
|
+
}
|
|
952
|
+
if (attrs.algn) {
|
|
953
|
+
r.alignment = attrs.algn;
|
|
954
|
+
}
|
|
955
|
+
if (attrs.rotWithShape === "1") {
|
|
956
|
+
r.rotateWithShape = true;
|
|
957
|
+
}
|
|
958
|
+
result.reflection = r;
|
|
959
|
+
}
|
|
960
|
+
if (Object.keys(result).length === 0) {
|
|
961
|
+
return undefined;
|
|
962
|
+
}
|
|
963
|
+
return result;
|
|
964
|
+
}
|
|
965
|
+
function parseShadowElement(xml, tag) {
|
|
966
|
+
const re = SHADOW_RES[tag] ?? new RegExp(`<${tag}\\s+([^>]*)>([\\s\\S]*?)<\\/${tag}>`);
|
|
967
|
+
const m = re.exec(xml);
|
|
968
|
+
if (!m) {
|
|
969
|
+
return undefined;
|
|
970
|
+
}
|
|
971
|
+
const attrs = parseAttrs(m[0]);
|
|
972
|
+
const color = parseColorFromXml(m[2]);
|
|
973
|
+
if (!color) {
|
|
974
|
+
return undefined;
|
|
975
|
+
}
|
|
976
|
+
const shadow = { color };
|
|
977
|
+
if (attrs.blurRad) {
|
|
978
|
+
shadow.blurRadius = parseInt(attrs.blurRad, 10);
|
|
979
|
+
}
|
|
980
|
+
if (attrs.dist) {
|
|
981
|
+
shadow.distance = parseInt(attrs.dist, 10);
|
|
982
|
+
}
|
|
983
|
+
if (attrs.dir) {
|
|
984
|
+
shadow.direction = parseInt(attrs.dir, 10);
|
|
985
|
+
}
|
|
986
|
+
if (attrs.algn) {
|
|
987
|
+
shadow.alignment = attrs.algn;
|
|
988
|
+
}
|
|
989
|
+
if (attrs.rotWithShape === "1") {
|
|
990
|
+
shadow.rotateWithShape = true;
|
|
991
|
+
}
|
|
992
|
+
if (attrs.sx) {
|
|
993
|
+
shadow.scaleHorizontal = parseInt(attrs.sx, 10);
|
|
994
|
+
}
|
|
995
|
+
if (attrs.sy) {
|
|
996
|
+
shadow.scaleVertical = parseInt(attrs.sy, 10);
|
|
997
|
+
}
|
|
998
|
+
if (attrs.kx) {
|
|
999
|
+
shadow.skewHorizontal = parseInt(attrs.kx, 10);
|
|
1000
|
+
}
|
|
1001
|
+
if (attrs.ky) {
|
|
1002
|
+
shadow.skewVertical = parseInt(attrs.ky, 10);
|
|
1003
|
+
}
|
|
1004
|
+
return shadow;
|
|
1005
|
+
}
|
|
1006
|
+
function parseScene3D(xml) {
|
|
1007
|
+
const sceneStart = xml.indexOf("<a:scene3d");
|
|
1008
|
+
const sceneEnd = xml.indexOf("</a:scene3d");
|
|
1009
|
+
if (sceneStart < 0 || sceneEnd < 0) {
|
|
1010
|
+
return undefined;
|
|
1011
|
+
}
|
|
1012
|
+
const region = xml.slice(sceneStart, sceneEnd + 13);
|
|
1013
|
+
const result = {};
|
|
1014
|
+
const cameraMatch = /<a:camera\s+([^>]*)(?:\/|>[\s\S]*?<\/a:camera)>/.exec(region);
|
|
1015
|
+
if (cameraMatch) {
|
|
1016
|
+
const attrs = parseAttrs(cameraMatch[0]);
|
|
1017
|
+
if (attrs.prst) {
|
|
1018
|
+
result.camera = { preset: attrs.prst };
|
|
1019
|
+
if (attrs.fov) {
|
|
1020
|
+
result.camera.fov = parseInt(attrs.fov, 10);
|
|
1021
|
+
}
|
|
1022
|
+
if (attrs.zoom) {
|
|
1023
|
+
result.camera.zoom = parseInt(attrs.zoom, 10);
|
|
1024
|
+
}
|
|
1025
|
+
const rotMatch = /<a:rot\s+([^/>]*)\s*\/>/.exec(cameraMatch[0]);
|
|
1026
|
+
if (rotMatch) {
|
|
1027
|
+
const ra = parseAttrs(rotMatch[0]);
|
|
1028
|
+
if (ra.lat && ra.lon && ra.rev) {
|
|
1029
|
+
result.camera.rotation = {
|
|
1030
|
+
lat: parseInt(ra.lat, 10),
|
|
1031
|
+
lon: parseInt(ra.lon, 10),
|
|
1032
|
+
rev: parseInt(ra.rev, 10)
|
|
1033
|
+
};
|
|
1034
|
+
}
|
|
1035
|
+
}
|
|
1036
|
+
}
|
|
1037
|
+
}
|
|
1038
|
+
const lightRigMatch = /<a:lightRig\s+([^>]*)(?:\/|>[\s\S]*?<\/a:lightRig)>/.exec(region);
|
|
1039
|
+
if (lightRigMatch) {
|
|
1040
|
+
const attrs = parseAttrs(lightRigMatch[0]);
|
|
1041
|
+
if (attrs.rig && attrs.dir) {
|
|
1042
|
+
result.lightRig = { rig: attrs.rig, direction: attrs.dir };
|
|
1043
|
+
}
|
|
1044
|
+
}
|
|
1045
|
+
if (!result.camera && !result.lightRig) {
|
|
1046
|
+
return undefined;
|
|
1047
|
+
}
|
|
1048
|
+
return result;
|
|
1049
|
+
}
|
|
1050
|
+
function parseSp3D(xml) {
|
|
1051
|
+
const spStart = xml.indexOf("<a:sp3d");
|
|
1052
|
+
if (spStart < 0) {
|
|
1053
|
+
return undefined;
|
|
1054
|
+
}
|
|
1055
|
+
// Determine the tag extent using indexOf (no backtracking risk).
|
|
1056
|
+
const selfCloseEnd = xml.indexOf("/>", spStart);
|
|
1057
|
+
const openTagEnd = xml.indexOf(">", spStart);
|
|
1058
|
+
const isSelfClose = selfCloseEnd >= 0 && (openTagEnd < 0 || selfCloseEnd < openTagEnd);
|
|
1059
|
+
let region;
|
|
1060
|
+
if (isSelfClose) {
|
|
1061
|
+
region = xml.slice(spStart, selfCloseEnd + 2);
|
|
1062
|
+
}
|
|
1063
|
+
else if (openTagEnd >= 0) {
|
|
1064
|
+
const closeTag = "</a:sp3d>";
|
|
1065
|
+
const closeIdx = xml.indexOf(closeTag, openTagEnd);
|
|
1066
|
+
region =
|
|
1067
|
+
closeIdx >= 0
|
|
1068
|
+
? xml.slice(spStart, closeIdx + closeTag.length)
|
|
1069
|
+
: xml.slice(spStart, openTagEnd + 1);
|
|
1070
|
+
}
|
|
1071
|
+
else {
|
|
1072
|
+
region = xml.slice(spStart);
|
|
1073
|
+
}
|
|
1074
|
+
// Only parse attributes from the opening tag itself — NOT from child
|
|
1075
|
+
// elements (e.g. `<a:bevelT w="..." h="..."/>`) which would pollute
|
|
1076
|
+
// the attribute dict with unrelated keys.
|
|
1077
|
+
const firstClose = region.indexOf(">");
|
|
1078
|
+
const openTag = firstClose >= 0 ? region.slice(0, firstClose + 1) : region;
|
|
1079
|
+
const attrs = parseAttrs(openTag);
|
|
1080
|
+
const result = {};
|
|
1081
|
+
if (attrs.z) {
|
|
1082
|
+
result.z = parseInt(attrs.z, 10);
|
|
1083
|
+
}
|
|
1084
|
+
if (attrs.extrusionH) {
|
|
1085
|
+
result.extrusionHeight = parseInt(attrs.extrusionH, 10);
|
|
1086
|
+
}
|
|
1087
|
+
if (attrs.contourW) {
|
|
1088
|
+
result.contourWidth = parseInt(attrs.contourW, 10);
|
|
1089
|
+
}
|
|
1090
|
+
if (attrs.prstMaterial) {
|
|
1091
|
+
result.material = attrs.prstMaterial;
|
|
1092
|
+
}
|
|
1093
|
+
// Bevels — use indexOf to find the self-closing tags within the region
|
|
1094
|
+
const bevelTStart = region.indexOf("<a:bevelT");
|
|
1095
|
+
if (bevelTStart >= 0) {
|
|
1096
|
+
const bevelTEnd = region.indexOf("/>", bevelTStart);
|
|
1097
|
+
if (bevelTEnd >= 0) {
|
|
1098
|
+
result.bevelTop = parseBevelAttrs(region.slice(bevelTStart, bevelTEnd + 2));
|
|
1099
|
+
}
|
|
1100
|
+
}
|
|
1101
|
+
const bevelBStart = region.indexOf("<a:bevelB");
|
|
1102
|
+
if (bevelBStart >= 0) {
|
|
1103
|
+
const bevelBEnd = region.indexOf("/>", bevelBStart);
|
|
1104
|
+
if (bevelBEnd >= 0) {
|
|
1105
|
+
result.bevelBottom = parseBevelAttrs(region.slice(bevelBStart, bevelBEnd + 2));
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
// Extrusion / contour colours — only present in open-close form
|
|
1109
|
+
if (!isSelfClose) {
|
|
1110
|
+
const extOpen = "<a:extrusionClr>";
|
|
1111
|
+
const extClose = "</a:extrusionClr>";
|
|
1112
|
+
const extStart = region.indexOf(extOpen);
|
|
1113
|
+
if (extStart >= 0) {
|
|
1114
|
+
const extEnd = region.indexOf(extClose, extStart);
|
|
1115
|
+
if (extEnd >= 0) {
|
|
1116
|
+
const c = parseColorFromXml(region.slice(extStart + extOpen.length, extEnd));
|
|
1117
|
+
if (c) {
|
|
1118
|
+
result.extrusionColor = c;
|
|
1119
|
+
}
|
|
1120
|
+
}
|
|
1121
|
+
}
|
|
1122
|
+
const contOpen = "<a:contourClr>";
|
|
1123
|
+
const contClose = "</a:contourClr>";
|
|
1124
|
+
const contStart = region.indexOf(contOpen);
|
|
1125
|
+
if (contStart >= 0) {
|
|
1126
|
+
const contEnd = region.indexOf(contClose, contStart);
|
|
1127
|
+
if (contEnd >= 0) {
|
|
1128
|
+
const c = parseColorFromXml(region.slice(contStart + contOpen.length, contEnd));
|
|
1129
|
+
if (c) {
|
|
1130
|
+
result.contourColor = c;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
}
|
|
1134
|
+
}
|
|
1135
|
+
return result;
|
|
1136
|
+
}
|
|
1137
|
+
function parseBevelAttrs(tag) {
|
|
1138
|
+
const attrs = parseAttrs(tag);
|
|
1139
|
+
const bevel = {};
|
|
1140
|
+
if (attrs.w) {
|
|
1141
|
+
bevel.width = parseInt(attrs.w, 10);
|
|
1142
|
+
}
|
|
1143
|
+
if (attrs.h) {
|
|
1144
|
+
bevel.height = parseInt(attrs.h, 10);
|
|
1145
|
+
}
|
|
1146
|
+
if (attrs.prst) {
|
|
1147
|
+
bevel.preset = attrs.prst;
|
|
1148
|
+
}
|
|
1149
|
+
return bevel;
|
|
1150
|
+
}
|
|
1151
|
+
function parseAttrs(tag) {
|
|
1152
|
+
const attrs = {};
|
|
1153
|
+
// Manual parser avoids regex backtracking on uncontrolled input.
|
|
1154
|
+
let i = 0;
|
|
1155
|
+
const len = tag.length;
|
|
1156
|
+
while (i < len) {
|
|
1157
|
+
// Skip non-word characters
|
|
1158
|
+
while (i < len && !isWordChar(tag.charCodeAt(i))) {
|
|
1159
|
+
i++;
|
|
1160
|
+
}
|
|
1161
|
+
if (i >= len) {
|
|
1162
|
+
break;
|
|
1163
|
+
}
|
|
1164
|
+
// Read attribute name (word chars only)
|
|
1165
|
+
const nameStart = i;
|
|
1166
|
+
while (i < len && isWordChar(tag.charCodeAt(i))) {
|
|
1167
|
+
i++;
|
|
1168
|
+
}
|
|
1169
|
+
const name = tag.slice(nameStart, i);
|
|
1170
|
+
// Expect `="`
|
|
1171
|
+
if (i >= len || tag.charCodeAt(i) !== 61 /* = */) {
|
|
1172
|
+
continue;
|
|
1173
|
+
}
|
|
1174
|
+
i++;
|
|
1175
|
+
if (i >= len || tag.charCodeAt(i) !== 34 /* " */) {
|
|
1176
|
+
continue;
|
|
1177
|
+
}
|
|
1178
|
+
i++;
|
|
1179
|
+
// Read attribute value until closing quote
|
|
1180
|
+
const valStart = i;
|
|
1181
|
+
while (i < len && tag.charCodeAt(i) !== 34) {
|
|
1182
|
+
i++;
|
|
1183
|
+
}
|
|
1184
|
+
attrs[name] = tag.slice(valStart, i);
|
|
1185
|
+
if (i < len) {
|
|
1186
|
+
i++; // skip closing quote
|
|
1187
|
+
}
|
|
1188
|
+
}
|
|
1189
|
+
return attrs;
|
|
1190
|
+
}
|
|
1191
|
+
/** Check if a char code is a word character [A-Za-z0-9_]. */
|
|
1192
|
+
function isWordChar(c) {
|
|
1193
|
+
return ((c >= 65 && c <= 90) || // A-Z
|
|
1194
|
+
(c >= 97 && c <= 122) || // a-z
|
|
1195
|
+
(c >= 48 && c <= 57) || // 0-9
|
|
1196
|
+
c === 95 // _
|
|
1197
|
+
);
|
|
1198
|
+
}
|
|
1199
|
+
/**
|
|
1200
|
+
* Extract a single attribute value from the first occurrence of `<tagName ...>`
|
|
1201
|
+
* in `xml`. Uses indexOf to locate the tag (no backtracking risk) then a simple
|
|
1202
|
+
* attribute regex on the bounded tag substring.
|
|
1203
|
+
*/
|
|
1204
|
+
function findTagAttr(xml, tagName, attrName) {
|
|
1205
|
+
const tagStart = xml.indexOf(`<${tagName}`);
|
|
1206
|
+
if (tagStart < 0) {
|
|
1207
|
+
return undefined;
|
|
1208
|
+
}
|
|
1209
|
+
const tagEnd = xml.indexOf(">", tagStart);
|
|
1210
|
+
if (tagEnd < 0) {
|
|
1211
|
+
return undefined;
|
|
1212
|
+
}
|
|
1213
|
+
const tag = xml.slice(tagStart, tagEnd + 1);
|
|
1214
|
+
const re = new RegExp(`${attrName}="([^"]*)"`);
|
|
1215
|
+
const m = re.exec(tag);
|
|
1216
|
+
return m ? m[1] : undefined;
|
|
1217
|
+
}
|
|
1218
|
+
/**
|
|
1219
|
+
* Get the solid fill color from a ShapeProperties object.
|
|
1220
|
+
* Works for both raw XML and structured models.
|
|
1221
|
+
*/
|
|
1222
|
+
export function getSpPrFillColor(spPr) {
|
|
1223
|
+
const parsed = isRawXml(spPr) ? parseSpPr(spPr) : spPr;
|
|
1224
|
+
return parsed.fill?.solid;
|
|
1225
|
+
}
|
|
1226
|
+
/**
|
|
1227
|
+
* Get the complete fill (solid / gradient / pattern / noFill) from a
|
|
1228
|
+
* ShapeProperties object. Works for both raw XML and structured models.
|
|
1229
|
+
* Prefer this over {@link getSpPrFillColor} when the caller needs to
|
|
1230
|
+
* distinguish between "no fill", "gradient", etc. — the color-only
|
|
1231
|
+
* accessor collapses all three to `undefined`.
|
|
1232
|
+
*/
|
|
1233
|
+
export function getSpPrFill(spPr) {
|
|
1234
|
+
const parsed = isRawXml(spPr) ? parseSpPr(spPr) : spPr;
|
|
1235
|
+
return parsed.fill;
|
|
1236
|
+
}
|
|
1237
|
+
/**
|
|
1238
|
+
* Get the line/outline properties from a ShapeProperties object.
|
|
1239
|
+
*/
|
|
1240
|
+
export function getSpPrLine(spPr) {
|
|
1241
|
+
const parsed = isRawXml(spPr) ? parseSpPr(spPr) : spPr;
|
|
1242
|
+
return parsed.line;
|
|
1243
|
+
}
|
|
1244
|
+
/**
|
|
1245
|
+
* Get the gradient fill from a ShapeProperties object.
|
|
1246
|
+
*/
|
|
1247
|
+
export function getSpPrGradient(spPr) {
|
|
1248
|
+
const parsed = isRawXml(spPr) ? parseSpPr(spPr) : spPr;
|
|
1249
|
+
return parsed.fill?.gradient;
|
|
1250
|
+
}
|
|
1251
|
+
/**
|
|
1252
|
+
* Get the pattern fill from a ShapeProperties object.
|
|
1253
|
+
*/
|
|
1254
|
+
export function getSpPrPattern(spPr) {
|
|
1255
|
+
const parsed = isRawXml(spPr) ? parseSpPr(spPr) : spPr;
|
|
1256
|
+
return parsed.fill?.pattern;
|
|
1257
|
+
}
|
|
1258
|
+
// ============================================================================
|
|
1259
|
+
// txPr: Read structured properties from raw XML
|
|
1260
|
+
// ============================================================================
|
|
1261
|
+
/**
|
|
1262
|
+
* Extract structured text properties from a raw txPr XML string.
|
|
1263
|
+
*
|
|
1264
|
+
* Parses the fields the structured {@link ChartTextProperties} model
|
|
1265
|
+
* declares:
|
|
1266
|
+
* - `size`, `bold`, `italic`, `underline`, `strike`, `cap`, `baseline`,
|
|
1267
|
+
* `kern`, `spacing`, `lang` (from the first `<a:defRPr>` / `<a:rPr>`)
|
|
1268
|
+
* - `color` (from `<a:solidFill>` inside the same element)
|
|
1269
|
+
* - `fontFamily`, `eastAsianFamily`, `complexScriptFamily`
|
|
1270
|
+
* (from `<a:latin>` / `<a:ea>` / `<a:cs>` children)
|
|
1271
|
+
* - `rotation` (from `<a:bodyPr/@rot>`)
|
|
1272
|
+
*
|
|
1273
|
+
* Callers that want to preserve every attribute OOXML might carry
|
|
1274
|
+
* (e.g. `spc="100"`, `u="sng"`, `baseline="30000"`) must not rely on
|
|
1275
|
+
* this function round-tripping via structured fields alone — keep the
|
|
1276
|
+
* `_rawXml` on the txPr. This parser is a best-effort structural view
|
|
1277
|
+
* for consumers that want to READ the common properties; `_rawXml`
|
|
1278
|
+
* remains authoritative for write-side fidelity.
|
|
1279
|
+
*/
|
|
1280
|
+
export function parseTxPr(txPr) {
|
|
1281
|
+
const rawXml = getRawXml(txPr);
|
|
1282
|
+
if (!rawXml) {
|
|
1283
|
+
return txPr; // already structured
|
|
1284
|
+
}
|
|
1285
|
+
const result = {};
|
|
1286
|
+
// Font size (a:sz) — search defRPr first, then rPr
|
|
1287
|
+
const szVal = findTagAttr(rawXml, "a:defRPr", "sz") ?? findTagAttr(rawXml, "a:rPr", "sz");
|
|
1288
|
+
if (szVal) {
|
|
1289
|
+
result.size = parseInt(szVal, 10);
|
|
1290
|
+
}
|
|
1291
|
+
// Bold — accept `"1"` / `"true"` per XSD `xsd:boolean`. Previously
|
|
1292
|
+
// only `"1"` was recognised, so LibreOffice-authored files (which
|
|
1293
|
+
// emit `b="true"`) silently round-tripped bold text as regular.
|
|
1294
|
+
// An explicit `b="0"` / `b="false"` is preserved as `false` rather
|
|
1295
|
+
// than dropped — semantically distinct from the attribute being
|
|
1296
|
+
// absent (which leaves the field undefined so downstream writers
|
|
1297
|
+
// know not to force a value).
|
|
1298
|
+
const bVal = findTagAttr(rawXml, "a:defRPr", "b") ?? findTagAttr(rawXml, "a:rPr", "b");
|
|
1299
|
+
if (bVal) {
|
|
1300
|
+
result.bold = bVal === "1" || bVal === "true";
|
|
1301
|
+
}
|
|
1302
|
+
// Italic — same lenient boolean handling as `b` above.
|
|
1303
|
+
const iVal = findTagAttr(rawXml, "a:defRPr", "i") ?? findTagAttr(rawXml, "a:rPr", "i");
|
|
1304
|
+
if (iVal) {
|
|
1305
|
+
result.italic = iVal === "1" || iVal === "true";
|
|
1306
|
+
}
|
|
1307
|
+
// Underline style (a:rPr/@u). Values are the DrawingML `ST_TextUnderlineType`
|
|
1308
|
+
// enum: "none" | "sng" | "dbl" | "heavy" | "dotted" | "dottedHeavy" |
|
|
1309
|
+
// "dash" | "dashHeavy" | "dashLong" | "dashLongHeavy" | "dotDash" |
|
|
1310
|
+
// "dotDashHeavy" | "dotDotDash" | "dotDotDashHeavy" | "wavy" |
|
|
1311
|
+
// "wavyHeavy" | "wavyDbl".
|
|
1312
|
+
const uVal = findTagAttr(rawXml, "a:defRPr", "u") ?? findTagAttr(rawXml, "a:rPr", "u");
|
|
1313
|
+
if (uVal) {
|
|
1314
|
+
result.underline = uVal;
|
|
1315
|
+
}
|
|
1316
|
+
// Strike-through (a:rPr/@strike). Values: "noStrike" | "sngStrike" |
|
|
1317
|
+
// "dblStrike".
|
|
1318
|
+
const strikeVal = findTagAttr(rawXml, "a:defRPr", "strike") ?? findTagAttr(rawXml, "a:rPr", "strike");
|
|
1319
|
+
if (strikeVal) {
|
|
1320
|
+
result.strike = strikeVal;
|
|
1321
|
+
}
|
|
1322
|
+
// Capitalisation (a:rPr/@cap). Values: "none" | "small" | "all".
|
|
1323
|
+
const capVal = findTagAttr(rawXml, "a:defRPr", "cap") ?? findTagAttr(rawXml, "a:rPr", "cap");
|
|
1324
|
+
if (capVal) {
|
|
1325
|
+
result.cap = capVal;
|
|
1326
|
+
}
|
|
1327
|
+
// Baseline offset (a:rPr/@baseline) — percentage * 1000 per OOXML
|
|
1328
|
+
// (signed; positive = superscript, negative = subscript).
|
|
1329
|
+
const baselineVal = findTagAttr(rawXml, "a:defRPr", "baseline") ?? findTagAttr(rawXml, "a:rPr", "baseline");
|
|
1330
|
+
if (baselineVal) {
|
|
1331
|
+
result.baseline = parseInt(baselineVal, 10);
|
|
1332
|
+
}
|
|
1333
|
+
// Character kerning cut-off (a:rPr/@kern) — hundredths of a point.
|
|
1334
|
+
const kernVal = findTagAttr(rawXml, "a:defRPr", "kern") ?? findTagAttr(rawXml, "a:rPr", "kern");
|
|
1335
|
+
if (kernVal) {
|
|
1336
|
+
result.kern = parseInt(kernVal, 10);
|
|
1337
|
+
}
|
|
1338
|
+
// Character spacing (a:rPr/@spc) — hundredths of a point.
|
|
1339
|
+
const spcVal = findTagAttr(rawXml, "a:defRPr", "spc") ?? findTagAttr(rawXml, "a:rPr", "spc");
|
|
1340
|
+
if (spcVal) {
|
|
1341
|
+
result.spacing = parseInt(spcVal, 10);
|
|
1342
|
+
}
|
|
1343
|
+
// Language (a:rPr/@lang) — BCP 47 language tag (e.g. "en-US", "ja-JP").
|
|
1344
|
+
// Wider character class than `\w+` because tags can include hyphens
|
|
1345
|
+
// and digits ("zh-Hant-TW").
|
|
1346
|
+
const langVal = findTagAttr(rawXml, "a:defRPr", "lang") ?? findTagAttr(rawXml, "a:rPr", "lang");
|
|
1347
|
+
if (langVal) {
|
|
1348
|
+
result.lang = langVal;
|
|
1349
|
+
}
|
|
1350
|
+
// Font color. Try the paragraph-level default (`<a:defRPr>…`) first,
|
|
1351
|
+
// then fall back to the first run-property block (`<a:rPr>…`). Chart
|
|
1352
|
+
// titles / data-label rich text often carry colour on `<a:rPr>` (per
|
|
1353
|
+
// run), not on `<a:defRPr>` — the old implementation only checked the
|
|
1354
|
+
// former and silently dropped colour on round-trip.
|
|
1355
|
+
const extractColorFrom = (openTag, closeTag) => {
|
|
1356
|
+
const start = rawXml.indexOf(openTag);
|
|
1357
|
+
if (start < 0) {
|
|
1358
|
+
return undefined;
|
|
1359
|
+
}
|
|
1360
|
+
const end = rawXml.indexOf(closeTag, start);
|
|
1361
|
+
const region = rawXml.slice(start, end > 0 ? end + closeTag.length : undefined);
|
|
1362
|
+
if (!region.includes("<a:solidFill")) {
|
|
1363
|
+
return undefined;
|
|
1364
|
+
}
|
|
1365
|
+
return parseColorFromXml(region);
|
|
1366
|
+
};
|
|
1367
|
+
result.color =
|
|
1368
|
+
extractColorFrom("<a:defRPr", "</a:defRPr>") ?? extractColorFrom("<a:rPr", "</a:rPr>");
|
|
1369
|
+
// Latin font family (a:latin/@typeface) — structured default.
|
|
1370
|
+
const latinMatch = /<a:latin\s+typeface="([^"]+)"/.exec(rawXml);
|
|
1371
|
+
if (latinMatch) {
|
|
1372
|
+
result.fontFamily = latinMatch[1];
|
|
1373
|
+
}
|
|
1374
|
+
// East Asian font family (a:ea/@typeface) — used for CJK characters
|
|
1375
|
+
// when the primary Latin font doesn't cover them. Dropping this
|
|
1376
|
+
// field on round-trip made CJK-labelled charts reflow on reload.
|
|
1377
|
+
const eaMatch = /<a:ea\s+typeface="([^"]+)"/.exec(rawXml);
|
|
1378
|
+
if (eaMatch) {
|
|
1379
|
+
result.eastAsianFamily = eaMatch[1];
|
|
1380
|
+
}
|
|
1381
|
+
// Complex-script font family (a:cs/@typeface) — used for Arabic /
|
|
1382
|
+
// Hebrew / Thai fallbacks.
|
|
1383
|
+
const csMatch = /<a:cs\s+typeface="([^"]+)"/.exec(rawXml);
|
|
1384
|
+
if (csMatch) {
|
|
1385
|
+
result.complexScriptFamily = csMatch[1];
|
|
1386
|
+
}
|
|
1387
|
+
// Rotation (on bodyPr)
|
|
1388
|
+
const rotVal = findTagAttr(rawXml, "a:bodyPr", "rot");
|
|
1389
|
+
if (rotVal) {
|
|
1390
|
+
result.rotation = parseInt(rotVal, 10);
|
|
1391
|
+
}
|
|
1392
|
+
return result;
|
|
1393
|
+
}
|
|
1394
|
+
/**
|
|
1395
|
+
* Get font size from a ChartTextProperties object (returns points, e.g. 10).
|
|
1396
|
+
*/
|
|
1397
|
+
export function getTxPrFontSize(txPr) {
|
|
1398
|
+
const parsed = isRawXml(txPr) ? parseTxPr(txPr) : txPr;
|
|
1399
|
+
return parsed.size !== undefined ? parsed.size / 100 : undefined;
|
|
1400
|
+
}
|
|
1401
|
+
/**
|
|
1402
|
+
* Get font color from a ChartTextProperties object.
|
|
1403
|
+
*/
|
|
1404
|
+
export function getTxPrColor(txPr) {
|
|
1405
|
+
const parsed = isRawXml(txPr) ? parseTxPr(txPr) : txPr;
|
|
1406
|
+
return parsed.color;
|
|
1407
|
+
}
|
|
1408
|
+
/**
|
|
1409
|
+
* Get the font family (typeface) declared on `<a:latin>` / `<a:cs>`
|
|
1410
|
+
* within a `txPr` raw or structured object. Returns `undefined` if the
|
|
1411
|
+
* properties do not carry a typeface, in which case renderers should
|
|
1412
|
+
* use their own default.
|
|
1413
|
+
*/
|
|
1414
|
+
export function getTxPrFontFamily(txPr) {
|
|
1415
|
+
const parsed = isRawXml(txPr) ? parseTxPr(txPr) : txPr;
|
|
1416
|
+
return parsed.fontFamily;
|
|
1417
|
+
}
|
|
1418
|
+
/**
|
|
1419
|
+
* Get the boolean bold flag from a `txPr`'s first `a:defRPr`/`a:rPr`.
|
|
1420
|
+
*/
|
|
1421
|
+
export function getTxPrBold(txPr) {
|
|
1422
|
+
const parsed = isRawXml(txPr) ? parseTxPr(txPr) : txPr;
|
|
1423
|
+
return parsed.bold;
|
|
1424
|
+
}
|
|
1425
|
+
/**
|
|
1426
|
+
* Get the boolean italic flag from a `txPr`'s first `a:defRPr`/`a:rPr`.
|
|
1427
|
+
*/
|
|
1428
|
+
export function getTxPrItalic(txPr) {
|
|
1429
|
+
const parsed = isRawXml(txPr) ? parseTxPr(txPr) : txPr;
|
|
1430
|
+
return parsed.italic;
|
|
1431
|
+
}
|
|
1432
|
+
// ============================================================================
|
|
1433
|
+
// Build structured spPr / txPr models
|
|
1434
|
+
// ============================================================================
|
|
1435
|
+
//
|
|
1436
|
+
// Previously this module also produced raw DrawingML XML for spPr / txPr via
|
|
1437
|
+
// a `colorToXml` helper. That path was removed because the chart writer
|
|
1438
|
+
// (`chart-space-xform._renderSpPr` / `_renderTxPr` / `_renderColor`) emits
|
|
1439
|
+
// the XML directly from structured data, and returning raw XML here forced
|
|
1440
|
+
// callers to rebuild `buildTxPr` after every mutation. The helper was dead
|
|
1441
|
+
// code and has been deleted — see the note on `buildTxPr` below.
|
|
1442
|
+
/**
|
|
1443
|
+
* Build a structured ShapeProperties object, preserving every field that
|
|
1444
|
+
* `parseSpPr` can produce (fill, line, effectList, scene3d, sp3d, transform,
|
|
1445
|
+
* presetGeometry, customGeometry, bwMode).
|
|
1446
|
+
*
|
|
1447
|
+
* Previous versions only copied a five-field subset, which caused
|
|
1448
|
+
* `setSpPrFill` / `setSpPrLine` to silently strip `xfrm` / `prstGeom` /
|
|
1449
|
+
* `custGeom` off the returned spPr whenever the input had been parsed from
|
|
1450
|
+
* raw XML. The earlier `_rawXml` round-trip path was dropped because it lost
|
|
1451
|
+
* effectList/scene3d/sp3d; we now keep all structured fields and intentionally
|
|
1452
|
+
* omit `_rawXml` so that `_renderSpPr` (chart-space-xform) re-emits the spPr
|
|
1453
|
+
* from the structured data.
|
|
1454
|
+
*/
|
|
1455
|
+
export function buildSpPr(props) {
|
|
1456
|
+
const result = {};
|
|
1457
|
+
if (props.fill) {
|
|
1458
|
+
result.fill = props.fill;
|
|
1459
|
+
}
|
|
1460
|
+
if (props.line) {
|
|
1461
|
+
result.line = props.line;
|
|
1462
|
+
}
|
|
1463
|
+
if (props.effectList) {
|
|
1464
|
+
result.effectList = props.effectList;
|
|
1465
|
+
}
|
|
1466
|
+
if (props.scene3d) {
|
|
1467
|
+
result.scene3d = props.scene3d;
|
|
1468
|
+
}
|
|
1469
|
+
if (props.sp3d) {
|
|
1470
|
+
result.sp3d = props.sp3d;
|
|
1471
|
+
}
|
|
1472
|
+
if (props.transform) {
|
|
1473
|
+
result.transform = props.transform;
|
|
1474
|
+
}
|
|
1475
|
+
if (props.presetGeometry) {
|
|
1476
|
+
result.presetGeometry = props.presetGeometry;
|
|
1477
|
+
}
|
|
1478
|
+
if (props.customGeometry) {
|
|
1479
|
+
result.customGeometry = props.customGeometry;
|
|
1480
|
+
}
|
|
1481
|
+
return result;
|
|
1482
|
+
}
|
|
1483
|
+
/**
|
|
1484
|
+
* Build a structured {@link ChartTextProperties} object.
|
|
1485
|
+
*
|
|
1486
|
+
* Returns a plain structured copy (no `_rawXml`) so downstream mutations
|
|
1487
|
+
* (`props.size = 1400`) take effect when the txPr is later serialised.
|
|
1488
|
+
* The writer (`_renderTxPr` / `_renderRunProperties` in
|
|
1489
|
+
* `chart-space-xform.ts`) fully supports structured txPr data and only
|
|
1490
|
+
* falls back to raw XML pass-through when `_rawXml` is present; returning
|
|
1491
|
+
* `_rawXml` here would freeze the txPr and silently discard subsequent
|
|
1492
|
+
* edits, which is a trap API.
|
|
1493
|
+
*/
|
|
1494
|
+
export function buildTxPr(props) {
|
|
1495
|
+
const result = {};
|
|
1496
|
+
if (props.size !== undefined) {
|
|
1497
|
+
result.size = props.size;
|
|
1498
|
+
}
|
|
1499
|
+
if (props.bold !== undefined) {
|
|
1500
|
+
result.bold = props.bold;
|
|
1501
|
+
}
|
|
1502
|
+
if (props.italic !== undefined) {
|
|
1503
|
+
result.italic = props.italic;
|
|
1504
|
+
}
|
|
1505
|
+
if (props.underline !== undefined) {
|
|
1506
|
+
result.underline = props.underline;
|
|
1507
|
+
}
|
|
1508
|
+
if (props.strike !== undefined) {
|
|
1509
|
+
result.strike = props.strike;
|
|
1510
|
+
}
|
|
1511
|
+
if (props.rotation !== undefined) {
|
|
1512
|
+
result.rotation = props.rotation;
|
|
1513
|
+
}
|
|
1514
|
+
if (props.baseline !== undefined) {
|
|
1515
|
+
result.baseline = props.baseline;
|
|
1516
|
+
}
|
|
1517
|
+
if (props.kern !== undefined) {
|
|
1518
|
+
result.kern = props.kern;
|
|
1519
|
+
}
|
|
1520
|
+
if (props.spacing !== undefined) {
|
|
1521
|
+
result.spacing = props.spacing;
|
|
1522
|
+
}
|
|
1523
|
+
if (props.cap !== undefined) {
|
|
1524
|
+
result.cap = props.cap;
|
|
1525
|
+
}
|
|
1526
|
+
if (props.lang !== undefined) {
|
|
1527
|
+
result.lang = props.lang;
|
|
1528
|
+
}
|
|
1529
|
+
if (props.color) {
|
|
1530
|
+
result.color = props.color;
|
|
1531
|
+
}
|
|
1532
|
+
if (props.fontFamily) {
|
|
1533
|
+
result.fontFamily = props.fontFamily;
|
|
1534
|
+
}
|
|
1535
|
+
if (props.eastAsianFamily) {
|
|
1536
|
+
result.eastAsianFamily = props.eastAsianFamily;
|
|
1537
|
+
}
|
|
1538
|
+
if (props.complexScriptFamily) {
|
|
1539
|
+
result.complexScriptFamily = props.complexScriptFamily;
|
|
1540
|
+
}
|
|
1541
|
+
return result;
|
|
1542
|
+
}
|
|
1543
|
+
/**
|
|
1544
|
+
* Modify a property on an existing spPr (raw or structured).
|
|
1545
|
+
* Returns a new ShapeProperties object with the modification applied.
|
|
1546
|
+
*/
|
|
1547
|
+
export function setSpPrFill(spPr, fill) {
|
|
1548
|
+
const parsed = spPr && isRawXml(spPr) ? parseSpPr(spPr) : (spPr ?? {});
|
|
1549
|
+
return buildSpPr({ ...parsed, fill });
|
|
1550
|
+
}
|
|
1551
|
+
/**
|
|
1552
|
+
* Modify line properties on an existing spPr.
|
|
1553
|
+
*/
|
|
1554
|
+
export function setSpPrLine(spPr, line) {
|
|
1555
|
+
const parsed = spPr && isRawXml(spPr) ? parseSpPr(spPr) : (spPr ?? {});
|
|
1556
|
+
return buildSpPr({ ...parsed, line });
|
|
1557
|
+
}
|