@a3s-lab/office 0.15.0 → 0.16.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.
Files changed (33) hide show
  1. package/COLLABORATION_ROADMAP.md +15 -5
  2. package/README.md +22 -1
  3. package/dist/0~6090.js +7 -8
  4. package/dist/0~spreadsheet-editor.js +2106 -438
  5. package/dist/2180.js +370 -34
  6. package/dist/4104.js +657 -22
  7. package/dist/5184.js +1 -1
  8. package/dist/8715.js +156 -156
  9. package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +2 -0
  10. package/dist/internal/collaboration/office-spreadsheet-collaboration-validation-support.d.ts +6 -0
  11. package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +1 -0
  12. package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +21 -1
  13. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +10 -0
  14. package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +4 -2
  15. package/dist/internal/features/work/editors/spreadsheet-table-command.d.ts +3 -0
  16. package/dist/internal/features/work/editors/spreadsheet-table-conversion.d.ts +7 -0
  17. package/dist/internal/features/work/editors/spreadsheet-table-dialog.d.ts +8 -0
  18. package/dist/internal/features/work/editors/spreadsheet-table-limits.d.ts +1 -0
  19. package/dist/internal/features/work/editors/spreadsheet-table-reconciliation.d.ts +21 -0
  20. package/dist/internal/features/work/editors/spreadsheet-table-render.d.ts +16 -0
  21. package/dist/internal/features/work/editors/spreadsheet-table-ribbon.d.ts +8 -0
  22. package/dist/internal/features/work/editors/spreadsheet-table-style.d.ts +31 -0
  23. package/dist/internal/features/work/editors/spreadsheet-table.d.ts +55 -0
  24. package/dist/internal/features/work/editors/use-spreadsheet-table.d.ts +23 -0
  25. package/dist/internal/features/work/work-types.d.ts +100 -0
  26. package/dist/internal/features/work/work-xlsx-interop.d.ts +2 -0
  27. package/dist/internal/features/work/work-xlsx-table-filters.d.ts +3 -0
  28. package/dist/internal/features/work/work-xlsx-tables.d.ts +4 -0
  29. package/dist/office-kernel.wasm +0 -0
  30. package/dist/styles.css +189 -0
  31. package/dist/work-spreadsheet-package-scan.worker.js +3 -2
  32. package/docs/latest/en/browser-editor-architecture.md +43 -0
  33. package/package.json +4 -1
package/dist/4104.js CHANGED
@@ -5637,7 +5637,8 @@ const IMPORTED_WORKSHEET_ELEMENTS = new Set([
5637
5637
  'printOptions',
5638
5638
  'headerFooter',
5639
5639
  'pageSetUpPr',
5640
- 'drawing'
5640
+ 'drawing',
5641
+ 'tableParts'
5641
5642
  ]);
5642
5643
  const DIAGNOSTIC_WORKSHEET_ELEMENTS = new Set([
5643
5644
  'conditionalFormatting',
@@ -5652,7 +5653,7 @@ const DIAGNOSTIC_WORKSHEET_ELEMENTS = new Set([
5652
5653
  'rowBreaks',
5653
5654
  'colBreaks'
5654
5655
  ]);
5655
- const WORKSHEET_SCAN_PATTERN = /<(?:[A-Za-z_][\w.-]*:)?(?:(cols|f|pane|dataValidation|conditionalFormatting|sheetProtection|protectedRange|rowBreaks|colBreaks|pageSetup|pageMargins|printOptions|headerFooter|pageSetUpPr|drawing)(?=[\s/>])|(row)(?=[\s/>])[^>]*\s(?:collapsed|customFormat|customHeight|hidden|ht|outlineLevel|thickBot|thickTop)\s*=|(c)(?=[\s/>])[^>]*\ss\s*=)/g;
5656
+ const WORKSHEET_SCAN_PATTERN = /<(?:[A-Za-z_][\w.-]*:)?(?:(cols|f|pane|dataValidation|conditionalFormatting|sheetProtection|protectedRange|rowBreaks|colBreaks|pageSetup|pageMargins|printOptions|headerFooter|pageSetUpPr|drawing|tableParts)(?=[\s/>])|(row)(?=[\s/>])[^>]*\s(?:collapsed|customFormat|customHeight|hidden|ht|outlineLevel|thickBot|thickTop)\s*=|(c)(?=[\s/>])[^>]*\ss\s*=)/g;
5656
5657
  function scanXlsxWorksheetXml(source) {
5657
5658
  let hasDirectCellStyles = false;
5658
5659
  let hasDiagnosticFeatures = false;
@@ -5679,6 +5680,636 @@ function scanXlsxWorksheetXml(source) {
5679
5680
  requiresSheetJsCellStyles
5680
5681
  };
5681
5682
  }
5683
+ const DYNAMIC_FILTERS = new Map([
5684
+ [
5685
+ 'aboveAverage',
5686
+ 'above-average'
5687
+ ],
5688
+ [
5689
+ 'belowAverage',
5690
+ 'below-average'
5691
+ ],
5692
+ [
5693
+ 'tomorrow',
5694
+ 'tomorrow'
5695
+ ],
5696
+ [
5697
+ 'today',
5698
+ 'today'
5699
+ ],
5700
+ [
5701
+ 'yesterday',
5702
+ 'yesterday'
5703
+ ],
5704
+ [
5705
+ 'nextWeek',
5706
+ 'next-week'
5707
+ ],
5708
+ [
5709
+ 'thisWeek',
5710
+ 'this-week'
5711
+ ],
5712
+ [
5713
+ 'lastWeek',
5714
+ 'last-week'
5715
+ ],
5716
+ [
5717
+ 'nextMonth',
5718
+ 'next-month'
5719
+ ],
5720
+ [
5721
+ 'thisMonth',
5722
+ 'this-month'
5723
+ ],
5724
+ [
5725
+ 'lastMonth',
5726
+ 'last-month'
5727
+ ],
5728
+ [
5729
+ 'nextQuarter',
5730
+ 'next-quarter'
5731
+ ],
5732
+ [
5733
+ 'thisQuarter',
5734
+ 'this-quarter'
5735
+ ],
5736
+ [
5737
+ 'lastQuarter',
5738
+ 'last-quarter'
5739
+ ],
5740
+ [
5741
+ 'nextYear',
5742
+ 'next-year'
5743
+ ],
5744
+ [
5745
+ 'thisYear',
5746
+ 'this-year'
5747
+ ],
5748
+ [
5749
+ 'lastYear',
5750
+ 'last-year'
5751
+ ],
5752
+ [
5753
+ 'yearToDate',
5754
+ 'year-to-date'
5755
+ ],
5756
+ [
5757
+ 'Q1',
5758
+ 'quarter-1'
5759
+ ],
5760
+ [
5761
+ 'Q2',
5762
+ 'quarter-2'
5763
+ ],
5764
+ [
5765
+ 'Q3',
5766
+ 'quarter-3'
5767
+ ],
5768
+ [
5769
+ 'Q4',
5770
+ 'quarter-4'
5771
+ ],
5772
+ [
5773
+ 'M1',
5774
+ 'month-1'
5775
+ ],
5776
+ [
5777
+ 'M2',
5778
+ 'month-2'
5779
+ ],
5780
+ [
5781
+ 'M3',
5782
+ 'month-3'
5783
+ ],
5784
+ [
5785
+ 'M4',
5786
+ 'month-4'
5787
+ ],
5788
+ [
5789
+ 'M5',
5790
+ 'month-5'
5791
+ ],
5792
+ [
5793
+ 'M6',
5794
+ 'month-6'
5795
+ ],
5796
+ [
5797
+ 'M7',
5798
+ 'month-7'
5799
+ ],
5800
+ [
5801
+ 'M8',
5802
+ 'month-8'
5803
+ ],
5804
+ [
5805
+ 'M9',
5806
+ 'month-9'
5807
+ ],
5808
+ [
5809
+ 'M10',
5810
+ 'month-10'
5811
+ ],
5812
+ [
5813
+ 'M11',
5814
+ 'month-11'
5815
+ ],
5816
+ [
5817
+ 'M12',
5818
+ 'month-12'
5819
+ ]
5820
+ ]);
5821
+ const OOXML_DYNAMIC_FILTERS = new Map([
5822
+ ...DYNAMIC_FILTERS
5823
+ ].map(([ooxml, model])=>[
5824
+ model,
5825
+ ooxml
5826
+ ]));
5827
+ function readXlsxTableFilters(table, width) {
5828
+ const autoFilter = directChild(table.documentElement, 'autoFilter');
5829
+ if (!autoFilter) return [];
5830
+ const result = [];
5831
+ const observed = new Set();
5832
+ for (const column of directChildren(autoFilter, 'filterColumn')){
5833
+ const index = integerAttribute(column, 'colId');
5834
+ if (null === index || index < 0 || index >= width || observed.has(index)) continue;
5835
+ const criteria = parseFilterCriteria(column);
5836
+ if (criteria) {
5837
+ observed.add(index);
5838
+ result.push({
5839
+ column: index,
5840
+ criteria
5841
+ });
5842
+ }
5843
+ }
5844
+ return result;
5845
+ }
5846
+ function xlsxTableAutoFilterXml(filters, rangeReference, totalsRow) {
5847
+ const filterRange = totalsRow ? tableRangeWithoutFinalRow(rangeReference) : rangeReference;
5848
+ const columns = filters.slice().sort((left, right)=>left.column - right.column).map((filter)=>`<filterColumn colId="${filter.column}">${criteriaXml(filter.criteria)}</filterColumn>`).join('');
5849
+ return `<autoFilter ref="${work_xlsx_table_filters_escapeXml(filterRange)}">${columns}</autoFilter>`;
5850
+ }
5851
+ function parseFilterCriteria(column) {
5852
+ const filters = directChild(column, 'filters');
5853
+ if (filters) {
5854
+ const values = directChildren(filters, 'filter').flatMap((filter)=>{
5855
+ const value = work_ooxml_package_attribute(filter, 'val');
5856
+ return null === value ? [] : [
5857
+ value
5858
+ ];
5859
+ });
5860
+ const includeBlanks = work_xlsx_table_filters_booleanAttribute(filters, 'blank');
5861
+ if (!values.length && includeBlanks) return {
5862
+ type: 'blanks'
5863
+ };
5864
+ if (values.length) return {
5865
+ type: 'values',
5866
+ values,
5867
+ includeBlanks
5868
+ };
5869
+ }
5870
+ const customFilters = directChild(column, 'customFilters');
5871
+ if (customFilters) {
5872
+ const items = directChildren(customFilters, 'customFilter').flatMap((filter)=>{
5873
+ const value = work_ooxml_package_attribute(filter, 'val');
5874
+ return null === value ? [] : [
5875
+ {
5876
+ operator: work_ooxml_package_attribute(filter, 'operator') ?? 'equal',
5877
+ value
5878
+ }
5879
+ ];
5880
+ });
5881
+ const item = 1 === items.length ? items[0] : void 0;
5882
+ if (item) return singleCustomFilter(item);
5883
+ if (2 === items.length) {
5884
+ const [first, second] = items;
5885
+ const conjunction = work_xlsx_table_filters_booleanAttribute(customFilters, 'and');
5886
+ if (conjunction && first?.operator === 'greaterThanOrEqual' && second?.operator === 'lessThanOrEqual') return {
5887
+ type: 'between',
5888
+ lower: first.value,
5889
+ upper: second.value
5890
+ };
5891
+ if (!conjunction && first?.operator === 'lessThan' && second?.operator === 'greaterThan') return {
5892
+ type: 'not-between',
5893
+ lower: first.value,
5894
+ upper: second.value
5895
+ };
5896
+ }
5897
+ }
5898
+ const top = directChild(column, 'top10');
5899
+ if (top) {
5900
+ const value = integerAttribute(top, 'val');
5901
+ if (null === value || value < 1) return null;
5902
+ const upper = '0' !== work_ooxml_package_attribute(top, 'top');
5903
+ const percent = work_xlsx_table_filters_booleanAttribute(top, 'percent');
5904
+ if (percent && value > 100 || !percent && value > 500) return null;
5905
+ if (upper && percent) return {
5906
+ type: 'top-percent',
5907
+ percent: value
5908
+ };
5909
+ if (upper) return {
5910
+ type: 'top',
5911
+ count: value
5912
+ };
5913
+ if (percent) return {
5914
+ type: 'bottom-percent',
5915
+ percent: value
5916
+ };
5917
+ return {
5918
+ type: 'bottom',
5919
+ count: value
5920
+ };
5921
+ }
5922
+ const dynamic = directChild(column, 'dynamicFilter');
5923
+ const kind = dynamic ? DYNAMIC_FILTERS.get(work_ooxml_package_attribute(dynamic, 'type') ?? '') : null;
5924
+ return kind ? {
5925
+ type: 'dynamic',
5926
+ kind
5927
+ } : null;
5928
+ }
5929
+ function singleCustomFilter(item) {
5930
+ if ('notEqual' === item.operator && '' === item.value) return {
5931
+ type: 'non-blanks'
5932
+ };
5933
+ if ('equal' === item.operator) {
5934
+ const wildcard = wildcardCriterion(item.value);
5935
+ return wildcard ?? {
5936
+ type: 'equals',
5937
+ value: unescapeWildcards(item.value)
5938
+ };
5939
+ }
5940
+ if ('notEqual' === item.operator) {
5941
+ const wildcard = wildcardCriterion(item.value);
5942
+ if (!wildcard) return {
5943
+ type: 'not-equals',
5944
+ value: unescapeWildcards(item.value)
5945
+ };
5946
+ return 'contains' === wildcard.type ? {
5947
+ type: 'does-not-contain',
5948
+ value: wildcard.value
5949
+ } : null;
5950
+ }
5951
+ const types = {
5952
+ greaterThan: 'greater-than',
5953
+ greaterThanOrEqual: 'greater-than-or-equal',
5954
+ lessThan: 'less-than',
5955
+ lessThanOrEqual: 'less-than-or-equal'
5956
+ };
5957
+ const type = types[item.operator];
5958
+ return type ? {
5959
+ type,
5960
+ value: item.value
5961
+ } : null;
5962
+ }
5963
+ function wildcardCriterion(source) {
5964
+ const starts = source.startsWith('*');
5965
+ const ends = unescapedFinalAsterisk(source);
5966
+ if (!starts && !ends) return null;
5967
+ const value = unescapeWildcards(source.slice(starts ? 1 : 0, ends ? -1 : void 0));
5968
+ if (starts && ends) return {
5969
+ type: 'contains',
5970
+ value
5971
+ };
5972
+ return starts ? {
5973
+ type: 'ends-with',
5974
+ value
5975
+ } : {
5976
+ type: 'begins-with',
5977
+ value
5978
+ };
5979
+ }
5980
+ function criteriaXml(criteria) {
5981
+ if ('values' === criteria.type) {
5982
+ const blank = criteria.includeBlanks ? ' blank="1"' : '';
5983
+ return `<filters${blank}>${criteria.values.map((value)=>`<filter val="${work_xlsx_table_filters_escapeXml(value)}"/>`).join('')}</filters>`;
5984
+ }
5985
+ if ('blanks' === criteria.type) return '<filters blank="1"/>';
5986
+ if ('non-blanks' === criteria.type) return customFilterXml('notEqual', '');
5987
+ if ('between' === criteria.type) return customFilterPairXml(true, 'greaterThanOrEqual', criteria.lower, 'lessThanOrEqual', criteria.upper);
5988
+ if ('not-between' === criteria.type) return customFilterPairXml(false, 'lessThan', criteria.lower, 'greaterThan', criteria.upper);
5989
+ if ('top' === criteria.type) return topXml(true, false, criteria.count);
5990
+ if ('top-percent' === criteria.type) return topXml(true, true, criteria.percent);
5991
+ if ('bottom' === criteria.type) return topXml(false, false, criteria.count);
5992
+ if ('bottom-percent' === criteria.type) return topXml(false, true, criteria.percent);
5993
+ if ('dynamic' === criteria.type) {
5994
+ const kind = OOXML_DYNAMIC_FILTERS.get(criteria.kind);
5995
+ return kind ? `<dynamicFilter type="${kind}"/>` : '';
5996
+ }
5997
+ const operator = comparisonOperator(criteria.type);
5998
+ const value = 'contains' === criteria.type ? `*${escapeWildcards(criteria.value)}*` : 'does-not-contain' === criteria.type ? `*${escapeWildcards(criteria.value)}*` : 'begins-with' === criteria.type ? `${escapeWildcards(criteria.value)}*` : 'ends-with' === criteria.type ? `*${escapeWildcards(criteria.value)}` : 'equals' === criteria.type || 'not-equals' === criteria.type ? escapeWildcards(criteria.value) : criteria.value;
5999
+ return customFilterXml(operator, value);
6000
+ }
6001
+ function comparisonOperator(type) {
6002
+ const operators = {
6003
+ 'begins-with': 'equal',
6004
+ contains: 'equal',
6005
+ 'does-not-contain': 'notEqual',
6006
+ 'ends-with': 'equal',
6007
+ equals: 'equal',
6008
+ 'greater-than': 'greaterThan',
6009
+ 'greater-than-or-equal': 'greaterThanOrEqual',
6010
+ 'less-than': 'lessThan',
6011
+ 'less-than-or-equal': 'lessThanOrEqual',
6012
+ 'not-equals': 'notEqual'
6013
+ };
6014
+ return operators[type];
6015
+ }
6016
+ function customFilterXml(operator, value) {
6017
+ return `<customFilters><customFilter operator="${operator}" val="${work_xlsx_table_filters_escapeXml(value)}"/></customFilters>`;
6018
+ }
6019
+ function customFilterPairXml(conjunction, firstOperator, firstValue, secondOperator, secondValue) {
6020
+ return `<customFilters and="${conjunction ? 1 : 0}"><customFilter operator="${firstOperator}" val="${work_xlsx_table_filters_escapeXml(firstValue)}"/><customFilter operator="${secondOperator}" val="${work_xlsx_table_filters_escapeXml(secondValue)}"/></customFilters>`;
6021
+ }
6022
+ function topXml(top, percent, value) {
6023
+ return `<top10 percent="${percent ? 1 : 0}" top="${top ? 1 : 0}" val="${value}"/>`;
6024
+ }
6025
+ function tableRangeWithoutFinalRow(reference) {
6026
+ const match = /^([A-Z]+)(\d+):([A-Z]+)(\d+)$/i.exec(reference);
6027
+ if (!match) return reference;
6028
+ const finalRow = Number(match[4]);
6029
+ return `${match[1]}${match[2]}:${match[3]}${Math.max(Number(match[2]), finalRow - 1)}`;
6030
+ }
6031
+ function work_xlsx_table_filters_booleanAttribute(element, name) {
6032
+ return [
6033
+ '1',
6034
+ 'true',
6035
+ 'on'
6036
+ ].includes((work_ooxml_package_attribute(element, name) ?? '').toLocaleLowerCase());
6037
+ }
6038
+ function integerAttribute(element, name) {
6039
+ const source = work_ooxml_package_attribute(element, name);
6040
+ if (null === source) return null;
6041
+ const value = Number(source);
6042
+ return Number.isSafeInteger(value) ? value : null;
6043
+ }
6044
+ function escapeWildcards(value) {
6045
+ return value.replaceAll('~', '~~').replaceAll('*', '~*').replaceAll('?', '~?');
6046
+ }
6047
+ function unescapeWildcards(value) {
6048
+ return value.replace(/~([~*?])/g, '$1');
6049
+ }
6050
+ function unescapedFinalAsterisk(value) {
6051
+ if (!value.endsWith('*')) return false;
6052
+ let escapes = 0;
6053
+ for(let index = value.length - 2; index >= 0 && '~' === value[index]; index -= 1)escapes += 1;
6054
+ return escapes % 2 === 0;
6055
+ }
6056
+ function work_xlsx_table_filters_escapeXml(value) {
6057
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&apos;');
6058
+ }
6059
+ const work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/package/2006/relationships';
6060
+ const TRANSITIONAL_DOCUMENT_RELATIONSHIP_NAMESPACE = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships';
6061
+ const STRICT_DOCUMENT_RELATIONSHIP_NAMESPACE = 'http://purl.oclc.org/ooxml/officeDocument/relationships';
6062
+ const TABLE_CONTENT_TYPE = 'application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml';
6063
+ async function readXlsxWorksheetTables(archive, worksheetPart) {
6064
+ if (!archive.has(worksheetPart)) return [];
6065
+ const worksheet = await archive.xml(worksheetPart);
6066
+ const relationships = await archive.relationships(worksheetPart);
6067
+ const tableParts = directChild(worksheet.documentElement, 'tableParts');
6068
+ if (!tableParts) return [];
6069
+ const tables = [];
6070
+ for (const tablePart of directChildren(tableParts, 'tablePart')){
6071
+ const relationship = relationships.get(work_ooxml_package_attribute(tablePart, 'r:id') ?? '');
6072
+ if (!relationship || 'External' === relationship.targetMode || !relationship.type.endsWith('/table') || !archive.has(relationship.target)) continue;
6073
+ const parsed = parseXlsxTable(await archive.xml(relationship.target), relationship.target);
6074
+ if (parsed) tables.push(parsed);
6075
+ }
6076
+ return tables;
6077
+ }
6078
+ async function patchXlsxSpreadsheetTables(buffer, content) {
6079
+ const archive = await work_ooxml_package_OoxmlPackage.load(buffer);
6080
+ const hasExistingTables = archive.paths('xl/tables/').some((path)=>path.endsWith('.xml'));
6081
+ if (!hasExistingTables && !content.sheets.some((sheet)=>sheet.tables?.length)) return buffer;
6082
+ const worksheetParts = await workbookWorksheetParts(archive);
6083
+ const zip = await jszip.loadAsync(buffer);
6084
+ for (const path of Object.keys(zip.files))if (path.startsWith('xl/tables/')) zip.remove(path);
6085
+ const contentTypeParts = [];
6086
+ const usedTableIds = new Set();
6087
+ let partIndex = 0;
6088
+ for (const sheet of content.sheets){
6089
+ const exportedName = sheet.name.slice(0, 31) || '工作表';
6090
+ const worksheetPart = worksheetParts.get(exportedName);
6091
+ const worksheetEntry = worksheetPart ? zip.file(worksheetPart) : null;
6092
+ if (!worksheetPart || !worksheetEntry) continue;
6093
+ const worksheet = parseXml(await worksheetEntry.async('text'), worksheetPart);
6094
+ for (const tableParts of directChildren(worksheet.documentElement, 'tableParts'))tableParts.remove();
6095
+ const relationshipPath = work_xlsx_tables_relationshipsPartPath(worksheetPart);
6096
+ const relationships = await readRelationshipsDocument(zip, relationshipPath);
6097
+ removeTableRelationships(relationships);
6098
+ const relationshipNamespace = documentRelationshipNamespace(worksheet);
6099
+ const validTables = (sheet.tables ?? []).filter(validExportTable);
6100
+ const tableParts = validTables.length ? worksheet.createElementNS(worksheet.documentElement.namespaceURI, 'tableParts') : null;
6101
+ if (tableParts) tableParts.setAttribute('count', String(validTables.length));
6102
+ for (const table of validTables){
6103
+ partIndex += 1;
6104
+ const tablePath = `xl/tables/table${partIndex}.xml`;
6105
+ const relationshipId = appendRelationship(relationships, `${relationshipNamespace}/table`, `../tables/table${partIndex}.xml`);
6106
+ const tablePart = worksheet.createElementNS(worksheet.documentElement.namespaceURI, 'tablePart');
6107
+ tablePart.setAttributeNS(relationshipNamespace, 'r:id', relationshipId);
6108
+ tableParts?.append(tablePart);
6109
+ const tableId = allocateTableId(table.ooxmlId, usedTableIds);
6110
+ zip.file(tablePath, xlsxTableXml(table, tableId, worksheet.documentElement.namespaceURI ?? 'http://schemas.openxmlformats.org/spreadsheetml/2006/main'));
6111
+ contentTypeParts.push(tablePath);
6112
+ }
6113
+ if (tableParts) {
6114
+ const anchor = directChildren(worksheet.documentElement).find((child)=>'extLst' === child.localName);
6115
+ worksheet.documentElement.insertBefore(tableParts, anchor ?? null);
6116
+ }
6117
+ zip.file(worksheetPart, new XMLSerializer().serializeToString(worksheet));
6118
+ if (directChildren(relationships.documentElement, 'Relationship').length > 0 || zip.file(relationshipPath)) zip.file(relationshipPath, new XMLSerializer().serializeToString(relationships));
6119
+ }
6120
+ await work_xlsx_tables_updateContentTypes(zip, contentTypeParts);
6121
+ return zip.generateAsync({
6122
+ type: 'arraybuffer',
6123
+ compression: 'DEFLATE'
6124
+ });
6125
+ }
6126
+ function parseXlsxTable(document1, partPath) {
6127
+ const root = document1.documentElement;
6128
+ if ('table' !== root.localName) return null;
6129
+ const name = work_ooxml_package_attribute(root, 'name')?.trim();
6130
+ const range = parseSpreadsheetCellRanges(work_ooxml_package_attribute(root, 'ref') ?? '')?.[0];
6131
+ const columnsElement = directChild(root, 'tableColumns');
6132
+ if (!name || !range || !columnsElement) return null;
6133
+ const columns = directChildren(columnsElement, 'tableColumn').flatMap((column)=>{
6134
+ const columnName = work_ooxml_package_attribute(column, 'name');
6135
+ return null === columnName ? [] : [
6136
+ {
6137
+ name: columnName
6138
+ }
6139
+ ];
6140
+ });
6141
+ const width = range.column[1] - range.column[0] + 1;
6142
+ if (columns.length !== width) return null;
6143
+ const ooxmlId = positiveIntegerAttribute(root, 'id');
6144
+ const displayName = work_ooxml_package_attribute(root, 'displayName')?.trim();
6145
+ const headerRow = '0' !== work_ooxml_package_attribute(root, 'headerRowCount');
6146
+ const totalsRow = null !== positiveIntegerAttribute(root, 'totalsRowCount') || work_xlsx_tables_booleanAttribute(root, 'totalsRowShown');
6147
+ const styleInfo = directChild(root, 'tableStyleInfo');
6148
+ const style = parseTableStyle(work_ooxml_package_attribute(styleInfo ?? root, 'name'));
6149
+ const stablePart = partPath.replace(/[^A-Za-z0-9]+/g, '-');
6150
+ return {
6151
+ id: `spreadsheet-table-${stablePart}-${ooxmlId ?? name}`,
6152
+ ...null === ooxmlId ? {} : {
6153
+ ooxmlId
6154
+ },
6155
+ name,
6156
+ ...displayName && displayName !== name ? {
6157
+ displayName
6158
+ } : {},
6159
+ range,
6160
+ columns,
6161
+ filters: headerRow ? readXlsxTableFilters(document1, width) : [],
6162
+ headerRow,
6163
+ totalsRow,
6164
+ style,
6165
+ showFirstColumn: work_xlsx_tables_booleanAttribute(styleInfo, 'showFirstColumn'),
6166
+ showLastColumn: work_xlsx_tables_booleanAttribute(styleInfo, 'showLastColumn'),
6167
+ showRowStripes: work_xlsx_tables_booleanAttribute(styleInfo, 'showRowStripes'),
6168
+ showColumnStripes: work_xlsx_tables_booleanAttribute(styleInfo, 'showColumnStripes')
6169
+ };
6170
+ }
6171
+ function xlsxTableXml(table, tableId, namespace) {
6172
+ const reference = formatSpreadsheetCellRanges([
6173
+ table.range
6174
+ ]);
6175
+ const displayName = table.displayName?.trim() || table.name;
6176
+ const filter = table.headerRow ? xlsxTableAutoFilterXml(table.filters, reference, table.totalsRow) : '';
6177
+ const columns = table.columns.map((column, index)=>`<tableColumn id="${index + 1}" name="${work_xlsx_tables_escapeXml(column.name)}"/>`).join('');
6178
+ const styleName = tableStyleName(table.style);
6179
+ const style = styleName ? `<tableStyleInfo name="${styleName}" showColumnStripes="${booleanToken(table.showColumnStripes)}" showFirstColumn="${booleanToken(table.showFirstColumn)}" showLastColumn="${booleanToken(table.showLastColumn)}" showRowStripes="${booleanToken(table.showRowStripes)}"/>` : '';
6180
+ return [
6181
+ '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>',
6182
+ `<table xmlns="${work_xlsx_tables_escapeXml(namespace)}" id="${tableId}" name="${work_xlsx_tables_escapeXml(table.name)}" displayName="${work_xlsx_tables_escapeXml(displayName)}" ref="${reference}"`,
6183
+ ` headerRowCount="${booleanToken(table.headerRow)}"`,
6184
+ ` totalsRowCount="${booleanToken(table.totalsRow)}"`,
6185
+ ` totalsRowShown="${booleanToken(table.totalsRow)}">`,
6186
+ filter,
6187
+ `<tableColumns count="${table.columns.length}">${columns}</tableColumns>`,
6188
+ style,
6189
+ '</table>'
6190
+ ].join('');
6191
+ }
6192
+ function validExportTable(table) {
6193
+ const range = table.range;
6194
+ const width = range.column[1] - range.column[0] + 1;
6195
+ const height = range.row[1] - range.row[0] + 1;
6196
+ return Number.isSafeInteger(range.row[0]) && Number.isSafeInteger(range.row[1]) && Number.isSafeInteger(range.column[0]) && Number.isSafeInteger(range.column[1]) && range.row[0] >= 0 && range.column[0] >= 0 && width > 0 && height > Number(table.headerRow) + Number(table.totalsRow) && table.columns.length === width && Boolean(table.name.trim()) && table.columns.every((column)=>Boolean(column.name.trim())) && null !== tableStyleName(table.style);
6197
+ }
6198
+ function parseTableStyle(value) {
6199
+ if (!value) return {
6200
+ family: 'none'
6201
+ };
6202
+ const match = /^TableStyle(Light|Medium|Dark)(\d+)$/.exec(value);
6203
+ if (!match) return {
6204
+ family: 'none'
6205
+ };
6206
+ const family = match[1]?.toLocaleLowerCase();
6207
+ const number = Number(match[2]);
6208
+ const maximum = 'light' === family ? 21 : 'medium' === family ? 28 : 11;
6209
+ return number >= 1 && number <= maximum ? {
6210
+ family,
6211
+ number
6212
+ } : {
6213
+ family: 'none'
6214
+ };
6215
+ }
6216
+ function tableStyleName(style) {
6217
+ if ('none' === style.family) return '';
6218
+ const maximum = 'light' === style.family ? 21 : 'medium' === style.family ? 28 : 11;
6219
+ if (!Number.isInteger(style.number) || style.number < 1 || style.number > maximum) return null;
6220
+ const family = `${style.family.charAt(0).toUpperCase()}${style.family.slice(1)}`;
6221
+ return `TableStyle${family}${style.number}`;
6222
+ }
6223
+ async function workbookWorksheetParts(archive) {
6224
+ if (!archive.has('xl/workbook.xml')) return new Map();
6225
+ const workbook = await archive.xml('xl/workbook.xml');
6226
+ const relationships = await archive.relationships('xl/workbook.xml');
6227
+ const parts = new Map();
6228
+ for (const sheet of firstDescendant(workbook, 'sheets')?.children ?? []){
6229
+ if (!(sheet instanceof Element) || 'sheet' !== sheet.localName) continue;
6230
+ const name = work_ooxml_package_attribute(sheet, 'name');
6231
+ const relationship = relationships.get(work_ooxml_package_attribute(sheet, 'r:id') ?? '');
6232
+ if (name && relationship?.type.endsWith('/worksheet')) parts.set(name, relationship.target);
6233
+ }
6234
+ return parts;
6235
+ }
6236
+ async function readRelationshipsDocument(zip, partPath) {
6237
+ const entry = zip.file(partPath);
6238
+ return entry ? parseXml(await entry.async('text'), partPath) : parseXml(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="${work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, partPath);
6239
+ }
6240
+ function appendRelationship(document1, type, target) {
6241
+ const id = work_xlsx_tables_nextRelationshipId(document1);
6242
+ const relationship = document1.createElementNS(document1.documentElement.namespaceURI ?? work_xlsx_tables_PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
6243
+ relationship.setAttribute('Id', id);
6244
+ relationship.setAttribute('Type', type);
6245
+ relationship.setAttribute('Target', target);
6246
+ document1.documentElement.append(relationship);
6247
+ return id;
6248
+ }
6249
+ function removeTableRelationships(document1) {
6250
+ for (const relationship of directChildren(document1.documentElement, 'Relationship'))if ((work_ooxml_package_attribute(relationship, 'Type') ?? '').endsWith('/table')) relationship.remove();
6251
+ }
6252
+ function work_xlsx_tables_nextRelationshipId(document1) {
6253
+ const used = new Set(directChildren(document1.documentElement, 'Relationship').map((item)=>work_ooxml_package_attribute(item, 'Id')));
6254
+ for(let index = 1; index < 1000000; index += 1){
6255
+ const id = `rId${index}`;
6256
+ if (!used.has(id)) return id;
6257
+ }
6258
+ return `rId${Date.now()}`;
6259
+ }
6260
+ async function work_xlsx_tables_updateContentTypes(zip, tableParts) {
6261
+ const entry = zip.file('[Content_Types].xml');
6262
+ if (!entry) return;
6263
+ const document1 = parseXml(await entry.async('text'), '[Content_Types].xml');
6264
+ for (const override of directChildren(document1.documentElement, 'Override'))if (work_ooxml_package_attribute(override, 'ContentType') === TABLE_CONTENT_TYPE) override.remove();
6265
+ const namespace = document1.documentElement.namespaceURI;
6266
+ for (const path of tableParts){
6267
+ const override = document1.createElementNS(namespace, 'Override');
6268
+ override.setAttribute('PartName', `/${path}`);
6269
+ override.setAttribute('ContentType', TABLE_CONTENT_TYPE);
6270
+ document1.documentElement.append(override);
6271
+ }
6272
+ zip.file('[Content_Types].xml', new XMLSerializer().serializeToString(document1));
6273
+ }
6274
+ function work_xlsx_tables_relationshipsPartPath(sourcePart) {
6275
+ const segments = sourcePart.split('/');
6276
+ const name = segments.pop() ?? '';
6277
+ return [
6278
+ ...segments,
6279
+ '_rels',
6280
+ `${name}.rels`
6281
+ ].join('/');
6282
+ }
6283
+ function documentRelationshipNamespace(document1) {
6284
+ return document1.documentElement.namespaceURI?.includes('purl.oclc.org') ? STRICT_DOCUMENT_RELATIONSHIP_NAMESPACE : TRANSITIONAL_DOCUMENT_RELATIONSHIP_NAMESPACE;
6285
+ }
6286
+ function allocateTableId(requested, used) {
6287
+ if (requested && Number.isSafeInteger(requested) && requested > 0 && !used.has(requested)) {
6288
+ used.add(requested);
6289
+ return requested;
6290
+ }
6291
+ let candidate = 1;
6292
+ while(used.has(candidate))candidate += 1;
6293
+ used.add(candidate);
6294
+ return candidate;
6295
+ }
6296
+ function positiveIntegerAttribute(element, name) {
6297
+ const value = Number(work_ooxml_package_attribute(element, name));
6298
+ return Number.isSafeInteger(value) && value > 0 ? value : null;
6299
+ }
6300
+ function work_xlsx_tables_booleanAttribute(element, name) {
6301
+ return element ? [
6302
+ '1',
6303
+ 'true',
6304
+ 'on'
6305
+ ].includes((work_ooxml_package_attribute(element, name) ?? '').toLocaleLowerCase()) : false;
6306
+ }
6307
+ function booleanToken(value) {
6308
+ return value ? '1' : '0';
6309
+ }
6310
+ function work_xlsx_tables_escapeXml(value) {
6311
+ return value.replaceAll('&', '&amp;').replaceAll('<', '&lt;').replaceAll('>', '&gt;').replaceAll('"', '&quot;').replaceAll("'", '&apos;');
6312
+ }
5682
6313
  async function readXlsxSheetFeaturesFromPackage(archive, worksheetScans) {
5683
6314
  const workbook = archive.has('xl/workbook.xml') ? await archive.xml('xl/workbook.xml') : null;
5684
6315
  const worksheetParts = await work_xlsx_interop_readWorksheetParts(archive, workbook);
@@ -5713,7 +6344,8 @@ async function readXlsxSheetFeaturesFromPackage(archive, worksheetScans) {
5713
6344
  pageBreaks: readXlsxManualPageBreaks(document1),
5714
6345
  pageSetup: readXlsxPageSetup(document1),
5715
6346
  images: await readXlsxWorksheetImages(archive, partPath, document1, imageBudget),
5716
- charts: await readXlsxWorksheetCharts(archive, partPath, document1)
6347
+ charts: await readXlsxWorksheetCharts(archive, partPath, document1),
6348
+ tables: await readXlsxWorksheetTables(archive, partPath)
5717
6349
  });
5718
6350
  }
5719
6351
  return features;
@@ -5731,7 +6363,8 @@ function emptyXlsxSheetFeatures() {
5731
6363
  columns: []
5732
6364
  },
5733
6365
  images: [],
5734
- charts: []
6366
+ charts: [],
6367
+ tables: []
5735
6368
  };
5736
6369
  }
5737
6370
  async function patchXlsxSheetFeatures(buffer, content) {
@@ -6360,7 +6993,7 @@ const PIVOT_CACHE_RECORDS_CONTENT_TYPE = 'application/vnd.openxmlformats-officed
6360
6993
  async function patchXlsxPivotTables(buffer, content) {
6361
6994
  if (!content.sheets.some((sheet)=>sheet.pivotTables?.length)) return buffer;
6362
6995
  const archive = await work_ooxml_package_OoxmlPackage.load(buffer);
6363
- const worksheetParts = await workbookWorksheetParts(archive);
6996
+ const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
6364
6997
  const candidates = content.sheets.flatMap((ownerSheet)=>(ownerSheet.pivotTables ?? []).flatMap((pivot)=>{
6365
6998
  if (!ownerSheet.id || !spreadsheetPivotValidation(content, ownerSheet.id, pivot).valid) return [];
6366
6999
  const worksheetPart = worksheetParts.get(ownerSheet.name.slice(0, 31) || '工作表');
@@ -6394,17 +7027,17 @@ async function patchXlsxPivotTables(buffer, content) {
6394
7027
  const pivotTablePath = `xl/pivotTables/pivotTable${partIndex}.xml`;
6395
7028
  const pivotCacheDefinitionPath = `xl/pivotCache/pivotCacheDefinition${partIndex}.xml`;
6396
7029
  const pivotCacheRecordsPath = `xl/pivotCache/pivotCacheRecords${partIndex}.xml`;
6397
- const workbookRelationshipId = appendRelationship(workbookRelationships, PIVOT_CACHE_DEFINITION_RELATIONSHIP, `pivotCache/pivotCacheDefinition${partIndex}.xml`);
7030
+ const workbookRelationshipId = work_xlsx_pivots_appendRelationship(workbookRelationships, PIVOT_CACHE_DEFINITION_RELATIONSHIP, `pivotCache/pivotCacheDefinition${partIndex}.xml`);
6398
7031
  const pivotCache = workbook.createElementNS(workbook.documentElement.namespaceURI, 'pivotCache');
6399
7032
  pivotCache.setAttribute('cacheId', String(cacheId));
6400
7033
  pivotCache.setAttributeNS(DOCUMENT_RELATIONSHIP_NAMESPACE, 'r:id', workbookRelationshipId);
6401
7034
  pivotCaches.append(pivotCache);
6402
- const worksheetRelationshipDocument = worksheetRelationships.get(candidate.worksheetPart) ?? await readRelationshipsDocument(zip, work_xlsx_pivots_relationshipsPartPath(candidate.worksheetPart));
7035
+ const worksheetRelationshipDocument = worksheetRelationships.get(candidate.worksheetPart) ?? await work_xlsx_pivots_readRelationshipsDocument(zip, work_xlsx_pivots_relationshipsPartPath(candidate.worksheetPart));
6403
7036
  if (!worksheetRelationships.has(candidate.worksheetPart)) {
6404
7037
  removeRelationships(worksheetRelationshipDocument, '/pivotTable');
6405
7038
  worksheetRelationships.set(candidate.worksheetPart, worksheetRelationshipDocument);
6406
7039
  }
6407
- appendRelationship(worksheetRelationshipDocument, PIVOT_TABLE_RELATIONSHIP, `../pivotTables/pivotTable${partIndex}.xml`);
7040
+ work_xlsx_pivots_appendRelationship(worksheetRelationshipDocument, PIVOT_TABLE_RELATIONSHIP, `../pivotTables/pivotTable${partIndex}.xml`);
6408
7041
  zip.file(pivotTablePath, parts.table);
6409
7042
  zip.file(pivotCacheDefinitionPath, parts.cacheDefinition);
6410
7043
  zip.file(pivotCacheRecordsPath, parts.cacheRecords);
@@ -6455,11 +7088,11 @@ async function inspectXlsxPivotTables(archive) {
6455
7088
  const workbookRelationships = await archive.relationships('xl/workbook.xml');
6456
7089
  const cacheById = new Map();
6457
7090
  for (const cache of directChildren(firstDescendant(workbook, 'pivotCaches') ?? workbook.documentElement, 'pivotCache')){
6458
- const cacheId = integerAttribute(cache, 'cacheId');
7091
+ const cacheId = work_xlsx_pivots_integerAttribute(cache, 'cacheId');
6459
7092
  const relationship = workbookRelationships.get(work_ooxml_package_attribute(cache, 'r:id') ?? work_ooxml_package_attribute(cache, 'id') ?? '');
6460
7093
  if (null !== cacheId && relationship && archive.has(relationship.target)) cacheById.set(cacheId, parsePivotCache(await archive.xml(relationship.target)));
6461
7094
  }
6462
- const worksheetParts = await workbookWorksheetParts(archive);
7095
+ const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
6463
7096
  const tables = [];
6464
7097
  const unsupported = [];
6465
7098
  let detected = 0;
@@ -6545,7 +7178,7 @@ function applyImportedXlsxPivotTables(content, imported) {
6545
7178
  sheets
6546
7179
  };
6547
7180
  }
6548
- async function workbookWorksheetParts(archive) {
7181
+ async function work_xlsx_pivots_workbookWorksheetParts(archive) {
6549
7182
  if (!archive.has('xl/workbook.xml')) return new Map();
6550
7183
  const workbook = await archive.xml('xl/workbook.xml');
6551
7184
  const relationships = await archive.relationships('xl/workbook.xml');
@@ -6618,7 +7251,7 @@ function parsePivotReportFilters(root, cache, location) {
6618
7251
  if (!pageFields) return {
6619
7252
  reportFilters: []
6620
7253
  };
6621
- const pageWrap = integerAttribute(root, 'pageWrap') ?? 0;
7254
+ const pageWrap = work_xlsx_pivots_integerAttribute(root, 'pageWrap') ?? 0;
6622
7255
  if (pageWrap > 0 || work_xlsx_pivots_booleanAttribute(root, 'pageOverThenDown')) return {
6623
7256
  unsupported: {
6624
7257
  code: 'xlsx.pivots.report-filter-layout',
@@ -6629,7 +7262,7 @@ function parsePivotReportFilters(root, cache, location) {
6629
7262
  const pivotFields = directChildren(directChild(root, 'pivotFields') ?? root, 'pivotField');
6630
7263
  const reportFilters = [];
6631
7264
  for (const pageField of directChildren(pageFields, 'pageField')){
6632
- const fieldIndex = integerAttribute(pageField, 'fld');
7265
+ const fieldIndex = work_xlsx_pivots_integerAttribute(pageField, 'fld');
6633
7266
  const pivotField = null === fieldIndex ? void 0 : pivotFields[fieldIndex];
6634
7267
  if (null === fieldIndex || !pivotField || !cache.fields[fieldIndex]) return {
6635
7268
  unsupported: {
@@ -6646,7 +7279,7 @@ function parsePivotReportFilters(root, cache, location) {
6646
7279
  location
6647
7280
  }
6648
7281
  };
6649
- const itemIndex = integerAttribute(pageField, 'item');
7282
+ const itemIndex = work_xlsx_pivots_integerAttribute(pageField, 'item');
6650
7283
  if (null === itemIndex) {
6651
7284
  reportFilters.push({
6652
7285
  fieldIndex
@@ -6667,7 +7300,7 @@ function parsePivotReportFilters(root, cache, location) {
6667
7300
  });
6668
7301
  continue;
6669
7302
  }
6670
- const sharedItemIndex = integerAttribute(pivotItem, 'x');
7303
+ const sharedItemIndex = work_xlsx_pivots_integerAttribute(pivotItem, 'x');
6671
7304
  const sharedItems = cache.fieldItems[fieldIndex] ?? [];
6672
7305
  if (null === sharedItemIndex || sharedItemIndex < 0 || sharedItemIndex >= sharedItems.length) return {
6673
7306
  unsupported: {
@@ -6689,7 +7322,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6689
7322
  const root = document1.documentElement;
6690
7323
  const name = work_ooxml_package_attribute(root, 'name')?.trim() || 'PivotTable';
6691
7324
  const locationLabel = destinationSheetName ? `${destinationSheetName} · ${name}` : name;
6692
- const cacheId = integerAttribute(root, 'cacheId');
7325
+ const cacheId = work_xlsx_pivots_integerAttribute(root, 'cacheId');
6693
7326
  const cache = null === cacheId ? void 0 : cacheById.get(cacheId);
6694
7327
  if (!cache || cache.unsupported || !cache.sourceSheetName || !cache.sourceReference) return {
6695
7328
  unsupported: {
@@ -6721,7 +7354,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6721
7354
  };
6722
7355
  const values = [];
6723
7356
  for (const dataField of directChildren(directChild(root, 'dataFields') ?? root, 'dataField')){
6724
- const fieldIndex = integerAttribute(dataField, 'fld');
7357
+ const fieldIndex = work_xlsx_pivots_integerAttribute(dataField, 'fld');
6725
7358
  const aggregation = workPivotAggregation(work_ooxml_package_attribute(dataField, 'subtotal'));
6726
7359
  if (null === fieldIndex || !aggregation || !cache.fields[fieldIndex]) return {
6727
7360
  unsupported: {
@@ -6809,17 +7442,17 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6809
7442
  function readPivotFieldIndexes(parent) {
6810
7443
  if (!parent) return [];
6811
7444
  return directChildren(parent, 'field').flatMap((field)=>{
6812
- const index = integerAttribute(field, 'x');
7445
+ const index = work_xlsx_pivots_integerAttribute(field, 'x');
6813
7446
  return null === index ? [] : [
6814
7447
  index
6815
7448
  ];
6816
7449
  });
6817
7450
  }
6818
- async function readRelationshipsDocument(zip, path) {
7451
+ async function work_xlsx_pivots_readRelationshipsDocument(zip, path) {
6819
7452
  const entry = zip.file(path);
6820
7453
  return entry ? parseXml(await entry.async('text'), path) : parseXml(`<?xml version="1.0" encoding="UTF-8" standalone="yes"?><Relationships xmlns="${work_xlsx_pivots_PACKAGE_RELATIONSHIP_NAMESPACE}"/>`, path);
6821
7454
  }
6822
- function appendRelationship(document1, type, target) {
7455
+ function work_xlsx_pivots_appendRelationship(document1, type, target) {
6823
7456
  const id = work_xlsx_pivots_nextRelationshipId(document1);
6824
7457
  const relationship = document1.createElementNS(work_xlsx_pivots_PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
6825
7458
  relationship.setAttribute('Id', id);
@@ -6887,7 +7520,7 @@ function work_xlsx_pivots_relationshipsPartPath(sourcePart) {
6887
7520
  `${name}.rels`
6888
7521
  ].join('/');
6889
7522
  }
6890
- function integerAttribute(element, name) {
7523
+ function work_xlsx_pivots_integerAttribute(element, name) {
6891
7524
  const source = work_ooxml_package_attribute(element, name);
6892
7525
  if (null === source || !source.trim()) return null;
6893
7526
  const value = Number(source);
@@ -6922,7 +7555,8 @@ async function createWorkSpreadsheetBlob(artifact) {
6922
7555
  compression: true
6923
7556
  });
6924
7557
  const withFeatures = await patchXlsxSheetFeatures(bytes, content);
6925
- const withDrawings = await patchXlsxWorksheetDrawings(withFeatures, content);
7558
+ const withTables = await patchXlsxSpreadsheetTables(withFeatures, content);
7559
+ const withDrawings = await patchXlsxWorksheetDrawings(withTables, content);
6926
7560
  const withFormulas = await patchXlsxFormulaFeatures(withDrawings, content);
6927
7561
  const output = await patchXlsxPivotTables(withFormulas, content);
6928
7562
  return new Blob([
@@ -7753,6 +8387,7 @@ async function importWorkSpreadsheetFile(file, extension, context) {
7753
8387
  luckysheet_conditionformat_save: features?.conditionalFormats.length ? features.conditionalFormats : void 0,
7754
8388
  images: features?.images.length ? xlsxWorksheetImagesToSheet(features.images, config) : void 0,
7755
8389
  charts: features?.charts.length ? xlsxWorksheetChartsToSheet(features.charts, config) : void 0,
8390
+ tables: features?.tables.length ? features.tables : void 0,
7756
8391
  formulaMetadata
7757
8392
  });
7758
8393
  await context.controller.checkpoint('parsing', sheetProgressStart + sheetProgressSize);