ooxml-core 0.19.0 → 0.21.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/README.md +21 -43
- package/dist/automation/index.cjs +195 -193
- package/dist/automation/index.mjs +195 -193
- package/dist/chart/axis-nice.d.ts +97 -0
- package/dist/chart/axis-nice.d.ts.map +1 -0
- package/dist/chart/histogram-binning.d.ts +40 -0
- package/dist/chart/histogram-binning.d.ts.map +1 -0
- package/dist/chart/index.cjs +167 -0
- package/dist/chart/index.d.ts +2 -0
- package/dist/chart/index.d.ts.map +1 -1
- package/dist/chart/index.mjs +162 -1
- package/dist/diagram/index.cjs +2 -1
- package/dist/diagram/index.mjs +2 -1
- package/dist/docx/attr-units.d.ts +11 -0
- package/dist/docx/attr-units.d.ts.map +1 -0
- package/dist/docx/block-parser.d.ts.map +1 -1
- package/dist/docx/case-transform.d.ts +9 -0
- package/dist/docx/case-transform.d.ts.map +1 -0
- package/dist/docx/embedded.cjs +2 -1
- package/dist/docx/embedded.mjs +2 -1
- package/dist/docx/index.cjs +289 -3
- package/dist/docx/index.d.ts +5 -0
- package/dist/docx/index.d.ts.map +1 -1
- package/dist/docx/index.mjs +269 -4
- package/dist/docx/layout/adapter.d.ts.map +1 -1
- package/dist/docx/layout/table-layout.d.ts.map +1 -1
- package/dist/docx/load/index.cjs +2 -1
- package/dist/docx/load/index.mjs +2 -1
- package/dist/docx/page-setup-model.d.ts +29 -0
- package/dist/docx/page-setup-model.d.ts.map +1 -0
- package/dist/docx/page-size.d.ts +11 -0
- package/dist/docx/page-size.d.ts.map +1 -0
- package/dist/docx/parse.d.ts.map +1 -1
- package/dist/docx/section-edit.d.ts +19 -0
- package/dist/docx/section-edit.d.ts.map +1 -0
- package/dist/docx/tab-stops.d.ts.map +1 -1
- package/dist/docx/ui/backstage-focus.d.ts +6 -0
- package/dist/docx/ui/backstage-focus.d.ts.map +1 -0
- package/dist/docx/ui/break-note-schema.d.ts +11 -0
- package/dist/docx/ui/break-note-schema.d.ts.map +1 -0
- package/dist/docx/ui/collaboration-authority.d.ts +31 -0
- package/dist/docx/ui/collaboration-authority.d.ts.map +1 -0
- package/dist/docx/ui/collaboration-identity.d.ts +8 -0
- package/dist/docx/ui/collaboration-identity.d.ts.map +1 -0
- package/dist/docx/ui/collaboration-protocol.d.ts +25 -0
- package/dist/docx/ui/collaboration-protocol.d.ts.map +1 -0
- package/dist/docx/ui/collaboration.d.ts +30 -0
- package/dist/docx/ui/collaboration.d.ts.map +1 -0
- package/dist/docx/ui/defined.d.ts +3 -0
- package/dist/docx/ui/defined.d.ts.map +1 -0
- package/dist/docx/ui/dirty-state.d.ts +9 -0
- package/dist/docx/ui/dirty-state.d.ts.map +1 -0
- package/dist/docx/ui/field-guard.d.ts +21 -0
- package/dist/docx/ui/field-guard.d.ts.map +1 -0
- package/dist/docx/ui/header-footer-history.d.ts +15 -0
- package/dist/docx/ui/header-footer-history.d.ts.map +1 -0
- package/dist/docx/ui/index.cjs +2380 -0
- package/dist/docx/ui/index.d.ts +30 -0
- package/dist/docx/ui/index.d.ts.map +1 -0
- package/dist/docx/ui/index.mjs +2317 -0
- package/dist/docx/ui/inline-content-schema.d.ts +15 -0
- package/dist/docx/ui/inline-content-schema.d.ts.map +1 -0
- package/dist/docx/ui/ligature-style.d.ts +4 -0
- package/dist/docx/ui/ligature-style.d.ts.map +1 -0
- package/dist/docx/ui/node-numbering.d.ts +8 -0
- package/dist/docx/ui/node-numbering.d.ts.map +1 -0
- package/dist/docx/ui/review-schema.d.ts +90 -0
- package/dist/docx/ui/review-schema.d.ts.map +1 -0
- package/dist/docx/ui/ribbon-action-ids.d.ts +26 -0
- package/dist/docx/ui/ribbon-action-ids.d.ts.map +1 -0
- package/dist/docx/ui/ribbon-colors.d.ts +3 -0
- package/dist/docx/ui/ribbon-colors.d.ts.map +1 -0
- package/dist/docx/ui/ribbon-legacy-labels.d.ts +6 -0
- package/dist/docx/ui/ribbon-legacy-labels.d.ts.map +1 -0
- package/dist/docx/ui/run-compare.d.ts +5 -0
- package/dist/docx/ui/run-compare.d.ts.map +1 -0
- package/dist/docx/ui/run-extra-mark.d.ts +17 -0
- package/dist/docx/ui/run-extra-mark.d.ts.map +1 -0
- package/dist/docx/ui/schema-marks.d.ts +273 -0
- package/dist/docx/ui/schema-marks.d.ts.map +1 -0
- package/dist/docx/ui/smartart-theme.d.ts +21 -0
- package/dist/docx/ui/smartart-theme.d.ts.map +1 -0
- package/dist/docx/ui/table-render.d.ts +24 -0
- package/dist/docx/ui/table-render.d.ts.map +1 -0
- package/dist/docx/ui/table-visuals.d.ts +3 -0
- package/dist/docx/ui/table-visuals.d.ts.map +1 -0
- package/dist/docx/ui/theme/css-vars.d.ts +6 -0
- package/dist/docx/ui/theme/css-vars.d.ts.map +1 -0
- package/dist/docx/ui/theme/defaults.d.ts +12 -0
- package/dist/docx/ui/theme/defaults.d.ts.map +1 -0
- package/dist/docx/ui/theme/element.d.ts +9 -0
- package/dist/docx/ui/theme/element.d.ts.map +1 -0
- package/dist/docx/ui/theme/index.d.ts +5 -0
- package/dist/docx/ui/theme/index.d.ts.map +1 -0
- package/dist/docx/ui/theme/types.d.ts +42 -0
- package/dist/docx/ui/theme/types.d.ts.map +1 -0
- package/dist/docx/ui/word-count.d.ts +3 -0
- package/dist/docx/ui/word-count.d.ts.map +1 -0
- package/dist/docx/ui/zoom-fit.d.ts +16 -0
- package/dist/docx/ui/zoom-fit.d.ts.map +1 -0
- package/dist/docx/validate-paragraph.d.ts.map +1 -1
- package/dist/index.cjs +169 -1
- package/dist/index.mjs +169 -1
- package/dist/math/index.cjs +2 -1
- package/dist/math/index.mjs +2 -1
- package/dist/opc/index.cjs +2 -1
- package/dist/opc/index.mjs +2 -1
- package/dist/pptx/automation/index.cjs +1572 -863
- package/dist/pptx/automation/index.d.ts +4 -3
- package/dist/pptx/automation/index.d.ts.map +1 -1
- package/dist/pptx/automation/index.mjs +1572 -863
- package/dist/pptx/chunks/color-ref-BM66NGFP.d.ts +42 -0
- package/dist/pptx/chunks/color-ref-BM66NGFP.d.ts.map +1 -0
- package/dist/pptx/chunks/{index-D0yGoLyw.d.ts → index-CcQTCBnT.d.ts} +63 -479
- package/dist/pptx/chunks/index-CcQTCBnT.d.ts.map +1 -0
- package/dist/pptx/chunks/{index-BtBj3VG1.d.ts → index-DHoPgFcH.d.ts} +529 -11
- package/dist/pptx/chunks/index-DHoPgFcH.d.ts.map +1 -0
- package/dist/pptx/chunks/{text-operations-GuisjlbR.d.ts → text-operations-BzdehTeY.d.ts} +50 -51
- package/dist/pptx/chunks/text-operations-BzdehTeY.d.ts.map +1 -0
- package/dist/pptx/cli/index.cjs +1204 -489
- package/dist/pptx/cli/index.d.ts +1 -1
- package/dist/pptx/cli/index.mjs +1204 -489
- package/dist/pptx/converter/index.cjs +8 -5
- package/dist/pptx/converter/index.d.ts +1 -1
- package/dist/pptx/converter/index.mjs +8 -5
- package/dist/pptx/index.cjs +1699 -989
- package/dist/pptx/index.d.ts +5 -4
- package/dist/pptx/index.mjs +1698 -990
- package/dist/pptx/ui/index.cjs +510 -0
- package/dist/pptx/ui/index.d.ts +80 -0
- package/dist/pptx/ui/index.d.ts.map +1 -0
- package/dist/pptx/ui/index.mjs +499 -0
- package/dist/visio/index.cjs +2 -1
- package/dist/visio/index.mjs +2 -1
- package/dist/visio/ui/contract.d.ts +33 -0
- package/dist/visio/ui/contract.d.ts.map +1 -0
- package/dist/visio/ui/demo-document.d.ts +4 -0
- package/dist/visio/ui/demo-document.d.ts.map +1 -0
- package/dist/visio/ui/diagnostics.d.ts +10 -0
- package/dist/visio/ui/diagnostics.d.ts.map +1 -0
- package/dist/visio/ui/document-history.d.ts +43 -0
- package/dist/visio/ui/document-history.d.ts.map +1 -0
- package/dist/visio/ui/document-text-search.d.ts +45 -0
- package/dist/visio/ui/document-text-search.d.ts.map +1 -0
- package/dist/visio/ui/edit-commands.d.ts +4 -0
- package/dist/visio/ui/edit-commands.d.ts.map +1 -0
- package/dist/visio/ui/edit-error.d.ts +5 -0
- package/dist/visio/ui/edit-error.d.ts.map +1 -0
- package/dist/visio/ui/foreign-vector-budget.d.ts +25 -0
- package/dist/visio/ui/foreign-vector-budget.d.ts.map +1 -0
- package/dist/visio/ui/index.cjs +1523 -0
- package/dist/visio/ui/index.d.ts +12 -0
- package/dist/visio/ui/index.d.ts.map +1 -0
- package/dist/visio/ui/index.mjs +1498 -0
- package/dist/visio/ui/scene-details.d.ts +8 -0
- package/dist/visio/ui/scene-details.d.ts.map +1 -0
- package/dist/visio/ui/scene-validation.d.ts +5 -0
- package/dist/visio/ui/scene-validation.d.ts.map +1 -0
- package/dist/visio/ui/snapshot-scene.d.ts +9 -0
- package/dist/visio/ui/snapshot-scene.d.ts.map +1 -0
- package/dist/xlsx/index.cjs +100 -98
- package/dist/xlsx/index.mjs +100 -98
- package/dist/xlsx/load/index.cjs +68 -66
- package/dist/xlsx/load/index.mjs +68 -66
- package/dist/xlsx/ui/backstage/templates.d.ts +16 -0
- package/dist/xlsx/ui/backstage/templates.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/alignment.d.ts +4 -0
- package/dist/xlsx/ui/commands/alignment.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/cells.d.ts +3 -0
- package/dist/xlsx/ui/commands/cells.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/cf-presets.d.ts +15 -0
- package/dist/xlsx/ui/commands/cf-presets.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/clipboard.d.ts +22 -0
- package/dist/xlsx/ui/commands/clipboard.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/contextual.d.ts +13 -0
- package/dist/xlsx/ui/commands/contextual.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/data.d.ts +3 -0
- package/dist/xlsx/ui/commands/data.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/editing.d.ts +13 -0
- package/dist/xlsx/ui/commands/editing.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/font.d.ts +21 -0
- package/dist/xlsx/ui/commands/font.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/formulas.d.ts +15 -0
- package/dist/xlsx/ui/commands/formulas.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/core-features.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/core-features.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/format-cells.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/format-cells.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/index.d.ts +4 -0
- package/dist/xlsx/ui/commands/i18n/index.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/messages.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/messages.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/navigation.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/navigation.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/ribbon-home.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/ribbon-home.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/ribbon-tabs.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/ribbon-tabs.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/rules.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/rules.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/tools.d.ts +3 -0
- package/dist/xlsx/ui/commands/i18n/tools.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/i18n/types.d.ts +5 -0
- package/dist/xlsx/ui/commands/i18n/types.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/icons.d.ts +4 -0
- package/dist/xlsx/ui/commands/icons.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/number.d.ts +11 -0
- package/dist/xlsx/ui/commands/number.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/page-layout.d.ts +10 -0
- package/dist/xlsx/ui/commands/page-layout.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/select-special.d.ts +12 -0
- package/dist/xlsx/ui/commands/select-special.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/sort-filter.d.ts +3 -0
- package/dist/xlsx/ui/commands/sort-filter.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/style-presets.d.ts +21 -0
- package/dist/xlsx/ui/commands/style-presets.d.ts.map +1 -0
- package/dist/xlsx/ui/commands/util.d.ts +59 -0
- package/dist/xlsx/ui/commands/util.d.ts.map +1 -0
- package/dist/xlsx/ui/commands.d.ts +36 -0
- package/dist/xlsx/ui/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/context-menu/items.d.ts +36 -0
- package/dist/xlsx/ui/context-menu/items.d.ts.map +1 -0
- package/dist/xlsx/ui/context.d.ts +65 -0
- package/dist/xlsx/ui/context.d.ts.map +1 -0
- package/dist/xlsx/ui/dialogs/format-cells/number-categories.d.ts +28 -0
- package/dist/xlsx/ui/dialogs/format-cells/number-categories.d.ts.map +1 -0
- package/dist/xlsx/ui/dialogs/format-cells/types.d.ts +40 -0
- package/dist/xlsx/ui/dialogs/format-cells/types.d.ts.map +1 -0
- package/dist/xlsx/ui/dialogs/insert-chart-model.d.ts +9 -0
- package/dist/xlsx/ui/dialogs/insert-chart-model.d.ts.map +1 -0
- package/dist/xlsx/ui/dialogs.d.ts +9 -0
- package/dist/xlsx/ui/dialogs.d.ts.map +1 -0
- package/dist/xlsx/ui/dirty-state.d.ts +9 -0
- package/dist/xlsx/ui/dirty-state.d.ts.map +1 -0
- package/dist/xlsx/ui/formula-bar/name-resolve.d.ts +23 -0
- package/dist/xlsx/ui/formula-bar/name-resolve.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/cell-items.d.ts +42 -0
- package/dist/xlsx/ui/grid/cell-items.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/cell-paint.d.ts +26 -0
- package/dist/xlsx/ui/grid/cell-paint.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/edit-bridge.d.ts +47 -0
- package/dist/xlsx/ui/grid/edit-bridge.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/geometry.d.ts +76 -0
- package/dist/xlsx/ui/grid/geometry.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/icon-sets.d.ts +3 -0
- package/dist/xlsx/ui/grid/icon-sets.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/number-fit.d.ts +3 -0
- package/dist/xlsx/ui/grid/number-fit.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/selection-ops.d.ts +32 -0
- package/dist/xlsx/ui/grid/selection-ops.d.ts.map +1 -0
- package/dist/xlsx/ui/grid/view-cache.d.ts +15 -0
- package/dist/xlsx/ui/grid/view-cache.d.ts.map +1 -0
- package/dist/xlsx/ui/index.cjs +28484 -0
- package/dist/xlsx/ui/index.d.ts +56 -0
- package/dist/xlsx/ui/index.d.ts.map +1 -0
- package/dist/xlsx/ui/index.mjs +28290 -0
- package/dist/xlsx/ui/locales/de/commands.d.ts +2 -0
- package/dist/xlsx/ui/locales/de/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/de/grid.d.ts +2 -0
- package/dist/xlsx/ui/locales/de/grid.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/de/index.d.ts +2 -0
- package/dist/xlsx/ui/locales/de/index.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/de/shell.d.ts +2 -0
- package/dist/xlsx/ui/locales/de/shell.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/en/commands.d.ts +2 -0
- package/dist/xlsx/ui/locales/en/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/en/grid.d.ts +2 -0
- package/dist/xlsx/ui/locales/en/grid.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/en/index.d.ts +2 -0
- package/dist/xlsx/ui/locales/en/index.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/en/shell.d.ts +2 -0
- package/dist/xlsx/ui/locales/en/shell.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/es/commands.d.ts +2 -0
- package/dist/xlsx/ui/locales/es/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/es/grid.d.ts +2 -0
- package/dist/xlsx/ui/locales/es/grid.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/es/index.d.ts +2 -0
- package/dist/xlsx/ui/locales/es/index.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/es/shell.d.ts +2 -0
- package/dist/xlsx/ui/locales/es/shell.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/fr/commands.d.ts +2 -0
- package/dist/xlsx/ui/locales/fr/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/fr/grid.d.ts +2 -0
- package/dist/xlsx/ui/locales/fr/grid.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/fr/index.d.ts +2 -0
- package/dist/xlsx/ui/locales/fr/index.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/fr/shell.d.ts +2 -0
- package/dist/xlsx/ui/locales/fr/shell.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/merge.d.ts +7 -0
- package/dist/xlsx/ui/locales/merge.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/zh-CN/commands.d.ts +2 -0
- package/dist/xlsx/ui/locales/zh-CN/commands.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/zh-CN/grid.d.ts +2 -0
- package/dist/xlsx/ui/locales/zh-CN/grid.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/zh-CN/index.d.ts +2 -0
- package/dist/xlsx/ui/locales/zh-CN/index.d.ts.map +1 -0
- package/dist/xlsx/ui/locales/zh-CN/shell.d.ts +2 -0
- package/dist/xlsx/ui/locales/zh-CN/shell.d.ts.map +1 -0
- package/dist/xlsx/ui/localization.d.ts +23 -0
- package/dist/xlsx/ui/localization.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/icon-paths.d.ts +9 -0
- package/dist/xlsx/ui/ribbon/icon-paths.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/parts.d.ts +88 -0
- package/dist/xlsx/ui/ribbon/parts.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/tab-api.d.ts +21 -0
- package/dist/xlsx/ui/ribbon/tab-api.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/tabs/review-view.d.ts +5 -0
- package/dist/xlsx/ui/ribbon/tabs/review-view.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/tabs/theme-palette.d.ts +8 -0
- package/dist/xlsx/ui/ribbon/tabs/theme-palette.d.ts.map +1 -0
- package/dist/xlsx/ui/ribbon/tell-me.d.ts +16 -0
- package/dist/xlsx/ui/ribbon/tell-me.d.ts.map +1 -0
- package/dist/xlsx/ui/selection.d.ts +34 -0
- package/dist/xlsx/ui/selection.d.ts.map +1 -0
- package/dist/xlsx/ui/theme/css-vars.d.ts +6 -0
- package/dist/xlsx/ui/theme/css-vars.d.ts.map +1 -0
- package/dist/xlsx/ui/theme/defaults.d.ts +6 -0
- package/dist/xlsx/ui/theme/defaults.d.ts.map +1 -0
- package/dist/xlsx/ui/theme/element.d.ts +9 -0
- package/dist/xlsx/ui/theme/element.d.ts.map +1 -0
- package/dist/xlsx/ui/theme/types.d.ts +54 -0
- package/dist/xlsx/ui/theme/types.d.ts.map +1 -0
- package/dist/xml/index.cjs +2 -1
- package/dist/xml/index.mjs +2 -1
- package/package.json +42 -4
- package/dist/pptx/chunks/index-BtBj3VG1.d.ts.map +0 -1
- package/dist/pptx/chunks/index-D0yGoLyw.d.ts.map +0 -1
- package/dist/pptx/chunks/text-operations-GuisjlbR.d.ts.map +0 -1
|
@@ -0,0 +1,1498 @@
|
|
|
1
|
+
// src/visio/ui/contract.ts
|
|
2
|
+
var propertyKeys = [
|
|
3
|
+
"document",
|
|
4
|
+
"pageIndex",
|
|
5
|
+
"zoom",
|
|
6
|
+
"showToolbar"
|
|
7
|
+
];
|
|
8
|
+
var eventKeys = [
|
|
9
|
+
"document-load",
|
|
10
|
+
"document-change",
|
|
11
|
+
"document-error",
|
|
12
|
+
"page-change",
|
|
13
|
+
"zoom-change",
|
|
14
|
+
"shape-select"
|
|
15
|
+
];
|
|
16
|
+
|
|
17
|
+
// src/visio/ui/demo-document.ts
|
|
18
|
+
function box(id, name, x, y, width, height, fill, kind = "box") {
|
|
19
|
+
const path = kind === "diamond" ? `M ${width / 2} 0 L ${width} ${height / 2} L ${width / 2} ${height} L 0 ${height / 2} Z` : `M 0 0 L ${width} 0 L ${width} ${height} L 0 ${height} Z`;
|
|
20
|
+
return {
|
|
21
|
+
id,
|
|
22
|
+
name,
|
|
23
|
+
kind: "shape",
|
|
24
|
+
width,
|
|
25
|
+
height,
|
|
26
|
+
transform: [1, 0, 0, 1, x, y],
|
|
27
|
+
hidden: false,
|
|
28
|
+
children: [],
|
|
29
|
+
geometry: [{ path, fill: true, stroke: true }],
|
|
30
|
+
style: {
|
|
31
|
+
fill,
|
|
32
|
+
lineColor: "#326765",
|
|
33
|
+
lineWidth: 0.015,
|
|
34
|
+
linePattern: 1,
|
|
35
|
+
fillOpacity: 1,
|
|
36
|
+
lineOpacity: 1,
|
|
37
|
+
startArrow: 0,
|
|
38
|
+
endArrow: 0
|
|
39
|
+
},
|
|
40
|
+
text: {
|
|
41
|
+
plainText: name,
|
|
42
|
+
runs: [],
|
|
43
|
+
fontFamily: "Arial",
|
|
44
|
+
fontSize: 0.15,
|
|
45
|
+
color: "#203d40",
|
|
46
|
+
horizontalAlign: "center",
|
|
47
|
+
verticalAlign: "middle",
|
|
48
|
+
transform: [1, 0, 0, 1, 0, 0],
|
|
49
|
+
width,
|
|
50
|
+
height,
|
|
51
|
+
margins: { left: 0.06, right: 0.06, top: 0.06, bottom: 0.06 }
|
|
52
|
+
}
|
|
53
|
+
};
|
|
54
|
+
}
|
|
55
|
+
function line(id, x, y, path) {
|
|
56
|
+
const shape = box(id, "", x, y, 0, 0, "none");
|
|
57
|
+
shape.kind = "connector";
|
|
58
|
+
shape.geometry = [{ path, fill: false, stroke: true }];
|
|
59
|
+
return shape;
|
|
60
|
+
}
|
|
61
|
+
var demoDocument = {
|
|
62
|
+
format: "vsdx",
|
|
63
|
+
diagnostics: [],
|
|
64
|
+
pages: [
|
|
65
|
+
{
|
|
66
|
+
id: "1",
|
|
67
|
+
name: "Release workflow",
|
|
68
|
+
width: 8.5,
|
|
69
|
+
height: 7,
|
|
70
|
+
isBackground: false,
|
|
71
|
+
connectors: [],
|
|
72
|
+
shapes: [
|
|
73
|
+
box("s1", "Start with an idea", 2.8, 5.5, 2.8, 0.7, "#d8efeb"),
|
|
74
|
+
line("c1", 4.2, 5.5, "M 0 0 L 0 -.5"),
|
|
75
|
+
box("s2", "Design and build", 2.8, 4.3, 2.8, 0.7, "#f3eee1"),
|
|
76
|
+
line("c2", 4.2, 4.3, "M 0 0 L 0 -.45"),
|
|
77
|
+
box("s3", "Ready?", 3.35, 2.8, 1.7, 1.05, "#dfebf7", "diamond"),
|
|
78
|
+
line("c3", 4.2, 2.8, "M 0 0 L 0 -.5"),
|
|
79
|
+
box("s4", "Review and release", 2.8, 1.6, 2.8, 0.7, "#d8efeb"),
|
|
80
|
+
line("c4", 5.05, 3.325, "M 0 0 L 1.3 0 L 1.3 1.325 L .55 1.325"),
|
|
81
|
+
box(
|
|
82
|
+
"note",
|
|
83
|
+
"Explore pages \xB7 Select shapes\nZoom with + / \u2212 \xB7 Fit with 0",
|
|
84
|
+
2.3,
|
|
85
|
+
0.45,
|
|
86
|
+
3.8,
|
|
87
|
+
0.7,
|
|
88
|
+
"#ffffff"
|
|
89
|
+
)
|
|
90
|
+
]
|
|
91
|
+
},
|
|
92
|
+
{
|
|
93
|
+
id: "2",
|
|
94
|
+
name: "Architecture",
|
|
95
|
+
width: 8.5,
|
|
96
|
+
height: 5.5,
|
|
97
|
+
isBackground: false,
|
|
98
|
+
connectors: [],
|
|
99
|
+
shapes: [
|
|
100
|
+
box("a1", "Your framework", 0.7, 3.5, 2, 0.9, "#dfebf7"),
|
|
101
|
+
box("a2", "One viewer", 3.2, 3.5, 2, 0.9, "#d8efeb"),
|
|
102
|
+
box("a3", "ooxml-core", 5.7, 3.5, 2, 0.9, "#f3eee1"),
|
|
103
|
+
line("ac1", 2.7, 3.95, "M 0 0 L .5 0"),
|
|
104
|
+
line("ac2", 5.2, 3.95, "M 0 0 L .5 0"),
|
|
105
|
+
box(
|
|
106
|
+
"a4",
|
|
107
|
+
"Framework-neutral rendering\nLocal files. Explicit compatibility notes.",
|
|
108
|
+
1.55,
|
|
109
|
+
1.5,
|
|
110
|
+
5.4,
|
|
111
|
+
1,
|
|
112
|
+
"#ffffff"
|
|
113
|
+
)
|
|
114
|
+
]
|
|
115
|
+
}
|
|
116
|
+
]
|
|
117
|
+
};
|
|
118
|
+
|
|
119
|
+
// src/visio/ui/diagnostics.ts
|
|
120
|
+
function compatibilityNotes(diagnostics, renderWarnings = []) {
|
|
121
|
+
const notes = /* @__PURE__ */ new Map();
|
|
122
|
+
for (const diagnostic of diagnostics) {
|
|
123
|
+
const existing = notes.get(diagnostic.message);
|
|
124
|
+
if (existing) {
|
|
125
|
+
existing.count++;
|
|
126
|
+
if (diagnostic.severity === "warning") existing.severity = "warning";
|
|
127
|
+
} else
|
|
128
|
+
notes.set(diagnostic.message, {
|
|
129
|
+
message: diagnostic.message,
|
|
130
|
+
count: 1,
|
|
131
|
+
severity: diagnostic.severity
|
|
132
|
+
});
|
|
133
|
+
}
|
|
134
|
+
for (const message of renderWarnings) {
|
|
135
|
+
const existing = notes.get(message);
|
|
136
|
+
if (existing) {
|
|
137
|
+
existing.count++;
|
|
138
|
+
existing.severity = "warning";
|
|
139
|
+
} else notes.set(message, { message, count: 1, severity: "warning" });
|
|
140
|
+
}
|
|
141
|
+
return [...notes.values()].sort(
|
|
142
|
+
(a, b) => Number(a.severity === "info") - Number(b.severity === "info")
|
|
143
|
+
);
|
|
144
|
+
}
|
|
145
|
+
function compatibilityText(note) {
|
|
146
|
+
return note.message + (note.count > 1 ? ` (${note.count} occurrences)` : "");
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
// src/visio/ui/document-history.ts
|
|
150
|
+
var EMPTY_EDIT_STATE = Object.freeze({
|
|
151
|
+
sourceAvailable: false,
|
|
152
|
+
busy: false,
|
|
153
|
+
dirty: false,
|
|
154
|
+
canUndo: false,
|
|
155
|
+
canRedo: false,
|
|
156
|
+
historyTruncated: false,
|
|
157
|
+
error: null,
|
|
158
|
+
diagnostics: Object.freeze([])
|
|
159
|
+
});
|
|
160
|
+
var EDIT_HISTORY_LIMITS = Object.freeze({ maxBytes: 96 * 1024 * 1024, maxEntries: 20 });
|
|
161
|
+
var DocumentHistory = class {
|
|
162
|
+
original;
|
|
163
|
+
#entries;
|
|
164
|
+
#index = 0;
|
|
165
|
+
#truncated = false;
|
|
166
|
+
constructor(bytes) {
|
|
167
|
+
this.original = { bytes: Uint8Array.from(bytes), diagnostics: Object.freeze([]) };
|
|
168
|
+
this.#entries = [this.original];
|
|
169
|
+
}
|
|
170
|
+
get current() {
|
|
171
|
+
return this.#entries[this.#index];
|
|
172
|
+
}
|
|
173
|
+
get undoTarget() {
|
|
174
|
+
return this.#entries[this.#index - 1];
|
|
175
|
+
}
|
|
176
|
+
get redoTarget() {
|
|
177
|
+
return this.#entries[this.#index + 1];
|
|
178
|
+
}
|
|
179
|
+
get state() {
|
|
180
|
+
return Object.freeze({
|
|
181
|
+
...EMPTY_EDIT_STATE,
|
|
182
|
+
sourceAvailable: true,
|
|
183
|
+
dirty: this.current !== this.original,
|
|
184
|
+
canUndo: !!this.undoTarget,
|
|
185
|
+
canRedo: !!this.redoTarget,
|
|
186
|
+
historyTruncated: this.#truncated,
|
|
187
|
+
diagnostics: this.current.diagnostics
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
append(bytes, diagnostics) {
|
|
191
|
+
const snapshot = {
|
|
192
|
+
bytes: Uint8Array.from(bytes),
|
|
193
|
+
diagnostics: Object.freeze(
|
|
194
|
+
diagnostics.map((note) => Object.freeze({ code: note.code, message: note.message }))
|
|
195
|
+
)
|
|
196
|
+
};
|
|
197
|
+
this.#entries = this.#entries.slice(0, this.#index + 1);
|
|
198
|
+
this.#entries.push(snapshot);
|
|
199
|
+
this.#index++;
|
|
200
|
+
const retained = () => /* @__PURE__ */ new Set([this.original, ...this.#entries]);
|
|
201
|
+
while (this.#entries.length > EDIT_HISTORY_LIMITS.maxEntries || [...retained()].reduce((sum, entry) => sum + entry.bytes.byteLength, 0) > EDIT_HISTORY_LIMITS.maxBytes) {
|
|
202
|
+
if (this.#index === 0) throw new Error("Source snapshots exceed the retained history limit.");
|
|
203
|
+
this.#entries.shift();
|
|
204
|
+
this.#index--;
|
|
205
|
+
this.#truncated = true;
|
|
206
|
+
}
|
|
207
|
+
}
|
|
208
|
+
move(target) {
|
|
209
|
+
const index = this.#entries.indexOf(target);
|
|
210
|
+
if (index < 0 || Math.abs(index - this.#index) !== 1)
|
|
211
|
+
throw new Error("The history target is stale.");
|
|
212
|
+
this.#index = index;
|
|
213
|
+
}
|
|
214
|
+
export() {
|
|
215
|
+
return {
|
|
216
|
+
bytes: Uint8Array.from(this.current.bytes),
|
|
217
|
+
dirty: this.current !== this.original,
|
|
218
|
+
diagnostics: this.current.diagnostics
|
|
219
|
+
};
|
|
220
|
+
}
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
// src/visio/ui/document-text-search.ts
|
|
224
|
+
var TEXT_SEARCH_LIMITS = Object.freeze({
|
|
225
|
+
queryCharacters: 256,
|
|
226
|
+
results: 500,
|
|
227
|
+
indexedCharacters: 2e6,
|
|
228
|
+
shapeCharacters: 32768,
|
|
229
|
+
previewCharacters: 160,
|
|
230
|
+
shapes: 25e3,
|
|
231
|
+
depth: 64
|
|
232
|
+
});
|
|
233
|
+
var EMPTY_TEXT_SEARCH = Object.freeze({
|
|
234
|
+
query: "",
|
|
235
|
+
results: Object.freeze([]),
|
|
236
|
+
activeIndex: -1,
|
|
237
|
+
indexTruncated: false,
|
|
238
|
+
resultsTruncated: false
|
|
239
|
+
});
|
|
240
|
+
function indexDocumentText(model, isVisible = (shape) => !shape.hidden) {
|
|
241
|
+
const entries = [];
|
|
242
|
+
const seen = /* @__PURE__ */ new Set();
|
|
243
|
+
let characters = 0, truncated = false;
|
|
244
|
+
for (const [pageIndex, page] of (model?.pages ?? []).entries()) {
|
|
245
|
+
const stack = page.shapes.map((shape) => ({ shape, depth: 0 })).reverse();
|
|
246
|
+
while (stack.length) {
|
|
247
|
+
const { shape, depth } = stack.pop();
|
|
248
|
+
if (seen.has(shape) || depth > TEXT_SEARCH_LIMITS.depth) {
|
|
249
|
+
truncated = true;
|
|
250
|
+
continue;
|
|
251
|
+
}
|
|
252
|
+
if (seen.size >= TEXT_SEARCH_LIMITS.shapes)
|
|
253
|
+
return Object.freeze({ entries: Object.freeze(entries), truncated: true });
|
|
254
|
+
seen.add(shape);
|
|
255
|
+
if (!isVisible(shape)) continue;
|
|
256
|
+
if (!(shape.kind === "group" && shape.groupDisplayMode === 0)) {
|
|
257
|
+
const source = shape.text.plainText;
|
|
258
|
+
const length = Math.min(
|
|
259
|
+
source.length,
|
|
260
|
+
TEXT_SEARCH_LIMITS.shapeCharacters,
|
|
261
|
+
TEXT_SEARCH_LIMITS.indexedCharacters - characters
|
|
262
|
+
);
|
|
263
|
+
if (length < source.length) truncated = true;
|
|
264
|
+
if (length) {
|
|
265
|
+
characters += length;
|
|
266
|
+
const text = source.slice(0, length);
|
|
267
|
+
const preview = text.slice(0, TEXT_SEARCH_LIMITS.previewCharacters) + (source.length > TEXT_SEARCH_LIMITS.previewCharacters ? "\u2026" : "");
|
|
268
|
+
entries.push(
|
|
269
|
+
Object.freeze({
|
|
270
|
+
foldedText: text.toLowerCase(),
|
|
271
|
+
result: Object.freeze({
|
|
272
|
+
pageIndex,
|
|
273
|
+
pageId: page.id,
|
|
274
|
+
pageName: page.name,
|
|
275
|
+
shapeId: shape.id,
|
|
276
|
+
shapeName: shape.name,
|
|
277
|
+
preview
|
|
278
|
+
})
|
|
279
|
+
})
|
|
280
|
+
);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
for (let i = shape.children.length - 1; i >= 0; i--)
|
|
284
|
+
stack.push({ shape: shape.children[i], depth: depth + 1 });
|
|
285
|
+
}
|
|
286
|
+
}
|
|
287
|
+
return Object.freeze({ entries: Object.freeze(entries), truncated });
|
|
288
|
+
}
|
|
289
|
+
function validateSearchQuery(query) {
|
|
290
|
+
if (typeof query !== "string" || query.length > TEXT_SEARCH_LIMITS.queryCharacters)
|
|
291
|
+
throw new Error(
|
|
292
|
+
`Search queries must be strings of at most ${TEXT_SEARCH_LIMITS.queryCharacters} characters.`
|
|
293
|
+
);
|
|
294
|
+
}
|
|
295
|
+
function searchDocumentText(index, query) {
|
|
296
|
+
validateSearchQuery(query);
|
|
297
|
+
const results = [];
|
|
298
|
+
let resultsTruncated = false;
|
|
299
|
+
if (query.trim()) {
|
|
300
|
+
const folded = query.toLowerCase();
|
|
301
|
+
for (const entry of index.entries) {
|
|
302
|
+
if (!entry.foldedText.includes(folded)) continue;
|
|
303
|
+
if (results.length === TEXT_SEARCH_LIMITS.results) {
|
|
304
|
+
resultsTruncated = true;
|
|
305
|
+
break;
|
|
306
|
+
}
|
|
307
|
+
results.push(entry.result);
|
|
308
|
+
}
|
|
309
|
+
}
|
|
310
|
+
return Object.freeze({
|
|
311
|
+
query,
|
|
312
|
+
results: Object.freeze(results),
|
|
313
|
+
activeIndex: -1,
|
|
314
|
+
indexTruncated: index.truncated,
|
|
315
|
+
resultsTruncated
|
|
316
|
+
});
|
|
317
|
+
}
|
|
318
|
+
function textSearchStatus(search) {
|
|
319
|
+
if (!search.query.trim()) return "Find text across pages";
|
|
320
|
+
const count = search.results.length;
|
|
321
|
+
const result = search.activeIndex < 0 ? `${count}${search.resultsTruncated ? "+" : ""} matching shapes` : `${search.activeIndex + 1} of ${count}${search.resultsTruncated ? "+" : ""} matching shapes`;
|
|
322
|
+
return result + (search.indexTruncated ? " \xB7 Partial text index" : "");
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
// src/visio/ui/edit-commands.ts
|
|
326
|
+
function snapshotEdits(edits) {
|
|
327
|
+
if (!Array.isArray(edits) || edits.length > 1e3)
|
|
328
|
+
throw new Error("At most 1000 edits are accepted per operation.");
|
|
329
|
+
let characters = 0;
|
|
330
|
+
return edits.map((command) => {
|
|
331
|
+
if (!command || typeof command.pageId !== "string" || !command.pageId || command.pageId.length > 256 || typeof command.shapeId !== "string" || !command.shapeId || command.shapeId.length > 256)
|
|
332
|
+
throw new Error("Invalid edit command.");
|
|
333
|
+
const target = { pageId: command.pageId, shapeId: command.shapeId };
|
|
334
|
+
const text = (value) => {
|
|
335
|
+
if (typeof value !== "string") throw new Error("Invalid edit text.");
|
|
336
|
+
characters += value.length;
|
|
337
|
+
if (characters > 1e6)
|
|
338
|
+
throw new Error("Edit text exceeds the one-million-character limit.");
|
|
339
|
+
return value;
|
|
340
|
+
};
|
|
341
|
+
const numbers = (...values) => {
|
|
342
|
+
if (values.some((value) => typeof value !== "number" || !Number.isFinite(value)))
|
|
343
|
+
throw new Error("Invalid geometry edit coordinates or dimensions.");
|
|
344
|
+
};
|
|
345
|
+
switch (command.type) {
|
|
346
|
+
case "replace-plain-text":
|
|
347
|
+
return { type: command.type, ...target, text: text(command.text) };
|
|
348
|
+
case "delete-shape":
|
|
349
|
+
return { type: command.type, ...target };
|
|
350
|
+
case "move-shape":
|
|
351
|
+
numbers(command.x, command.y);
|
|
352
|
+
return { type: command.type, ...target, x: command.x, y: command.y };
|
|
353
|
+
case "resize-shape":
|
|
354
|
+
numbers(command.width, command.height);
|
|
355
|
+
return { type: command.type, ...target, width: command.width, height: command.height };
|
|
356
|
+
case "create-rectangle":
|
|
357
|
+
numbers(command.x, command.y, command.width, command.height);
|
|
358
|
+
return {
|
|
359
|
+
type: command.type,
|
|
360
|
+
...target,
|
|
361
|
+
x: command.x,
|
|
362
|
+
y: command.y,
|
|
363
|
+
width: command.width,
|
|
364
|
+
height: command.height,
|
|
365
|
+
...command.text === void 0 ? {} : { text: text(command.text) }
|
|
366
|
+
};
|
|
367
|
+
default:
|
|
368
|
+
throw new Error("Invalid edit command type.");
|
|
369
|
+
}
|
|
370
|
+
});
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
// src/visio/ui/edit-error.ts
|
|
374
|
+
function editErrorMessage(error) {
|
|
375
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
376
|
+
const code = error && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code.slice(0, 256) : void 0;
|
|
377
|
+
return code ? `${code}: ${message}` : message;
|
|
378
|
+
}
|
|
379
|
+
function isEditCancellation(error) {
|
|
380
|
+
return !!error && typeof error === "object" && "name" in error && error.name === "AbortError";
|
|
381
|
+
}
|
|
382
|
+
new TextDecoder("utf-8", { fatal: true });
|
|
383
|
+
var crcTable = Uint32Array.from({ length: 256 }, (_, value) => {
|
|
384
|
+
for (let i = 0; i < 8; i++) value = value & 1 ? 3988292384 ^ value >>> 1 : value >>> 1;
|
|
385
|
+
return value >>> 0;
|
|
386
|
+
});
|
|
387
|
+
function crc32(bytes, crc = 4294967295) {
|
|
388
|
+
for (const byte of bytes) crc = (crcTable[(crc ^ byte) & 255] ?? 0) ^ crc >>> 8;
|
|
389
|
+
return crc >>> 0;
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
// src/visio/foreign-vector-types.ts
|
|
393
|
+
var VISIO_FOREIGN_VECTOR_LIMITS = Object.freeze({
|
|
394
|
+
maxNodes: 25e3,
|
|
395
|
+
maxCharacters: 2 * 1024 * 1024,
|
|
396
|
+
maxPathOperands: 1e5,
|
|
397
|
+
maxPathCommands: 5e4,
|
|
398
|
+
maxDepth: 64,
|
|
399
|
+
maxDimension: 2048,
|
|
400
|
+
maxCoordinate: 1e6,
|
|
401
|
+
maxExpandedNodes: 25e3,
|
|
402
|
+
maxExpandedOperands: 1e5,
|
|
403
|
+
maxExpandedCommands: 5e4
|
|
404
|
+
});
|
|
405
|
+
var VisioForeignVectorError = class extends Error {
|
|
406
|
+
constructor(code, message) {
|
|
407
|
+
super(message);
|
|
408
|
+
this.code = code;
|
|
409
|
+
}
|
|
410
|
+
code;
|
|
411
|
+
name = "VisioForeignVectorError";
|
|
412
|
+
};
|
|
413
|
+
function unsafe(message) {
|
|
414
|
+
throw new VisioForeignVectorError("unsafe-vector", message);
|
|
415
|
+
}
|
|
416
|
+
function limit(message) {
|
|
417
|
+
throw new VisioForeignVectorError("vector-limit", message);
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// src/visio/foreign-vector-values.ts
|
|
421
|
+
var IDENTITY = Object.freeze([1, 0, 0, 1, 0, 0]);
|
|
422
|
+
var NUMBER = /^[+-]?(?:\d+(?:\.\d*)?|\.\d+)(?:[eE][+-]?\d+)?$/;
|
|
423
|
+
function record(value, allowed) {
|
|
424
|
+
if (!value || typeof value !== "object" || Array.isArray(value))
|
|
425
|
+
unsafe("Expected a plain object.");
|
|
426
|
+
const prototype = Object.getPrototypeOf(value);
|
|
427
|
+
if (prototype !== Object.prototype && prototype !== null) unsafe("Unexpected object prototype.");
|
|
428
|
+
const result = /* @__PURE__ */ Object.create(null);
|
|
429
|
+
const keys = Reflect.ownKeys(value);
|
|
430
|
+
if (keys.length > allowed.length) unsafe("Unexpected object fields.");
|
|
431
|
+
for (const key of keys) {
|
|
432
|
+
if (typeof key !== "string" || !allowed.includes(key)) unsafe("Unexpected object field.");
|
|
433
|
+
const descriptor = Object.getOwnPropertyDescriptor(value, key);
|
|
434
|
+
if (!descriptor || !("value" in descriptor) || !descriptor.enumerable)
|
|
435
|
+
unsafe("Invalid data property.");
|
|
436
|
+
result[key] = descriptor.value;
|
|
437
|
+
}
|
|
438
|
+
return result;
|
|
439
|
+
}
|
|
440
|
+
function limitsFor(options) {
|
|
441
|
+
const result = { ...VISIO_FOREIGN_VECTOR_LIMITS };
|
|
442
|
+
const values = record(options, Object.keys(result));
|
|
443
|
+
for (const key of Object.keys(values)) {
|
|
444
|
+
const value = values[key];
|
|
445
|
+
if (typeof value !== "number" || !Number.isSafeInteger(value) || value < 1 || value > result[key])
|
|
446
|
+
unsafe("Limits must be positive integers no greater than the defaults.");
|
|
447
|
+
result[key] = value;
|
|
448
|
+
}
|
|
449
|
+
return result;
|
|
450
|
+
}
|
|
451
|
+
function finite(value, maximum) {
|
|
452
|
+
if (typeof value !== "number" || !Number.isFinite(value)) unsafe("Expected a finite number.");
|
|
453
|
+
if (Math.abs(value) > maximum) limit("Numeric magnitude limit exceeded.");
|
|
454
|
+
return value;
|
|
455
|
+
}
|
|
456
|
+
function scalar(value, maximum, minimum = 0) {
|
|
457
|
+
if (typeof value === "string") {
|
|
458
|
+
if (!NUMBER.test(value)) unsafe("Invalid numeric attribute.");
|
|
459
|
+
value = Number(value);
|
|
460
|
+
}
|
|
461
|
+
const n = finite(value, maximum);
|
|
462
|
+
if (n < minimum) unsafe("Numeric attribute below its minimum.");
|
|
463
|
+
return n;
|
|
464
|
+
}
|
|
465
|
+
function compose(a, b, max) {
|
|
466
|
+
const result = [
|
|
467
|
+
a[0] * b[0] + a[2] * b[1],
|
|
468
|
+
a[1] * b[0] + a[3] * b[1],
|
|
469
|
+
a[0] * b[2] + a[2] * b[3],
|
|
470
|
+
a[1] * b[2] + a[3] * b[3],
|
|
471
|
+
a[0] * b[4] + a[2] * b[5] + a[4],
|
|
472
|
+
a[1] * b[4] + a[3] * b[5] + a[5]
|
|
473
|
+
];
|
|
474
|
+
for (const value of result) finite(value, max);
|
|
475
|
+
return result;
|
|
476
|
+
}
|
|
477
|
+
function rule(value) {
|
|
478
|
+
if (value === void 0) return "nonzero";
|
|
479
|
+
if (value !== "nonzero" && value !== "evenodd") unsafe("Unsupported winding rule.");
|
|
480
|
+
return value;
|
|
481
|
+
}
|
|
482
|
+
function literal(value, fallback) {
|
|
483
|
+
if (value === void 0) return fallback;
|
|
484
|
+
if (typeof value !== "string" || !/^(?:none|#[0-9a-fA-F]{6})$/.test(value))
|
|
485
|
+
unsafe("Nonliteral paint.");
|
|
486
|
+
return value.toLowerCase();
|
|
487
|
+
}
|
|
488
|
+
function choice(value, choices, fallback) {
|
|
489
|
+
if (value === void 0) return fallback;
|
|
490
|
+
if (typeof value !== "string" || !choices.includes(value))
|
|
491
|
+
unsafe("Unsupported paint value.");
|
|
492
|
+
return value;
|
|
493
|
+
}
|
|
494
|
+
function paint(attrs) {
|
|
495
|
+
return Object.freeze({
|
|
496
|
+
fill: literal(attrs.fill, "#000000"),
|
|
497
|
+
stroke: literal(attrs.stroke, "none"),
|
|
498
|
+
fillRule: rule(attrs["fill-rule"]),
|
|
499
|
+
strokeWidth: scalar(attrs["stroke-width"] === void 0 ? 1 : attrs["stroke-width"], 1024),
|
|
500
|
+
strokeMiterlimit: scalar(
|
|
501
|
+
attrs["stroke-miterlimit"] === void 0 ? 4 : attrs["stroke-miterlimit"],
|
|
502
|
+
1024,
|
|
503
|
+
1
|
|
504
|
+
),
|
|
505
|
+
strokeLinecap: choice(attrs["stroke-linecap"], ["butt", "round", "square"], "butt"),
|
|
506
|
+
strokeLinejoin: choice(attrs["stroke-linejoin"], ["miter", "round", "bevel"], "miter"),
|
|
507
|
+
opacity: scalar(attrs.opacity === void 0 ? 1 : attrs.opacity, 1),
|
|
508
|
+
fillOpacity: scalar(attrs["fill-opacity"] === void 0 ? 1 : attrs["fill-opacity"], 1),
|
|
509
|
+
strokeOpacity: scalar(attrs["stroke-opacity"] === void 0 ? 1 : attrs["stroke-opacity"], 1)
|
|
510
|
+
});
|
|
511
|
+
}
|
|
512
|
+
|
|
513
|
+
// src/visio/foreign-vector-path.ts
|
|
514
|
+
function checkPathBounds(commands, matrix2, max) {
|
|
515
|
+
const point = (x2, y2) => {
|
|
516
|
+
finite(x2, max);
|
|
517
|
+
finite(y2, max);
|
|
518
|
+
finite(matrix2[0] * x2 + matrix2[2] * y2 + matrix2[4], max);
|
|
519
|
+
finite(matrix2[1] * x2 + matrix2[3] * y2 + matrix2[5], max);
|
|
520
|
+
};
|
|
521
|
+
let x = 0, y = 0, startX = 0, startY = 0;
|
|
522
|
+
for (const { command, values: v } of commands) {
|
|
523
|
+
if (command === "Z") {
|
|
524
|
+
x = startX;
|
|
525
|
+
y = startY;
|
|
526
|
+
continue;
|
|
527
|
+
}
|
|
528
|
+
if (command === "A") {
|
|
529
|
+
const endX = v[5], endY = v[6];
|
|
530
|
+
point(endX, endY);
|
|
531
|
+
if (v[0] !== 0 && v[1] !== 0 && (x !== endX || y !== endY)) {
|
|
532
|
+
const angle = v[2] % 360 * Math.PI / 180, c = Math.cos(angle), s = Math.sin(angle);
|
|
533
|
+
const dx = (x - endX) / 2, dy = (y - endY) / 2;
|
|
534
|
+
const scale = Math.max(
|
|
535
|
+
1,
|
|
536
|
+
Math.hypot((c * dx + s * dy) / v[0], (-s * dx + c * dy) / v[1])
|
|
537
|
+
);
|
|
538
|
+
const rx = finite(v[0] * scale, max), ry = finite(v[1] * scale, max);
|
|
539
|
+
const bx = 2 * (Math.abs(c) * rx + Math.abs(s) * ry);
|
|
540
|
+
const by = 2 * (Math.abs(s) * rx + Math.abs(c) * ry);
|
|
541
|
+
for (const signX of [-1, 1])
|
|
542
|
+
for (const signY of [-1, 1]) point(x + signX * bx, y + signY * by);
|
|
543
|
+
}
|
|
544
|
+
x = endX;
|
|
545
|
+
y = endY;
|
|
546
|
+
} else {
|
|
547
|
+
for (let i = 0; i < v.length; i += 2) point(v[i], v[i + 1]);
|
|
548
|
+
x = v[v.length - 2];
|
|
549
|
+
y = v[v.length - 1];
|
|
550
|
+
if (command === "M") {
|
|
551
|
+
startX = x;
|
|
552
|
+
startY = y;
|
|
553
|
+
}
|
|
554
|
+
}
|
|
555
|
+
}
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
// src/visio/foreign-vector-graph.ts
|
|
559
|
+
function checkVectorGraph(scene, limits) {
|
|
560
|
+
let characters = scene.kind.length;
|
|
561
|
+
function strings(target) {
|
|
562
|
+
if ("kind" in target) characters += target.kind.length;
|
|
563
|
+
if ("commands" in target) {
|
|
564
|
+
characters += target.commands.length;
|
|
565
|
+
if ("clipRule" in target) characters += target.clipRule.length;
|
|
566
|
+
if ("paint" in target) {
|
|
567
|
+
const p = target.paint;
|
|
568
|
+
characters += p.fill.length + p.stroke.length + p.fillRule.length + p.strokeLinecap.length + p.strokeLinejoin.length;
|
|
569
|
+
}
|
|
570
|
+
} else for (const child of target.items) strings(child);
|
|
571
|
+
if (characters > limits.maxCharacters) limit("Retained vector character limit exceeded.");
|
|
572
|
+
}
|
|
573
|
+
for (const clip of scene.clips) strings(clip);
|
|
574
|
+
for (const item of scene.items) strings(item);
|
|
575
|
+
const active = /* @__PURE__ */ new Set(), done = /* @__PURE__ */ new Set();
|
|
576
|
+
const depths = /* @__PURE__ */ new Map();
|
|
577
|
+
function checkClip(index, depth) {
|
|
578
|
+
if (depth > limits.maxDepth) limit("Clip graph depth limit exceeded.");
|
|
579
|
+
if (active.has(index)) unsafe("Cyclic clip reference.");
|
|
580
|
+
if (done.has(index)) return depths.get(index);
|
|
581
|
+
active.add(index);
|
|
582
|
+
const clip = scene.clips[index];
|
|
583
|
+
let height = 1;
|
|
584
|
+
for (const target of [clip, ...clip.items]) {
|
|
585
|
+
if (target.clipIndex !== void 0)
|
|
586
|
+
height = Math.max(height, 1 + checkClip(target.clipIndex, depth + 1));
|
|
587
|
+
}
|
|
588
|
+
if (height > limits.maxDepth) limit("Clip graph depth limit exceeded.");
|
|
589
|
+
active.delete(index);
|
|
590
|
+
done.add(index);
|
|
591
|
+
depths.set(index, height);
|
|
592
|
+
return height;
|
|
593
|
+
}
|
|
594
|
+
for (let i = 0; i < scene.clips.length; i++) checkClip(i, 1);
|
|
595
|
+
let expandedNodes = 0, expandedOperands = 0, expandedCommands = 0;
|
|
596
|
+
function charge(depth) {
|
|
597
|
+
if (depth > limits.maxDepth) limit("Expanded vector depth limit exceeded.");
|
|
598
|
+
if (++expandedNodes > limits.maxExpandedNodes) limit("Expanded vector node limit exceeded.");
|
|
599
|
+
}
|
|
600
|
+
function content(target, parent, depth) {
|
|
601
|
+
charge(depth);
|
|
602
|
+
const matrix2 = compose(parent, target.matrix, limits.maxCoordinate);
|
|
603
|
+
if ("commands" in target) {
|
|
604
|
+
expandedCommands += target.commands.length;
|
|
605
|
+
if (expandedCommands > limits.maxExpandedCommands)
|
|
606
|
+
limit("Expanded path command limit exceeded.");
|
|
607
|
+
for (const command of target.commands) expandedOperands += command.values.length;
|
|
608
|
+
if (expandedOperands > limits.maxExpandedOperands)
|
|
609
|
+
limit("Expanded path operand limit exceeded.");
|
|
610
|
+
checkPathBounds(target.commands, matrix2, limits.maxCoordinate);
|
|
611
|
+
if ("paint" in target && target.paint.stroke !== "none") {
|
|
612
|
+
const extent = target.paint.strokeWidth * target.paint.strokeMiterlimit;
|
|
613
|
+
finite(extent * (Math.abs(matrix2[0]) + Math.abs(matrix2[2])), limits.maxCoordinate);
|
|
614
|
+
finite(extent * (Math.abs(matrix2[1]) + Math.abs(matrix2[3])), limits.maxCoordinate);
|
|
615
|
+
}
|
|
616
|
+
} else for (const child of target.items) content(child, matrix2, depth + 1);
|
|
617
|
+
if (target.clipIndex !== void 0) content(scene.clips[target.clipIndex], matrix2, depth + 1);
|
|
618
|
+
}
|
|
619
|
+
for (const clip of scene.clips) content(clip, IDENTITY, 1);
|
|
620
|
+
for (const item of scene.items) content(item, IDENTITY, 1);
|
|
621
|
+
}
|
|
622
|
+
|
|
623
|
+
// src/visio/foreign-vector-validation.ts
|
|
624
|
+
var ARITY = { M: 2, L: 2, C: 6, Q: 4, A: 7, Z: 0 };
|
|
625
|
+
var PAINT = {
|
|
626
|
+
fill: "fill",
|
|
627
|
+
stroke: "stroke",
|
|
628
|
+
fillRule: "fill-rule",
|
|
629
|
+
strokeWidth: "stroke-width",
|
|
630
|
+
strokeMiterlimit: "stroke-miterlimit",
|
|
631
|
+
strokeLinecap: "stroke-linecap",
|
|
632
|
+
strokeLinejoin: "stroke-linejoin",
|
|
633
|
+
opacity: "opacity",
|
|
634
|
+
fillOpacity: "fill-opacity",
|
|
635
|
+
strokeOpacity: "stroke-opacity"
|
|
636
|
+
};
|
|
637
|
+
function validateVisioForeignVector(value, options = {}) {
|
|
638
|
+
try {
|
|
639
|
+
return validate(value, limitsFor(options));
|
|
640
|
+
} catch (error) {
|
|
641
|
+
if (error instanceof VisioForeignVectorError) throw error;
|
|
642
|
+
unsafe("Unable to inspect vector scene safely.");
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
function validate(value, limits) {
|
|
646
|
+
let nodes = 0, operands = 0, commands = 0, characters = 0, clipCount = 0;
|
|
647
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
648
|
+
function own(input, fields2, depth) {
|
|
649
|
+
if (depth > limits.maxDepth) limit("Scene depth limit exceeded.");
|
|
650
|
+
if (++nodes > limits.maxNodes) limit("Scene node limit exceeded.");
|
|
651
|
+
if (!input || typeof input !== "object" || seen.has(input))
|
|
652
|
+
unsafe("Repeated or cyclic scene object.");
|
|
653
|
+
seen.add(input);
|
|
654
|
+
return data(input, fields2);
|
|
655
|
+
}
|
|
656
|
+
function data(input, fields2) {
|
|
657
|
+
const output = record(input, fields2);
|
|
658
|
+
for (const value2 of Object.values(output)) {
|
|
659
|
+
characters += typeof value2 === "string" ? value2.length : 0;
|
|
660
|
+
if (characters > limits.maxCharacters) limit("Scene character limit exceeded.");
|
|
661
|
+
}
|
|
662
|
+
return output;
|
|
663
|
+
}
|
|
664
|
+
function array(input, maximum) {
|
|
665
|
+
if (!Array.isArray(input) || Object.getPrototypeOf(input) !== Array.prototype)
|
|
666
|
+
unsafe("Expected plain scene array.");
|
|
667
|
+
if (input.length > maximum) limit("Scene array limit exceeded.");
|
|
668
|
+
if (Reflect.ownKeys(input).length !== input.length + 1)
|
|
669
|
+
unsafe("Sparse or extended scene array.");
|
|
670
|
+
const output = [];
|
|
671
|
+
for (let i = 0; i < input.length; i++) {
|
|
672
|
+
const item2 = Object.getOwnPropertyDescriptor(input, i);
|
|
673
|
+
if (!item2 || !("value" in item2) || !item2.enumerable)
|
|
674
|
+
unsafe("Sparse or accessor scene array.");
|
|
675
|
+
output.push(item2.value);
|
|
676
|
+
}
|
|
677
|
+
return output;
|
|
678
|
+
}
|
|
679
|
+
function base(input) {
|
|
680
|
+
const values = array(input.matrix, 6);
|
|
681
|
+
if (values.length !== 6) unsafe("Invalid matrix arity.");
|
|
682
|
+
const matrix2 = Object.freeze(
|
|
683
|
+
values.map((item2) => finite(item2, limits.maxCoordinate))
|
|
684
|
+
);
|
|
685
|
+
if (input.clipIndex === void 0) return { matrix: matrix2 };
|
|
686
|
+
if (typeof input.clipIndex !== "number" || !Number.isSafeInteger(input.clipIndex) || input.clipIndex < 0 || input.clipIndex >= clipCount)
|
|
687
|
+
unsafe("Invalid clip index.");
|
|
688
|
+
return { matrix: matrix2, clipIndex: input.clipIndex };
|
|
689
|
+
}
|
|
690
|
+
function path(input) {
|
|
691
|
+
const values = array(input, limits.maxPathCommands - commands);
|
|
692
|
+
const result = [];
|
|
693
|
+
for (const value2 of values) {
|
|
694
|
+
const command = data(value2, ["command", "values"]);
|
|
695
|
+
if (typeof command.command !== "string" || !Object.hasOwn(ARITY, command.command))
|
|
696
|
+
unsafe("Invalid normalized command.");
|
|
697
|
+
if (!result.length && command.command !== "M") unsafe("Path must begin with moveto.");
|
|
698
|
+
const count = ARITY[command.command];
|
|
699
|
+
const numbers = array(command.values, count);
|
|
700
|
+
if (numbers.length !== count) unsafe("Invalid normalized command arity.");
|
|
701
|
+
if ((operands += count) > limits.maxPathOperands) limit("Scene operand limit exceeded.");
|
|
702
|
+
commands++;
|
|
703
|
+
const copied = numbers.map((item2) => finite(item2, limits.maxCoordinate));
|
|
704
|
+
if (command.command === "A" && (copied[0] < 0 || copied[1] < 0 || ![0, 1].includes(copied[3]) || ![0, 1].includes(copied[4])))
|
|
705
|
+
unsafe("Invalid normalized arc.");
|
|
706
|
+
result.push(
|
|
707
|
+
Object.freeze({
|
|
708
|
+
command: command.command,
|
|
709
|
+
values: Object.freeze(copied)
|
|
710
|
+
})
|
|
711
|
+
);
|
|
712
|
+
}
|
|
713
|
+
return Object.freeze(result);
|
|
714
|
+
}
|
|
715
|
+
function literalPaint(input) {
|
|
716
|
+
const fields2 = Object.keys(PAINT);
|
|
717
|
+
const value2 = data(input, fields2);
|
|
718
|
+
if (Object.keys(value2).length !== fields2.length) unsafe("Missing normalized paint field.");
|
|
719
|
+
const attrs = /* @__PURE__ */ Object.create(null);
|
|
720
|
+
for (const field of fields2) {
|
|
721
|
+
if (value2[field] === void 0) unsafe("Missing normalized paint value.");
|
|
722
|
+
if (["strokeWidth", "strokeMiterlimit", "opacity", "fillOpacity", "strokeOpacity"].includes(
|
|
723
|
+
field
|
|
724
|
+
) && typeof value2[field] !== "number")
|
|
725
|
+
unsafe("Normalized paint must be numeric.");
|
|
726
|
+
attrs[PAINT[field]] = value2[field];
|
|
727
|
+
}
|
|
728
|
+
return paint(attrs);
|
|
729
|
+
}
|
|
730
|
+
function item(input, depth) {
|
|
731
|
+
const node = own(input, ["kind", "matrix", "clipIndex", "items", "commands", "paint"], depth);
|
|
732
|
+
if (node.kind === "path") {
|
|
733
|
+
if (Object.hasOwn(node, "items")) unsafe("Path contains group fields.");
|
|
734
|
+
return Object.freeze({
|
|
735
|
+
kind: "path",
|
|
736
|
+
...base(node),
|
|
737
|
+
commands: path(node.commands),
|
|
738
|
+
paint: literalPaint(node.paint)
|
|
739
|
+
});
|
|
740
|
+
}
|
|
741
|
+
if (node.kind !== "group" || Object.hasOwn(node, "commands") || Object.hasOwn(node, "paint"))
|
|
742
|
+
unsafe("Invalid normalized group.");
|
|
743
|
+
return Object.freeze({
|
|
744
|
+
kind: "group",
|
|
745
|
+
...base(node),
|
|
746
|
+
items: Object.freeze(
|
|
747
|
+
array(node.items, limits.maxNodes - nodes).map((child) => item(child, depth + 1))
|
|
748
|
+
)
|
|
749
|
+
});
|
|
750
|
+
}
|
|
751
|
+
function clip(input, depth) {
|
|
752
|
+
const node = own(input, ["matrix", "clipIndex", "items"], depth);
|
|
753
|
+
const items2 = [];
|
|
754
|
+
for (const value2 of array(node.items, limits.maxNodes - nodes)) {
|
|
755
|
+
const child = own(value2, ["matrix", "clipIndex", "commands", "clipRule"], depth + 1);
|
|
756
|
+
if (child.clipRule !== "nonzero" && child.clipRule !== "evenodd")
|
|
757
|
+
unsafe("Invalid normalized clip rule.");
|
|
758
|
+
items2.push(
|
|
759
|
+
Object.freeze({ ...base(child), commands: path(child.commands), clipRule: child.clipRule })
|
|
760
|
+
);
|
|
761
|
+
}
|
|
762
|
+
return Object.freeze({ ...base(node), items: Object.freeze(items2) });
|
|
763
|
+
}
|
|
764
|
+
const root = own(value, ["kind", "width", "height", "items", "clips"], 0);
|
|
765
|
+
if (root.kind !== "vector") unsafe("Invalid normalized vector.");
|
|
766
|
+
const width = finite(root.width, limits.maxDimension), height = finite(root.height, limits.maxDimension);
|
|
767
|
+
if (width < 1 || height < 1) unsafe("Empty normalized dimensions.");
|
|
768
|
+
const definitions = array(root.clips, limits.maxNodes - nodes);
|
|
769
|
+
clipCount = definitions.length;
|
|
770
|
+
const clips = Object.freeze(definitions.map((value2) => clip(value2, 1)));
|
|
771
|
+
const items = Object.freeze(
|
|
772
|
+
array(root.items, limits.maxNodes - nodes).map((value2) => item(value2, 1))
|
|
773
|
+
);
|
|
774
|
+
const scene = { kind: "vector", width, height, clips, items };
|
|
775
|
+
checkVectorGraph(scene, limits);
|
|
776
|
+
return Object.freeze(scene);
|
|
777
|
+
}
|
|
778
|
+
|
|
779
|
+
// src/visio/media.ts
|
|
780
|
+
var VISIO_RASTER_IMAGE_LIMITS = Object.freeze({
|
|
781
|
+
maxImageBytes: 8 * 1024 * 1024,
|
|
782
|
+
maxPixels: 16e6,
|
|
783
|
+
maxDimension: 16384
|
|
784
|
+
});
|
|
785
|
+
var VisioImageError = class extends Error {
|
|
786
|
+
constructor(code, message) {
|
|
787
|
+
super(message);
|
|
788
|
+
this.code = code;
|
|
789
|
+
this.name = "VisioImageError";
|
|
790
|
+
}
|
|
791
|
+
code;
|
|
792
|
+
};
|
|
793
|
+
var invalid = (message) => {
|
|
794
|
+
throw new VisioImageError("invalid-image", message);
|
|
795
|
+
};
|
|
796
|
+
var unsupported = (message) => {
|
|
797
|
+
throw new VisioImageError("unsupported-image", message);
|
|
798
|
+
};
|
|
799
|
+
function dimensions(width, height, limits) {
|
|
800
|
+
if (!width || !height) invalid("Raster image has zero dimensions.");
|
|
801
|
+
if (width > limits.maxDimension || height > limits.maxDimension || width * height > limits.maxPixels)
|
|
802
|
+
throw new VisioImageError(
|
|
803
|
+
"image-limit",
|
|
804
|
+
"Raster image dimensions exceed the configured limit."
|
|
805
|
+
);
|
|
806
|
+
}
|
|
807
|
+
var ascii = (bytes, start, length) => String.fromCharCode(...bytes.subarray(start, start + length));
|
|
808
|
+
function png(bytes, limits) {
|
|
809
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
810
|
+
if (bytes.length < 33 || view.getUint32(8) !== 13 || ascii(bytes, 12, 4) !== "IHDR")
|
|
811
|
+
return invalid("PNG is missing a complete IHDR header.");
|
|
812
|
+
const width = view.getUint32(16), height = view.getUint32(20);
|
|
813
|
+
dimensions(width, height, limits);
|
|
814
|
+
const depth = bytes[24], color = bytes[25];
|
|
815
|
+
const depths = {
|
|
816
|
+
0: [1, 2, 4, 8, 16],
|
|
817
|
+
2: [8, 16],
|
|
818
|
+
3: [1, 2, 4, 8],
|
|
819
|
+
4: [8, 16],
|
|
820
|
+
6: [8, 16]
|
|
821
|
+
};
|
|
822
|
+
if (!depths[color]?.includes(depth) || bytes[26] !== 0 || bytes[27] !== 0 || bytes[28] > 1)
|
|
823
|
+
invalid("PNG header uses invalid color, compression, filter, or interlace values.");
|
|
824
|
+
let data = false;
|
|
825
|
+
for (let at = 8; at < bytes.length; ) {
|
|
826
|
+
if (at + 12 > bytes.length) invalid("Truncated PNG chunk.");
|
|
827
|
+
const length = view.getUint32(at), type = ascii(bytes, at + 4, 4), end = at + length + 12;
|
|
828
|
+
if (end > bytes.length) invalid("Truncated PNG chunk payload.");
|
|
829
|
+
if ((crc32(bytes.subarray(at + 4, end - 4)) ^ 4294967295) >>> 0 !== view.getUint32(end - 4))
|
|
830
|
+
invalid("PNG chunk checksum mismatch.");
|
|
831
|
+
if (type === "acTL") unsupported("Animated PNG is not supported.");
|
|
832
|
+
if (type === "IHDR" && at !== 8) invalid("PNG contains multiple image headers.");
|
|
833
|
+
if (type === "IDAT" && length) data = true;
|
|
834
|
+
if (type === "IEND") {
|
|
835
|
+
if (length || end !== bytes.length || !data) invalid("PNG has an invalid image terminator.");
|
|
836
|
+
return [width, height];
|
|
837
|
+
}
|
|
838
|
+
at = end;
|
|
839
|
+
}
|
|
840
|
+
return invalid("PNG has no image terminator.");
|
|
841
|
+
}
|
|
842
|
+
function gif(bytes, limits) {
|
|
843
|
+
if (bytes.length < 13) return invalid("GIF is missing a complete screen descriptor.");
|
|
844
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
845
|
+
const width = view.getUint16(6, true), height = view.getUint16(8, true);
|
|
846
|
+
dimensions(width, height, limits);
|
|
847
|
+
let at = 13 + (bytes[10] & 128 ? 3 * 2 ** ((bytes[10] & 7) + 1) : 0);
|
|
848
|
+
let frames = 0, pixels = 0;
|
|
849
|
+
const blocks = () => {
|
|
850
|
+
for (; ; ) {
|
|
851
|
+
if (at >= bytes.length) invalid("GIF has truncated data blocks.");
|
|
852
|
+
const size = bytes[at++];
|
|
853
|
+
if (!size) return;
|
|
854
|
+
at += size;
|
|
855
|
+
if (at > bytes.length) invalid("GIF has a truncated data block.");
|
|
856
|
+
}
|
|
857
|
+
};
|
|
858
|
+
while (at < bytes.length) {
|
|
859
|
+
const marker = bytes[at++];
|
|
860
|
+
if (marker === 59) {
|
|
861
|
+
if (!frames || at !== bytes.length) invalid("GIF has an invalid image terminator.");
|
|
862
|
+
return [width, height];
|
|
863
|
+
}
|
|
864
|
+
if (marker === 33) {
|
|
865
|
+
if (at >= bytes.length) invalid("GIF has a truncated extension.");
|
|
866
|
+
at++;
|
|
867
|
+
blocks();
|
|
868
|
+
continue;
|
|
869
|
+
}
|
|
870
|
+
if (marker !== 44 || at + 9 > bytes.length) invalid("GIF has an invalid image descriptor.");
|
|
871
|
+
const left = view.getUint16(at, true), top = view.getUint16(at + 2, true);
|
|
872
|
+
const frameWidth = view.getUint16(at + 4, true), frameHeight = view.getUint16(at + 6, true);
|
|
873
|
+
dimensions(frameWidth, frameHeight, limits);
|
|
874
|
+
if (left + frameWidth > width || top + frameHeight > height)
|
|
875
|
+
invalid("GIF frame exceeds its screen.");
|
|
876
|
+
pixels += width * height;
|
|
877
|
+
if (pixels > limits.maxPixels)
|
|
878
|
+
throw new VisioImageError("image-limit", "GIF animation exceeds the pixel limit.");
|
|
879
|
+
const packed = bytes[at + 8];
|
|
880
|
+
at += 9 + (packed & 128 ? 3 * 2 ** ((packed & 7) + 1) : 0);
|
|
881
|
+
if (at >= bytes.length || bytes[at] < 2 || bytes[at] > 8)
|
|
882
|
+
invalid("GIF has an invalid LZW header.");
|
|
883
|
+
at++;
|
|
884
|
+
blocks();
|
|
885
|
+
frames++;
|
|
886
|
+
}
|
|
887
|
+
return invalid("GIF has no image terminator.");
|
|
888
|
+
}
|
|
889
|
+
function jpeg(bytes, limits) {
|
|
890
|
+
const view = new DataView(bytes.buffer, bytes.byteOffset, bytes.byteLength);
|
|
891
|
+
let at = 2, width = 0, height = 0, scan = false;
|
|
892
|
+
while (at < bytes.length) {
|
|
893
|
+
if (bytes[at++] !== 255) invalid("JPEG has an invalid segment marker.");
|
|
894
|
+
while (bytes[at] === 255) at++;
|
|
895
|
+
const marker = bytes[at++];
|
|
896
|
+
if (marker === 217) {
|
|
897
|
+
if (!width || !scan || at !== bytes.length) invalid("JPEG has an invalid image terminator.");
|
|
898
|
+
return [width, height];
|
|
899
|
+
}
|
|
900
|
+
if (marker === void 0 || marker === 0 || marker === 216 || marker === 1 || marker >= 208 && marker <= 215)
|
|
901
|
+
invalid("JPEG has an unexpected standalone marker.");
|
|
902
|
+
if (at + 2 > bytes.length) invalid("JPEG has a truncated segment header.");
|
|
903
|
+
const length = view.getUint16(at), end = at + length;
|
|
904
|
+
if (length < 2 || end > bytes.length) invalid("JPEG has a truncated segment.");
|
|
905
|
+
if (marker >= 192 && marker <= 207 && ![196, 200, 204].includes(marker)) {
|
|
906
|
+
if (![192, 193, 194].includes(marker))
|
|
907
|
+
unsupported("This JPEG frame coding is unsupported.");
|
|
908
|
+
if (width || length < 11 || bytes[at + 2] !== 8 || length !== 8 + 3 * bytes[at + 7])
|
|
909
|
+
invalid("JPEG has an invalid frame header.");
|
|
910
|
+
height = view.getUint16(at + 3);
|
|
911
|
+
width = view.getUint16(at + 5);
|
|
912
|
+
dimensions(width, height, limits);
|
|
913
|
+
}
|
|
914
|
+
if (marker === 220) unsupported("JPEG deferred dimensions are unsupported.");
|
|
915
|
+
at = end;
|
|
916
|
+
if (marker === 218) {
|
|
917
|
+
if (!width || length < 8 || length !== 6 + 2 * bytes[end - length + 2])
|
|
918
|
+
invalid("JPEG has an invalid scan header.");
|
|
919
|
+
scan = true;
|
|
920
|
+
while (at < bytes.length) {
|
|
921
|
+
if (bytes[at] !== 255) {
|
|
922
|
+
at++;
|
|
923
|
+
continue;
|
|
924
|
+
}
|
|
925
|
+
const next = bytes[at + 1];
|
|
926
|
+
if (next === 0 || next !== void 0 && next >= 208 && next <= 215) {
|
|
927
|
+
at += 2;
|
|
928
|
+
continue;
|
|
929
|
+
}
|
|
930
|
+
break;
|
|
931
|
+
}
|
|
932
|
+
}
|
|
933
|
+
}
|
|
934
|
+
return invalid("JPEG has no image terminator.");
|
|
935
|
+
}
|
|
936
|
+
function inspectVisioRasterImage(bytes, options = {}) {
|
|
937
|
+
if (!options || typeof options !== "object" || Array.isArray(options))
|
|
938
|
+
throw new VisioImageError("invalid-limit", "Image limits must be an options object.");
|
|
939
|
+
const limits = { ...VISIO_RASTER_IMAGE_LIMITS, ...options };
|
|
940
|
+
for (const key of Object.keys(VISIO_RASTER_IMAGE_LIMITS)) {
|
|
941
|
+
const value = limits[key];
|
|
942
|
+
if (!Number.isSafeInteger(value) || value <= 0 || value > VISIO_RASTER_IMAGE_LIMITS[key])
|
|
943
|
+
throw new VisioImageError("invalid-limit", `Invalid raster image limit: ${key}.`);
|
|
944
|
+
}
|
|
945
|
+
if (!(bytes instanceof Uint8Array)) invalid("Raster image bytes must be a Uint8Array.");
|
|
946
|
+
if (bytes.byteLength > limits.maxImageBytes)
|
|
947
|
+
throw new VisioImageError("image-limit", "Raster image bytes exceed the configured limit.");
|
|
948
|
+
return inspect(bytes, limits);
|
|
949
|
+
}
|
|
950
|
+
function inspect(bytes, limits) {
|
|
951
|
+
let mimeType, size;
|
|
952
|
+
if ([137, 80, 78, 71, 13, 10, 26, 10].every((value, index) => bytes[index] === value)) {
|
|
953
|
+
mimeType = "image/png";
|
|
954
|
+
size = png(bytes, limits);
|
|
955
|
+
} else if (["GIF87a", "GIF89a"].includes(ascii(bytes, 0, 6))) {
|
|
956
|
+
mimeType = "image/gif";
|
|
957
|
+
size = gif(bytes, limits);
|
|
958
|
+
} else if (bytes[0] === 255 && bytes[1] === 216) {
|
|
959
|
+
mimeType = "image/jpeg";
|
|
960
|
+
size = jpeg(bytes, limits);
|
|
961
|
+
} else return unsupported("Foreign data is not a supported PNG, JPEG, or GIF raster image.");
|
|
962
|
+
return { mimeType, pixelWidth: size[0], pixelHeight: size[1] };
|
|
963
|
+
}
|
|
964
|
+
|
|
965
|
+
// src/visio/ui/foreign-vector-budget.ts
|
|
966
|
+
var FOREIGN_VECTOR_SCENE_LIMITS = Object.freeze({
|
|
967
|
+
maxNodes: 1e5,
|
|
968
|
+
maxCommands: 4e5,
|
|
969
|
+
maxOperands: 1e6
|
|
970
|
+
});
|
|
971
|
+
function inspectForeignVectorResource(source) {
|
|
972
|
+
const vector = validateVisioForeignVector(source);
|
|
973
|
+
let nodes = 1, commands = 0, operands = 0, svgBytes = 1536;
|
|
974
|
+
const count = (item, retained) => {
|
|
975
|
+
nodes++;
|
|
976
|
+
if (retained) svgBytes += 1024;
|
|
977
|
+
if ("commands" in item) {
|
|
978
|
+
commands += item.commands.length;
|
|
979
|
+
if (retained) svgBytes += item.commands.length * 4;
|
|
980
|
+
for (const command of item.commands) {
|
|
981
|
+
operands += command.values.length;
|
|
982
|
+
if (retained) svgBytes += command.values.length * 32;
|
|
983
|
+
}
|
|
984
|
+
} else for (const child of item.items) count(child, retained);
|
|
985
|
+
if (item.clipIndex !== void 0) count(vector.clips[item.clipIndex], false);
|
|
986
|
+
};
|
|
987
|
+
for (const clip of vector.clips) count(clip, true);
|
|
988
|
+
for (const item of vector.items) count(item, true);
|
|
989
|
+
return {
|
|
990
|
+
vector,
|
|
991
|
+
nodes,
|
|
992
|
+
commands,
|
|
993
|
+
operands,
|
|
994
|
+
svgBytes,
|
|
995
|
+
validationWork: nodes * 128 + commands * 32 + operands * 8
|
|
996
|
+
};
|
|
997
|
+
}
|
|
998
|
+
var ForeignVectorBudget = class {
|
|
999
|
+
nodes = 0;
|
|
1000
|
+
commands = 0;
|
|
1001
|
+
operands = 0;
|
|
1002
|
+
take(source) {
|
|
1003
|
+
const resource = inspectForeignVectorResource(source);
|
|
1004
|
+
this.nodes += resource.nodes;
|
|
1005
|
+
this.commands += resource.commands;
|
|
1006
|
+
this.operands += resource.operands;
|
|
1007
|
+
if (this.nodes > FOREIGN_VECTOR_SCENE_LIMITS.maxNodes || this.commands > FOREIGN_VECTOR_SCENE_LIMITS.maxCommands || this.operands > FOREIGN_VECTOR_SCENE_LIMITS.maxOperands)
|
|
1008
|
+
throw new Error("The scene exceeds aggregate foreign vector work limits.");
|
|
1009
|
+
return resource;
|
|
1010
|
+
}
|
|
1011
|
+
};
|
|
1012
|
+
|
|
1013
|
+
// src/visio/ui/scene-details.ts
|
|
1014
|
+
function assertShapeDetails(shape, budget) {
|
|
1015
|
+
const data = shape.shapeData ?? [], links = shape.hyperlinks ?? [];
|
|
1016
|
+
if (!Array.isArray(data) || !Array.isArray(links) || data.length + links.length > 1024 || (budget.rows += data.length + links.length) > 1e5)
|
|
1017
|
+
throw new Error("The scene exceeds shape metadata row limits.");
|
|
1018
|
+
const strings = (record2, names, required = false) => {
|
|
1019
|
+
for (const name of names)
|
|
1020
|
+
if ((required || record2[name] !== void 0) && typeof record2[name] !== "string")
|
|
1021
|
+
throw new Error("The scene has invalid shape metadata text.");
|
|
1022
|
+
};
|
|
1023
|
+
const booleans = (record2, names) => {
|
|
1024
|
+
for (const name of names)
|
|
1025
|
+
if (record2[name] !== void 0 && typeof record2[name] !== "boolean")
|
|
1026
|
+
throw new Error("The scene has invalid shape metadata flags.");
|
|
1027
|
+
};
|
|
1028
|
+
const count = (record2, skipTarget = false) => {
|
|
1029
|
+
const values = Object.entries(record2);
|
|
1030
|
+
if (values.length > 32) throw new Error("The scene has excessive shape metadata fields.");
|
|
1031
|
+
for (const [name, value] of values) {
|
|
1032
|
+
if (skipTarget && name === "target") continue;
|
|
1033
|
+
if (typeof value === "string") {
|
|
1034
|
+
if (value.length > 8192 || (budget.characters += value.length) > 5e6)
|
|
1035
|
+
throw new Error("The scene exceeds shape metadata string limits.");
|
|
1036
|
+
} else if (typeof value === "number") {
|
|
1037
|
+
if (!Number.isFinite(value)) throw new Error("The scene has invalid numeric metadata.");
|
|
1038
|
+
} else if (value !== void 0 && value !== null && typeof value !== "boolean")
|
|
1039
|
+
throw new Error("The scene has invalid shape metadata values.");
|
|
1040
|
+
}
|
|
1041
|
+
};
|
|
1042
|
+
for (const row of data) {
|
|
1043
|
+
const record2 = row;
|
|
1044
|
+
strings(record2, ["id", "name", "valueKind"], true);
|
|
1045
|
+
strings(record2, [
|
|
1046
|
+
"label",
|
|
1047
|
+
"rawType",
|
|
1048
|
+
"rawValue",
|
|
1049
|
+
"unit",
|
|
1050
|
+
"error",
|
|
1051
|
+
"format",
|
|
1052
|
+
"prompt",
|
|
1053
|
+
"sortKey"
|
|
1054
|
+
]);
|
|
1055
|
+
booleans(record2, ["invisible"]);
|
|
1056
|
+
count(row);
|
|
1057
|
+
}
|
|
1058
|
+
for (const row of links) {
|
|
1059
|
+
const record2 = row;
|
|
1060
|
+
strings(record2, ["id", "name"], true);
|
|
1061
|
+
strings(record2, ["description", "address", "subAddress", "sortKey"]);
|
|
1062
|
+
booleans(record2, ["default", "newWindow", "invisible"]);
|
|
1063
|
+
count(row, true);
|
|
1064
|
+
if (!row.target || typeof row.target !== "object" || Array.isArray(row.target))
|
|
1065
|
+
throw new Error("The scene has invalid hyperlink metadata.");
|
|
1066
|
+
const target = row.target;
|
|
1067
|
+
const key = row.target.kind === "external" ? "href" : row.target.kind === "internal" ? "subAddress" : row.target.kind === "unresolved" ? "reason" : void 0;
|
|
1068
|
+
if (!key) throw new Error("The scene has invalid hyperlink metadata.");
|
|
1069
|
+
strings(target, [key], true);
|
|
1070
|
+
count(row.target);
|
|
1071
|
+
}
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
// src/visio/ui/scene-validation.ts
|
|
1075
|
+
var MAX_INPUT_BYTES = 32 * 1024 * 1024;
|
|
1076
|
+
var MAX_DIMENSION = 1e4;
|
|
1077
|
+
var MAX_SHAPES = 25e3;
|
|
1078
|
+
function finite2(value, label, min = -MAX_DIMENSION, max = MAX_DIMENSION) {
|
|
1079
|
+
if (!Number.isFinite(value) || value < min || value > max)
|
|
1080
|
+
throw new Error(`The scene has an invalid ${label}.`);
|
|
1081
|
+
}
|
|
1082
|
+
function member(value, choices, label) {
|
|
1083
|
+
if (!choices.includes(value)) throw new Error(`The scene has an invalid ${label}.`);
|
|
1084
|
+
}
|
|
1085
|
+
function assertViewableDocument(model) {
|
|
1086
|
+
if (model.format !== "vsdx" && model.format !== "vsd" || !Array.isArray(model.pages) || model.pages.length > 256 || !Array.isArray(model.diagnostics) || model.diagnostics.length > 2e3)
|
|
1087
|
+
throw new Error("The scene has an invalid page list.");
|
|
1088
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1089
|
+
let pathBytes = 0, textBytes = 0, runCount = 0, imageBytes = 0, geometryCount = 0, uniquePixels = 0, drawnPixels = 0, layerCount = 0, paragraphCount = 0, gradientStops = 0;
|
|
1090
|
+
const imageResources = /* @__PURE__ */ new Map();
|
|
1091
|
+
const vectorBudget = new ForeignVectorBudget();
|
|
1092
|
+
let metadataBytes = 0;
|
|
1093
|
+
const detailBudget = { rows: 0, characters: 0 };
|
|
1094
|
+
const label = (value, limit2 = 4096) => {
|
|
1095
|
+
if (typeof value !== "string" || value.length > limit2)
|
|
1096
|
+
throw new Error("The scene exceeds safe metadata string limits.");
|
|
1097
|
+
metadataBytes += value.length;
|
|
1098
|
+
if (metadataBytes > 1e6) throw new Error("The scene exceeds aggregate metadata limits.");
|
|
1099
|
+
};
|
|
1100
|
+
for (const diagnostic of model.diagnostics) {
|
|
1101
|
+
label(diagnostic.code, 256);
|
|
1102
|
+
label(diagnostic.message);
|
|
1103
|
+
member(diagnostic.severity, ["info", "warning"], "diagnostic severity");
|
|
1104
|
+
}
|
|
1105
|
+
const pageIds = /* @__PURE__ */ new Set();
|
|
1106
|
+
const stack = [];
|
|
1107
|
+
for (const page of model.pages) {
|
|
1108
|
+
label(page.id, 256);
|
|
1109
|
+
if (pageIds.has(page.id)) throw new Error("The scene has duplicate page identities.");
|
|
1110
|
+
pageIds.add(page.id);
|
|
1111
|
+
label(page.name);
|
|
1112
|
+
if (page.layers !== void 0 && !Array.isArray(page.layers))
|
|
1113
|
+
throw new Error("The scene has an invalid layer list.");
|
|
1114
|
+
layerCount += page.layers?.length ?? 0;
|
|
1115
|
+
if (layerCount > 25e3) throw new Error("The scene exceeds safe layer count limits.");
|
|
1116
|
+
for (const layer of page.layers ?? []) {
|
|
1117
|
+
label(layer.id, 256);
|
|
1118
|
+
label(layer.name);
|
|
1119
|
+
for (const flag of [layer.visible, layer.printable, layer.locked])
|
|
1120
|
+
member(flag, [true, false], "layer flag");
|
|
1121
|
+
}
|
|
1122
|
+
finite2(page.width, "page width", 1e-3);
|
|
1123
|
+
finite2(page.height, "page height", 1e-3);
|
|
1124
|
+
if (!Array.isArray(page.shapes) || stack.length + page.shapes.length > MAX_SHAPES)
|
|
1125
|
+
throw new Error("The scene exceeds safe shape count limits or has an invalid shape list.");
|
|
1126
|
+
const ids = /* @__PURE__ */ new Set();
|
|
1127
|
+
for (const shape of page.shapes) stack.push({ shape, depth: 0, ids });
|
|
1128
|
+
}
|
|
1129
|
+
while (stack.length) {
|
|
1130
|
+
const { shape, depth, ids } = stack.pop();
|
|
1131
|
+
if (depth > 64 || seen.has(shape) || seen.size >= MAX_SHAPES)
|
|
1132
|
+
throw new Error("The scene exceeds safe shape depth/count limits or contains a cycle.");
|
|
1133
|
+
seen.add(shape);
|
|
1134
|
+
if (!Array.isArray(shape.children) || seen.size + stack.length + shape.children.length > MAX_SHAPES)
|
|
1135
|
+
throw new Error("The scene exceeds safe shape count limits or has an invalid child list.");
|
|
1136
|
+
label(shape.id, 1024);
|
|
1137
|
+
if (ids.has(shape.id)) throw new Error("The scene has duplicate shape identities on one page.");
|
|
1138
|
+
ids.add(shape.id);
|
|
1139
|
+
member(shape.hidden, [true, false], "hidden flag");
|
|
1140
|
+
member(shape.kind, ["shape", "group", "connector", "foreign"], "shape kind");
|
|
1141
|
+
if (shape.groupDisplayMode !== void 0)
|
|
1142
|
+
member(shape.groupDisplayMode, [0, 1, 2], "group display mode");
|
|
1143
|
+
member(shape.text.horizontalAlign, ["left", "center", "right"], "text alignment");
|
|
1144
|
+
member(shape.text.verticalAlign, ["top", "middle", "bottom"], "text alignment");
|
|
1145
|
+
label(shape.name);
|
|
1146
|
+
label(shape.text.fontFamily, 1024);
|
|
1147
|
+
label(shape.style.fill, 256);
|
|
1148
|
+
label(shape.style.lineColor, 256);
|
|
1149
|
+
label(shape.text.color, 256);
|
|
1150
|
+
if (shape.text.backgroundColor) label(shape.text.backgroundColor, 256);
|
|
1151
|
+
if (shape.text.backgroundOpacity !== void 0)
|
|
1152
|
+
finite2(shape.text.backgroundOpacity, "text background opacity", 0, 1);
|
|
1153
|
+
assertShapeDetails(shape, detailBudget);
|
|
1154
|
+
if (shape.visibility) {
|
|
1155
|
+
member(shape.visibility.layerHidden, [true, false], "layer visibility metadata");
|
|
1156
|
+
member(shape.visibility.guide, [true, false], "guide visibility metadata");
|
|
1157
|
+
member(shape.visibility.noShow, [void 0, true, false], "NoShow visibility metadata");
|
|
1158
|
+
member(shape.visibility.nonPrinting, [void 0, true, false], "NonPrinting metadata");
|
|
1159
|
+
member(
|
|
1160
|
+
shape.visibility.layerPrintSummary,
|
|
1161
|
+
["unlayered", "all-enabled", "all-disabled", "mixed", "unknown"],
|
|
1162
|
+
"layer print summary"
|
|
1163
|
+
);
|
|
1164
|
+
}
|
|
1165
|
+
finite2(shape.width, "shape width", 0);
|
|
1166
|
+
finite2(shape.height, "shape height", 0);
|
|
1167
|
+
if (shape.transform.length !== 6 || shape.text.transform.length !== 6)
|
|
1168
|
+
throw new Error("The scene has an invalid transform.");
|
|
1169
|
+
for (const value of [...shape.transform, ...shape.text.transform]) finite2(value, "transform");
|
|
1170
|
+
finite2(shape.text.width, "text width", 0);
|
|
1171
|
+
finite2(shape.text.height, "text height", 0);
|
|
1172
|
+
finite2(shape.text.fontSize, "font size", 0, 100);
|
|
1173
|
+
finite2(shape.style.lineWidth, "line width", 0, 100);
|
|
1174
|
+
if (shape.style.lineDash !== void 0) {
|
|
1175
|
+
const dash = shape.style.lineDash;
|
|
1176
|
+
if (!Array.isArray(dash) || dash.length < 2 || dash.length > 6 || dash.length % 2 !== 0)
|
|
1177
|
+
throw new Error("The scene has an invalid normalized line dash.");
|
|
1178
|
+
for (const value of dash) finite2(value, "line dash length", 0, 27);
|
|
1179
|
+
if (!dash.some((value) => value > 0))
|
|
1180
|
+
throw new Error("The scene has an empty line dash pattern.");
|
|
1181
|
+
}
|
|
1182
|
+
for (const value of [shape.style.linePattern, shape.style.startArrow, shape.style.endArrow]) {
|
|
1183
|
+
finite2(value, "line pattern or arrow code", 0, 65535);
|
|
1184
|
+
if (!Number.isInteger(value))
|
|
1185
|
+
throw new Error("The scene has an invalid line pattern or arrow code.");
|
|
1186
|
+
}
|
|
1187
|
+
for (const size of [shape.style.startArrowSize, shape.style.endArrowSize])
|
|
1188
|
+
if (size !== void 0) finite2(size, "arrow size", 0, 65535);
|
|
1189
|
+
if (shape.style.lineCap !== void 0 && !["round", "butt", "square"].includes(shape.style.lineCap))
|
|
1190
|
+
throw new Error("The scene has an invalid normalized line cap.");
|
|
1191
|
+
finite2(shape.style.fillOpacity, "fill opacity", 0, 1);
|
|
1192
|
+
finite2(shape.style.lineOpacity, "line opacity", 0, 1);
|
|
1193
|
+
if (shape.style.fillGradient) {
|
|
1194
|
+
const gradient = shape.style.fillGradient;
|
|
1195
|
+
if (gradient.type !== "linear" || !Array.isArray(gradient.stops) || gradient.stops.length < 2 || gradient.stops.length > 128 || gradient.start.length !== 2 || gradient.end.length !== 2)
|
|
1196
|
+
throw new Error("The scene has an invalid fill gradient.");
|
|
1197
|
+
if ((gradientStops += gradient.stops.length) > 1e5)
|
|
1198
|
+
throw new Error("The scene exceeds aggregate gradient stop limits.");
|
|
1199
|
+
for (const value of [...gradient.start, ...gradient.end])
|
|
1200
|
+
finite2(value, "gradient position", -2e4, 2e4);
|
|
1201
|
+
let offset = -1;
|
|
1202
|
+
for (const stop of gradient.stops) {
|
|
1203
|
+
finite2(stop.offset, "gradient stop", 0, 1);
|
|
1204
|
+
finite2(stop.opacity, "gradient opacity", 0, 1);
|
|
1205
|
+
label(stop.color, 256);
|
|
1206
|
+
if (stop.offset < offset) throw new Error("Gradient stops must be ordered.");
|
|
1207
|
+
offset = stop.offset;
|
|
1208
|
+
}
|
|
1209
|
+
}
|
|
1210
|
+
if (typeof shape.text.plainText !== "string")
|
|
1211
|
+
throw new Error("The scene has invalid plain text.");
|
|
1212
|
+
textBytes += shape.text.plainText.length;
|
|
1213
|
+
if (!Array.isArray(shape.text.runs) || runCount + shape.text.runs.length > 1e5)
|
|
1214
|
+
throw new Error("The scene exceeds safe text run limits or has an invalid run list.");
|
|
1215
|
+
for (const run of shape.text.runs) {
|
|
1216
|
+
label(run.fontFamily, 1024);
|
|
1217
|
+
label(run.color, 256);
|
|
1218
|
+
if (typeof run.text !== "string") throw new Error("The scene has invalid run text.");
|
|
1219
|
+
textBytes += run.text.length;
|
|
1220
|
+
++runCount;
|
|
1221
|
+
finite2(run.fontSize, "run font size", 0, 100);
|
|
1222
|
+
}
|
|
1223
|
+
if (!Array.isArray(shape.geometry) || geometryCount + shape.geometry.length > 1e5)
|
|
1224
|
+
throw new Error("The scene exceeds safe geometry limits or has an invalid geometry list.");
|
|
1225
|
+
for (const geometry of shape.geometry) {
|
|
1226
|
+
if (typeof geometry.path !== "string") throw new Error("The scene has invalid path text.");
|
|
1227
|
+
member(geometry.fill, [true, false], "geometry fill flag");
|
|
1228
|
+
member(geometry.stroke, [true, false], "geometry stroke flag");
|
|
1229
|
+
pathBytes += geometry.path.length;
|
|
1230
|
+
geometryCount++;
|
|
1231
|
+
}
|
|
1232
|
+
if (geometryCount > 1e5) throw new Error("The scene exceeds safe geometry limits.");
|
|
1233
|
+
if (pathBytes > 16e6 || textBytes > 5e6 || runCount > 1e5)
|
|
1234
|
+
throw new Error("The scene exceeds safe path/text limits.");
|
|
1235
|
+
for (const value of [
|
|
1236
|
+
shape.text.margins.left,
|
|
1237
|
+
shape.text.margins.right,
|
|
1238
|
+
shape.text.margins.top,
|
|
1239
|
+
shape.text.margins.bottom
|
|
1240
|
+
])
|
|
1241
|
+
finite2(value, "text margin");
|
|
1242
|
+
const paragraphs = shape.text.paragraphs ?? [];
|
|
1243
|
+
if (!Array.isArray(paragraphs) || paragraphs.length > 5e3 || (paragraphCount += paragraphs.length) > 5e4)
|
|
1244
|
+
throw new Error("The scene exceeds safe paragraph limits.");
|
|
1245
|
+
for (const paragraph of paragraphs) {
|
|
1246
|
+
member(paragraph.direction, ["ltr", "rtl"], "paragraph direction");
|
|
1247
|
+
member(
|
|
1248
|
+
paragraph.horizontalAlign,
|
|
1249
|
+
["left", "center", "right", "justify", "distributed"],
|
|
1250
|
+
"paragraph alignment"
|
|
1251
|
+
);
|
|
1252
|
+
member(paragraph.lineSpacing.kind, ["multiple", "exact"], "paragraph line spacing");
|
|
1253
|
+
if (!Number.isSafeInteger(paragraph.start) || !Number.isSafeInteger(paragraph.end) || paragraph.start < 0 || paragraph.end < paragraph.start || paragraph.end > shape.text.plainText.length)
|
|
1254
|
+
throw new Error("The scene has invalid paragraph offsets.");
|
|
1255
|
+
for (const value of [
|
|
1256
|
+
paragraph.indentLeft,
|
|
1257
|
+
paragraph.indentRight,
|
|
1258
|
+
paragraph.indentFirst,
|
|
1259
|
+
paragraph.spaceBefore,
|
|
1260
|
+
paragraph.spaceAfter
|
|
1261
|
+
])
|
|
1262
|
+
finite2(value, "paragraph position");
|
|
1263
|
+
finite2(paragraph.lineSpacing.value, "line spacing", 0, 100);
|
|
1264
|
+
if (paragraph.bullet) {
|
|
1265
|
+
label(paragraph.bullet.text, 1024);
|
|
1266
|
+
label(paragraph.bullet.fontFamily, 1024);
|
|
1267
|
+
finite2(paragraph.bullet.fontSize, "bullet size", 0, 100);
|
|
1268
|
+
finite2(paragraph.bullet.offset, "bullet offset");
|
|
1269
|
+
}
|
|
1270
|
+
}
|
|
1271
|
+
if (shape.foreignVector !== void 0) {
|
|
1272
|
+
const foreign = shape.foreignVector;
|
|
1273
|
+
if (!foreign || typeof foreign !== "object")
|
|
1274
|
+
throw new Error("The scene has an invalid foreign vector placement.");
|
|
1275
|
+
finite2(foreign.x, "foreign vector position");
|
|
1276
|
+
finite2(foreign.y, "foreign vector position");
|
|
1277
|
+
finite2(foreign.width, "foreign vector width", 0);
|
|
1278
|
+
finite2(foreign.height, "foreign vector height", 0);
|
|
1279
|
+
finite2(foreign.opacity, "foreign vector opacity", 0, 1);
|
|
1280
|
+
vectorBudget.take(foreign.vector);
|
|
1281
|
+
}
|
|
1282
|
+
if (shape.image) {
|
|
1283
|
+
const image = shape.image;
|
|
1284
|
+
if (!["image/png", "image/jpeg", "image/gif"].includes(image.mimeType) || !(image.bytes instanceof Uint8Array))
|
|
1285
|
+
throw new Error("Unsupported embedded image.");
|
|
1286
|
+
imageBytes += image.bytes.byteLength;
|
|
1287
|
+
if (image.bytes.byteLength > 8 * 1024 * 1024 || imageBytes > 64 * 1024 * 1024)
|
|
1288
|
+
throw new Error("The scene exceeds safe image limits.");
|
|
1289
|
+
finite2(image.pixelWidth, "image width", 1, 16384);
|
|
1290
|
+
finite2(image.pixelHeight, "image height", 1, 16384);
|
|
1291
|
+
drawnPixels += image.pixelWidth * image.pixelHeight;
|
|
1292
|
+
if (!imageResources.has(image.bytes)) {
|
|
1293
|
+
imageResources.set(image.bytes, image);
|
|
1294
|
+
uniquePixels += image.pixelWidth * image.pixelHeight;
|
|
1295
|
+
} else {
|
|
1296
|
+
const previous = imageResources.get(image.bytes);
|
|
1297
|
+
if (previous.mimeType !== image.mimeType || previous.pixelWidth !== image.pixelWidth || previous.pixelHeight !== image.pixelHeight)
|
|
1298
|
+
throw new Error("Shared raster bytes have inconsistent declared metadata.");
|
|
1299
|
+
}
|
|
1300
|
+
if (uniquePixels > 64e6 || drawnPixels > 256e6)
|
|
1301
|
+
throw new Error("The scene exceeds aggregate decoded image limits.");
|
|
1302
|
+
if (image.opacity !== void 0) finite2(image.opacity, "image opacity", 0, 1);
|
|
1303
|
+
if (image.pixelWidth * image.pixelHeight > VISIO_RASTER_IMAGE_LIMITS.maxPixels)
|
|
1304
|
+
throw new Error("The scene exceeds safe image pixel limits.");
|
|
1305
|
+
if (image.x !== void 0) finite2(image.x, "image position");
|
|
1306
|
+
if (image.y !== void 0) finite2(image.y, "image position");
|
|
1307
|
+
if (image.width !== void 0) finite2(image.width, "image width", 0);
|
|
1308
|
+
if (image.height !== void 0) finite2(image.height, "image height", 0);
|
|
1309
|
+
}
|
|
1310
|
+
for (const child of shape.children) stack.push({ shape: child, depth: depth + 1, ids });
|
|
1311
|
+
}
|
|
1312
|
+
for (const image of imageResources.values()) {
|
|
1313
|
+
const actual = inspectVisioRasterImage(image.bytes);
|
|
1314
|
+
if (actual.mimeType !== image.mimeType || actual.pixelWidth !== image.pixelWidth || actual.pixelHeight !== image.pixelHeight)
|
|
1315
|
+
throw new Error("Declared raster MIME or dimensions do not match the embedded bytes.");
|
|
1316
|
+
}
|
|
1317
|
+
}
|
|
1318
|
+
|
|
1319
|
+
// src/visio/ui/snapshot-scene.ts
|
|
1320
|
+
function fields(source, keys) {
|
|
1321
|
+
const result = {};
|
|
1322
|
+
for (const key of keys) {
|
|
1323
|
+
const value = source[key];
|
|
1324
|
+
if (value !== null && (typeof value === "object" || typeof value === "function"))
|
|
1325
|
+
throw invalid2();
|
|
1326
|
+
if (value !== void 0) result[key] = value;
|
|
1327
|
+
}
|
|
1328
|
+
return result;
|
|
1329
|
+
}
|
|
1330
|
+
var matrix = (value) => [
|
|
1331
|
+
value[0],
|
|
1332
|
+
value[1],
|
|
1333
|
+
value[2],
|
|
1334
|
+
value[3],
|
|
1335
|
+
value[4],
|
|
1336
|
+
value[5]
|
|
1337
|
+
];
|
|
1338
|
+
var invalid2 = () => new Error("The scene exceeds safe snapshot copy limits.");
|
|
1339
|
+
function copySnapshotScene(model) {
|
|
1340
|
+
const counts = /* @__PURE__ */ new Map();
|
|
1341
|
+
const take = (key, amount, maximum) => {
|
|
1342
|
+
const total = (counts.get(key) ?? 0) + amount;
|
|
1343
|
+
if (!Number.isSafeInteger(amount) || amount < 0 || total > maximum) throw invalid2();
|
|
1344
|
+
counts.set(key, total);
|
|
1345
|
+
};
|
|
1346
|
+
const list = (source, key, maximum, copy) => {
|
|
1347
|
+
if (!Array.isArray(source)) throw invalid2();
|
|
1348
|
+
const length = source.length;
|
|
1349
|
+
take(key, length, maximum);
|
|
1350
|
+
const result = [];
|
|
1351
|
+
for (let index = 0; index < length; index++) result.push(copy(source[index]));
|
|
1352
|
+
return result;
|
|
1353
|
+
};
|
|
1354
|
+
const resources = /* @__PURE__ */ new Map();
|
|
1355
|
+
const vectorBudget = new ForeignVectorBudget();
|
|
1356
|
+
const foreignVector = (source) => ({
|
|
1357
|
+
...fields(source, ["x", "y", "width", "height", "opacity"]),
|
|
1358
|
+
vector: vectorBudget.take(source.vector).vector
|
|
1359
|
+
});
|
|
1360
|
+
const image = (source) => {
|
|
1361
|
+
const original = source.bytes;
|
|
1362
|
+
if (!(original instanceof Uint8Array) || original.byteLength > 8 * 1024 * 1024) throw invalid2();
|
|
1363
|
+
let bytes = resources.get(original);
|
|
1364
|
+
if (!bytes) {
|
|
1365
|
+
take("raster bytes", original.byteLength, 64 * 1024 * 1024);
|
|
1366
|
+
bytes = new Uint8Array(original.byteLength);
|
|
1367
|
+
bytes.set(original);
|
|
1368
|
+
resources.set(original, bytes);
|
|
1369
|
+
}
|
|
1370
|
+
return {
|
|
1371
|
+
...fields(source, [
|
|
1372
|
+
"mimeType",
|
|
1373
|
+
"pixelWidth",
|
|
1374
|
+
"pixelHeight",
|
|
1375
|
+
"opacity",
|
|
1376
|
+
"x",
|
|
1377
|
+
"y",
|
|
1378
|
+
"width",
|
|
1379
|
+
"height"
|
|
1380
|
+
]),
|
|
1381
|
+
bytes
|
|
1382
|
+
};
|
|
1383
|
+
};
|
|
1384
|
+
const style = (source) => {
|
|
1385
|
+
const result = fields(source, [
|
|
1386
|
+
"fill",
|
|
1387
|
+
"lineColor",
|
|
1388
|
+
"lineWidth",
|
|
1389
|
+
"lineCap",
|
|
1390
|
+
"linePattern",
|
|
1391
|
+
"fillOpacity",
|
|
1392
|
+
"lineOpacity",
|
|
1393
|
+
"startArrow",
|
|
1394
|
+
"endArrow",
|
|
1395
|
+
"startArrowSize",
|
|
1396
|
+
"endArrowSize"
|
|
1397
|
+
]);
|
|
1398
|
+
const dash = source.lineDash;
|
|
1399
|
+
const gradient = source.fillGradient;
|
|
1400
|
+
return {
|
|
1401
|
+
...result,
|
|
1402
|
+
...dash === void 0 ? {} : { lineDash: list(dash, "dash values", 15e4, (value) => value) },
|
|
1403
|
+
...gradient ? {
|
|
1404
|
+
fillGradient: {
|
|
1405
|
+
type: gradient.type,
|
|
1406
|
+
start: [gradient.start[0], gradient.start[1]],
|
|
1407
|
+
end: [gradient.end[0], gradient.end[1]],
|
|
1408
|
+
stops: list(
|
|
1409
|
+
gradient.stops,
|
|
1410
|
+
"gradient stops",
|
|
1411
|
+
1e5,
|
|
1412
|
+
(stop) => fields(stop, ["offset", "color", "opacity"])
|
|
1413
|
+
)
|
|
1414
|
+
}
|
|
1415
|
+
} : {}
|
|
1416
|
+
};
|
|
1417
|
+
};
|
|
1418
|
+
const paragraph = (source) => ({
|
|
1419
|
+
...fields(source, [
|
|
1420
|
+
"start",
|
|
1421
|
+
"end",
|
|
1422
|
+
"horizontalAlign",
|
|
1423
|
+
"indentLeft",
|
|
1424
|
+
"indentRight",
|
|
1425
|
+
"indentFirst",
|
|
1426
|
+
"spaceBefore",
|
|
1427
|
+
"spaceAfter",
|
|
1428
|
+
"direction"
|
|
1429
|
+
]),
|
|
1430
|
+
lineSpacing: fields(source.lineSpacing, ["kind", "value"]),
|
|
1431
|
+
...source.bullet ? { bullet: fields(source.bullet, ["text", "fontFamily", "fontSize", "offset"]) } : {}
|
|
1432
|
+
});
|
|
1433
|
+
const text = (source) => ({
|
|
1434
|
+
...fields(source, [
|
|
1435
|
+
"plainText",
|
|
1436
|
+
"backgroundColor",
|
|
1437
|
+
"backgroundOpacity",
|
|
1438
|
+
"fontFamily",
|
|
1439
|
+
"fontSize",
|
|
1440
|
+
"color",
|
|
1441
|
+
"horizontalAlign",
|
|
1442
|
+
"verticalAlign",
|
|
1443
|
+
"width",
|
|
1444
|
+
"height"
|
|
1445
|
+
]),
|
|
1446
|
+
transform: matrix(source.transform),
|
|
1447
|
+
margins: fields(source.margins, ["left", "right", "top", "bottom"]),
|
|
1448
|
+
runs: list(source.runs, "text runs", 1e5, (run) => ({
|
|
1449
|
+
...fields(run, ["text", "fontFamily", "fontSize", "color"]),
|
|
1450
|
+
bold: !!run.bold,
|
|
1451
|
+
italic: !!run.italic,
|
|
1452
|
+
underline: !!run.underline
|
|
1453
|
+
})),
|
|
1454
|
+
...source.paragraphs === void 0 ? {} : { paragraphs: list(source.paragraphs, "paragraphs", 5e4, paragraph) }
|
|
1455
|
+
});
|
|
1456
|
+
const seen = /* @__PURE__ */ new Set();
|
|
1457
|
+
const shapes = (source, depth = 0) => {
|
|
1458
|
+
if (depth > 64) {
|
|
1459
|
+
if (!Array.isArray(source) || source.length) throw invalid2();
|
|
1460
|
+
return [];
|
|
1461
|
+
}
|
|
1462
|
+
return list(source, "shapes", 25e3, (shape) => {
|
|
1463
|
+
if (seen.has(shape)) throw invalid2();
|
|
1464
|
+
seen.add(shape);
|
|
1465
|
+
return {
|
|
1466
|
+
...fields(shape, ["id", "name", "kind", "groupDisplayMode", "width", "height", "hidden"]),
|
|
1467
|
+
transform: matrix(shape.transform),
|
|
1468
|
+
geometry: list(
|
|
1469
|
+
shape.geometry,
|
|
1470
|
+
"geometry",
|
|
1471
|
+
1e5,
|
|
1472
|
+
(geometry) => fields(geometry, ["path", "fill", "stroke"])
|
|
1473
|
+
),
|
|
1474
|
+
style: style(shape.style),
|
|
1475
|
+
text: text(shape.text),
|
|
1476
|
+
children: shapes(shape.children, depth + 1),
|
|
1477
|
+
...shape.image ? { image: image(shape.image) } : {},
|
|
1478
|
+
...shape.foreignVector ? { foreignVector: foreignVector(shape.foreignVector) } : {}
|
|
1479
|
+
};
|
|
1480
|
+
});
|
|
1481
|
+
};
|
|
1482
|
+
return {
|
|
1483
|
+
format: "vsdx",
|
|
1484
|
+
diagnostics: list(
|
|
1485
|
+
model.diagnostics,
|
|
1486
|
+
"diagnostics",
|
|
1487
|
+
2e3,
|
|
1488
|
+
(note) => fields(note, ["code", "message", "severity"])
|
|
1489
|
+
),
|
|
1490
|
+
pages: list(model.pages, "pages", 256, (page) => ({
|
|
1491
|
+
...fields(page, ["id", "name", "width", "height", "isBackground", "backgroundPageId"]),
|
|
1492
|
+
shapes: shapes(page.shapes),
|
|
1493
|
+
connectors: []
|
|
1494
|
+
}))
|
|
1495
|
+
};
|
|
1496
|
+
}
|
|
1497
|
+
|
|
1498
|
+
export { DocumentHistory, EDIT_HISTORY_LIMITS, EMPTY_EDIT_STATE, EMPTY_TEXT_SEARCH, FOREIGN_VECTOR_SCENE_LIMITS, ForeignVectorBudget, MAX_INPUT_BYTES, TEXT_SEARCH_LIMITS, assertShapeDetails, assertViewableDocument, compatibilityNotes, compatibilityText, copySnapshotScene, demoDocument, editErrorMessage, eventKeys, indexDocumentText, inspectForeignVectorResource, isEditCancellation, propertyKeys, searchDocumentText, snapshotEdits, textSearchStatus, validateSearchQuery };
|