@a3s-lab/office 0.14.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 (46) hide show
  1. package/COLLABORATION_ROADMAP.md +15 -5
  2. package/README.md +34 -1
  3. package/dist/0~6090.js +7 -8
  4. package/dist/0~spreadsheet-editor.js +6869 -3427
  5. package/dist/0~work-office-diagnostics.js +1 -1
  6. package/dist/{4476.js → 2180.js} +404 -35
  7. package/dist/4104.js +698 -41
  8. package/dist/5184.js +1 -1
  9. package/dist/8715.js +156 -156
  10. package/dist/core.js +1 -1
  11. package/dist/index.js +1 -1
  12. package/dist/internal/collaboration/office-spreadsheet-collaboration-records.d.ts +2 -0
  13. package/dist/internal/collaboration/office-spreadsheet-collaboration-validation-support.d.ts +6 -0
  14. package/dist/internal/features/work/editors/spreadsheet-auto-filter.d.ts +1 -0
  15. package/dist/internal/features/work/editors/spreadsheet-command-catalog.d.ts +44 -1
  16. package/dist/internal/features/work/editors/spreadsheet-command-controller.d.ts +28 -0
  17. package/dist/internal/features/work/editors/spreadsheet-data-validation-command.d.ts +3 -0
  18. package/dist/internal/features/work/editors/spreadsheet-data-validation-dialog.d.ts +9 -0
  19. package/dist/internal/features/work/editors/spreadsheet-data-validation.d.ts +50 -0
  20. package/dist/internal/features/work/editors/spreadsheet-editor-ribbon.d.ts +4 -2
  21. package/dist/internal/features/work/editors/spreadsheet-editor-support.d.ts +1 -0
  22. package/dist/internal/features/work/editors/spreadsheet-hyperlink-command.d.ts +3 -0
  23. package/dist/internal/features/work/editors/spreadsheet-hyperlink-dialog.d.ts +9 -0
  24. package/dist/internal/features/work/editors/spreadsheet-hyperlink.d.ts +44 -0
  25. package/dist/internal/features/work/editors/spreadsheet-table-command.d.ts +3 -0
  26. package/dist/internal/features/work/editors/spreadsheet-table-conversion.d.ts +7 -0
  27. package/dist/internal/features/work/editors/spreadsheet-table-dialog.d.ts +8 -0
  28. package/dist/internal/features/work/editors/spreadsheet-table-limits.d.ts +1 -0
  29. package/dist/internal/features/work/editors/spreadsheet-table-reconciliation.d.ts +21 -0
  30. package/dist/internal/features/work/editors/spreadsheet-table-render.d.ts +16 -0
  31. package/dist/internal/features/work/editors/spreadsheet-table-ribbon.d.ts +8 -0
  32. package/dist/internal/features/work/editors/spreadsheet-table-style.d.ts +31 -0
  33. package/dist/internal/features/work/editors/spreadsheet-table.d.ts +55 -0
  34. package/dist/internal/features/work/editors/use-spreadsheet-data-validation.d.ts +23 -0
  35. package/dist/internal/features/work/editors/use-spreadsheet-hyperlink.d.ts +24 -0
  36. package/dist/internal/features/work/editors/use-spreadsheet-table.d.ts +23 -0
  37. package/dist/internal/features/work/work-spreadsheet-data-validation.d.ts +2 -0
  38. package/dist/internal/features/work/work-types.d.ts +100 -0
  39. package/dist/internal/features/work/work-xlsx-interop.d.ts +2 -0
  40. package/dist/internal/features/work/work-xlsx-table-filters.d.ts +3 -0
  41. package/dist/internal/features/work/work-xlsx-tables.d.ts +4 -0
  42. package/dist/office-kernel.wasm +0 -0
  43. package/dist/styles.css +486 -0
  44. package/dist/work-spreadsheet-package-scan.worker.js +3 -2
  45. package/docs/latest/en/browser-editor-architecture.md +43 -0
  46. package/package.json +12 -3
package/dist/4104.js CHANGED
@@ -5,7 +5,7 @@ import { OFFICE_COLLABORATION_PROTOCOL as WORK_OFFICE_COLLABORATION_PROTOCOL, Of
5
5
  import { contentTypeForPart, directChildren, bytesToDataUrl, OoxmlPackage as work_ooxml_package_OoxmlPackage, parseXml, firstDescendant, xmlNamespacePrefix, descendants, directChild, createArtifact as createWorkArtifact, xmlContainsAnyElement, createOfficeId as createWorkId, attribute as work_ooxml_package_attribute } from "./5184.js";
6
6
  import { mountWorkLiveDocumentCapture, materializeWorkDocumentContent as work_document_model_codec_materializeWorkDocumentContent, documentPageSurfaceGeometryForElement, createWorkDocumentModel, documentContentLayoutProperties, documentModelForContent, createWorkDocumentExtensions, positionWorkLiveDocumentCapture } from "./6282.js";
7
7
  import { normalizeWorkSpreadsheetDataLabels, workSpreadsheetChartSupportsGrouping, normalizeSpreadsheetPrintArea, normalizeWorkSpreadsheetChartLegendPosition, formatSpreadsheetCellRanges, spreadsheetCellAddress, normalizeWorkSpreadsheetChartSmoothLines, spreadsheetFormulaRangeForCell, normalizeWorkSpreadsheetChartColor, readXlsxDrawingAnchor, sparseArrayEntries, qualifySpreadsheetRange, normalizeWorkSpreadsheetBubbleScale, normalizeWorkSpreadsheetChartSeriesStyle, normalizeSpreadsheetPrintTitleRows, normalizeSpreadsheetPrintTitleColumns, spreadsheetPivotFilterValueKey, normalizeWorkSpreadsheetErrorBars, normalizeWorkSpreadsheetBubbleSizeRepresents, workSpreadsheetChartSupportsTrendlines, stripSpreadsheetSheetQualifier, normalizeWorkSpreadsheetChartLegendOverlay, normalizeWorkSpreadsheetChartGapWidth, normalizeWorkSpreadsheetChartGrouping, workSpreadsheetChartSupportsBarSpacing, workSpreadsheetChartSupportsSmoothLines, workSpreadsheetChartGroupingIsStacked, xlsxDrawingAnchorToBounds, xlsxTwoCellAnchorMarkers, workSpreadsheetChartSupportsErrorBars, sparseMatrixColumnCount, refreshSpreadsheetPivotTables, normalizeWorkSpreadsheetChartAxisGroup, isValidSpreadsheetDefinedName, normalizeWorkSpreadsheetScatterStyle, workSpreadsheetChartAxisDefaultLabelPosition, spreadsheetPivotValidation, resolveSpreadsheetChart, parseSpreadsheetCellRanges, workSpreadsheetChartAxisIsCategoryAxis, spreadsheetPivotFields, normalizeWorkSpreadsheetDoughnutHoleSize, normalizeWorkSpreadsheetChartAxes, parseSpreadsheetPrintTitles, spreadsheetFormulaRangeConflict, spreadsheetFormulaForXlsx, editableSpreadsheetFormula, workSpreadsheetChartUsesNumericXAxis, normalizeWorkSpreadsheetChartOverlap, workSpreadsheetChartSupportsAxes, workSpreadsheetChartAxisShowsMajorGridlinesByDefault, normalizeWorkSpreadsheetCombinationSeriesType, effectiveSpreadsheetCalculationSettings, normalizeWorkSpreadsheetTrendline, normalizeWorkSpreadsheetRadarStyle } from "./8715.js";
8
- import { freezeImportedSpreadsheetCell, editableRangeRequiresCredentials, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, normalizeSpreadsheetConditionalVisualOptions, normalizeSpreadsheetPaperSize, normalizeSheetProtectionAuthority, importedSheetProtectionAuthority, defaultSpreadsheetColorScaleThresholds, sheetHasProtectionState, spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalComparisonOperator, registerImportedSpreadsheetMatrix, defaultSpreadsheetConditionalIconThresholds, DEFAULT_PROTECTION_HINT, isSpreadsheetConditionalIconSetName, spreadsheetConditionalThresholdsEqual, spreadsheetConditionalIconSetCount } from "./4476.js";
8
+ import { freezeImportedSpreadsheetCell, editableRangeRequiresCredentials, spreadsheetDateValidationFormula, normalizeSpreadsheetConditionalIconSetFormat, defaultSpreadsheetDataBarOptions, normalizeSpreadsheetConditionalVisualOptions, normalizeSpreadsheetPaperSize, normalizeSheetProtectionAuthority, importedSheetProtectionAuthority, defaultSpreadsheetColorScaleThresholds, sheetHasProtectionState, spreadsheetConditionalComparisonNeedsUpperValue, isSpreadsheetConditionalComparisonOperator, registerImportedSpreadsheetMatrix, defaultSpreadsheetConditionalIconThresholds, DEFAULT_PROTECTION_HINT, normalizeSpreadsheetDateValidationBoundary, isSpreadsheetConditionalIconSetName, spreadsheetConditionalThresholdsEqual, spreadsheetConditionalIconSetCount } from "./2180.js";
9
9
  import { WorkFileImportController, materializeWorkFileSource } from "./9356.js";
10
10
  import "./2591.js";
11
11
  import "./3818.js";
@@ -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,8 +5680,640 @@ 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
- const worksheetParts = await work_xlsx_interop_readWorksheetParts(archive);
6314
+ const workbook = archive.has('xl/workbook.xml') ? await archive.xml('xl/workbook.xml') : null;
6315
+ const worksheetParts = await work_xlsx_interop_readWorksheetParts(archive, workbook);
6316
+ const uses1904DateSystem = xlsxUses1904DateSystem(workbook);
5684
6317
  const styles = archive.has('xl/styles.xml') ? await archive.xml('xl/styles.xml') : null;
5685
6318
  const theme = archive.has('xl/theme/theme1.xml') ? await archive.xml('xl/theme/theme1.xml') : null;
5686
6319
  const differentialFormats = readXlsxDifferentialFormats(styles);
@@ -5705,13 +6338,14 @@ async function readXlsxSheetFeaturesFromPackage(archive, worksheetScans) {
5705
6338
  features.set(sheetName, {
5706
6339
  directCellStyles: readXlsxDirectCellStyles(document1, styles, theme),
5707
6340
  frozen: parseFrozenPane(document1) ?? void 0,
5708
- validations: parseDataValidations(document1),
6341
+ validations: parseDataValidations(document1, uses1904DateSystem),
5709
6342
  conditionalFormats: readXlsxConditionalFormats(document1, differentialFormats),
5710
6343
  protection: readXlsxProtection(document1, styles),
5711
6344
  pageBreaks: readXlsxManualPageBreaks(document1),
5712
6345
  pageSetup: readXlsxPageSetup(document1),
5713
6346
  images: await readXlsxWorksheetImages(archive, partPath, document1, imageBudget),
5714
- charts: await readXlsxWorksheetCharts(archive, partPath, document1)
6347
+ charts: await readXlsxWorksheetCharts(archive, partPath, document1),
6348
+ tables: await readXlsxWorksheetTables(archive, partPath)
5715
6349
  });
5716
6350
  }
5717
6351
  return features;
@@ -5729,7 +6363,8 @@ function emptyXlsxSheetFeatures() {
5729
6363
  columns: []
5730
6364
  },
5731
6365
  images: [],
5732
- charts: []
6366
+ charts: [],
6367
+ tables: []
5733
6368
  };
5734
6369
  }
5735
6370
  async function patchXlsxSheetFeatures(buffer, content) {
@@ -5760,7 +6395,7 @@ async function patchXlsxSheetFeatures(buffer, content) {
5760
6395
  if (!partPath || !entry) continue;
5761
6396
  const document1 = parseXml(await entry.async('text'), partPath);
5762
6397
  if (sheet.frozen) writeFrozenPane(document1, sheet.frozen);
5763
- writeDataValidations(document1, sheet.dataVerification, sheet.dataValidationRanges);
6398
+ writeDataValidations(document1, sheet.dataVerification, sheet.dataValidationRanges, new Set((content.namedRanges ?? []).filter((namedRange)=>!namedRange.scopeSheetId || namedRange.scopeSheetId === sheet.id).map((namedRange)=>namedRange.name.trim().toLocaleLowerCase())));
5764
6399
  writeXlsxConditionalFormats(document1, sheet.luckysheet_conditionformat_save, differentialFormats);
5765
6400
  if (directCellStyles) writeXlsxDirectCellStyles(document1, sheet, directCellStyles);
5766
6401
  writeXlsxProtection(document1, sheet, cellProtection);
@@ -5774,9 +6409,9 @@ async function patchXlsxSheetFeatures(buffer, content) {
5774
6409
  compression: 'DEFLATE'
5775
6410
  });
5776
6411
  }
5777
- async function work_xlsx_interop_readWorksheetParts(archive) {
6412
+ async function work_xlsx_interop_readWorksheetParts(archive, workbookDocument) {
5778
6413
  if (!archive.has('xl/workbook.xml')) return new Map();
5779
- const workbook = await archive.xml('xl/workbook.xml');
6414
+ const workbook = workbookDocument ?? await archive.xml('xl/workbook.xml');
5780
6415
  const relationships = await archive.relationships('xl/workbook.xml');
5781
6416
  const parts = new Map();
5782
6417
  for (const sheet of firstDescendant(workbook, 'sheets')?.children ?? []){
@@ -5802,7 +6437,7 @@ function parseFrozenPane(document1) {
5802
6437
  }
5803
6438
  };
5804
6439
  }
5805
- function parseDataValidations(document1) {
6440
+ function parseDataValidations(document1, uses1904DateSystem) {
5806
6441
  const validations = firstDescendant(document1, 'dataValidations');
5807
6442
  if (!validations) return [];
5808
6443
  return directChildren(validations, 'dataValidation').flatMap((element)=>{
@@ -5813,10 +6448,10 @@ function parseDataValidations(document1) {
5813
6448
  const formula2 = firstDescendant(element, 'formula2')?.textContent?.trim() ?? '';
5814
6449
  const item = {
5815
6450
  type,
5816
- type2: fortuneValidationOperator(work_ooxml_package_attribute(element, 'operator')),
6451
+ type2: fortuneValidationOperator(work_ooxml_package_attribute(element, 'operator'), 'date' === type),
5817
6452
  rangeTxt: references.join(','),
5818
- value1: 'dropdown' === type ? parseListFormula(formula1) : formula1,
5819
- value2: formula2,
6453
+ value1: 'dropdown' === type ? parseListFormula(formula1) : 'date' === type ? normalizeSpreadsheetDateValidationBoundary(formula1, uses1904DateSystem) ?? formula1 : formula1,
6454
+ value2: 'date' === type ? normalizeSpreadsheetDateValidationBoundary(formula2, uses1904DateSystem) ?? formula2 : formula2,
5820
6455
  validity: '',
5821
6456
  remote: false,
5822
6457
  prohibitInput: work_xlsx_interop_booleanAttribute(element, 'showErrorMessage'),
@@ -5832,7 +6467,7 @@ function parseDataValidations(document1) {
5832
6467
  ];
5833
6468
  });
5834
6469
  }
5835
- function writeDataValidations(document1, source, compact) {
6470
+ function writeDataValidations(document1, source, compact, namedListSources) {
5836
6471
  const root = document1.documentElement;
5837
6472
  for (const existing of directChildren(root, 'dataValidations'))existing.remove();
5838
6473
  const grouped = groupDataValidations(source, compact);
@@ -5852,8 +6487,8 @@ function writeDataValidations(document1, source, compact) {
5852
6487
  element.setAttribute('showInputMessage', item.hintShow ? '1' : '0');
5853
6488
  if (item.hintValue) element.setAttribute('prompt', item.hintValue.slice(0, 255));
5854
6489
  element.setAttribute('sqref', references.join(' '));
5855
- work_xlsx_interop_appendFormula(document1, element, 'formula1', xlsxValidationFormula(item));
5856
- if (item.value2) work_xlsx_interop_appendFormula(document1, element, 'formula2', item.value2);
6490
+ work_xlsx_interop_appendFormula(document1, element, 'formula1', xlsxValidationFormula(item, item.value1, namedListSources));
6491
+ if (item.value2) work_xlsx_interop_appendFormula(document1, element, 'formula2', xlsxValidationFormula(item, item.value2, namedListSources));
5857
6492
  container.append(element);
5858
6493
  }
5859
6494
  if (!container.children.length) return;
@@ -5931,10 +6566,12 @@ function work_xlsx_interop_appendFormula(document1, parent, name, value) {
5931
6566
  formula.textContent = value.replace(/^=/, '');
5932
6567
  parent.append(formula);
5933
6568
  }
5934
- function xlsxValidationFormula(item) {
5935
- const value = item.value1.trim();
6569
+ function xlsxValidationFormula(item, source, namedListSources) {
6570
+ const value = source.trim();
6571
+ if ('date' === item.type) return spreadsheetDateValidationFormula(value);
5936
6572
  if ('dropdown' !== item.type) return value;
5937
- if (/^=?[^,]+![A-Z]+\d+(?::[A-Z]+\d+)?$/i.test(value) || /^=?\$?[A-Z]+\$?\d+(?::\$?[A-Z]+\$?\d+)?$/i.test(value)) return value.replace(/^=/, '');
6573
+ const formula = value.replace(/^=/, '');
6574
+ if (/^=?[^,]+![A-Z]+\d+(?::[A-Z]+\d+)?$/i.test(value) || /^=?\$?[A-Z]+\$?\d+(?::\$?[A-Z]+\$?\d+)?$/i.test(value) || namedListSources.has(formula.toLocaleLowerCase())) return formula;
5938
6575
  return `"${value.replaceAll('"', '""')}"`;
5939
6576
  }
5940
6577
  function parseListFormula(value) {
@@ -5945,7 +6582,7 @@ function fortuneValidationType(value) {
5945
6582
  const types = {
5946
6583
  list: 'dropdown',
5947
6584
  whole: 'number_integer',
5948
- decimal: 'number_decimal',
6585
+ decimal: 'number',
5949
6586
  textLength: 'text_length',
5950
6587
  date: 'date'
5951
6588
  };
@@ -5962,7 +6599,16 @@ function xlsxValidationType(value) {
5962
6599
  };
5963
6600
  return types[value] ?? null;
5964
6601
  }
5965
- function fortuneValidationOperator(value) {
6602
+ function fortuneValidationOperator(value, date) {
6603
+ if (date) {
6604
+ const dateOperators = {
6605
+ lessThan: 'earlierThan',
6606
+ lessThanOrEqual: 'noLaterThan',
6607
+ greaterThan: 'laterThan',
6608
+ greaterThanOrEqual: 'noEarlierThan'
6609
+ };
6610
+ if (value && dateOperators[value]) return dateOperators[value];
6611
+ }
5966
6612
  const operators = {
5967
6613
  between: 'between',
5968
6614
  notBetween: 'notBetween',
@@ -5984,10 +6630,19 @@ function xlsxValidationOperator(value) {
5984
6630
  moreThanThe: 'greaterThan',
5985
6631
  lessThan: 'lessThan',
5986
6632
  greaterOrEqualTo: 'greaterThanOrEqual',
5987
- lessThanOrEqualTo: 'lessThanOrEqual'
6633
+ lessThanOrEqualTo: 'lessThanOrEqual',
6634
+ earlierThan: 'lessThan',
6635
+ noEarlierThan: 'greaterThanOrEqual',
6636
+ laterThan: 'greaterThan',
6637
+ noLaterThan: 'lessThanOrEqual'
5988
6638
  };
5989
6639
  return operators[value] ?? null;
5990
6640
  }
6641
+ function xlsxUses1904DateSystem(workbook) {
6642
+ if (!workbook) return false;
6643
+ const workbookProperties = firstDescendant(workbook, 'workbookPr');
6644
+ return workbookProperties ? work_xlsx_interop_booleanAttribute(workbookProperties, 'date1904') : false;
6645
+ }
5991
6646
  function work_xlsx_interop_booleanAttribute(element, name) {
5992
6647
  const value = work_ooxml_package_attribute(element, name)?.toLowerCase();
5993
6648
  return '1' === value || 'true' === value;
@@ -6338,7 +6993,7 @@ const PIVOT_CACHE_RECORDS_CONTENT_TYPE = 'application/vnd.openxmlformats-officed
6338
6993
  async function patchXlsxPivotTables(buffer, content) {
6339
6994
  if (!content.sheets.some((sheet)=>sheet.pivotTables?.length)) return buffer;
6340
6995
  const archive = await work_ooxml_package_OoxmlPackage.load(buffer);
6341
- const worksheetParts = await workbookWorksheetParts(archive);
6996
+ const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
6342
6997
  const candidates = content.sheets.flatMap((ownerSheet)=>(ownerSheet.pivotTables ?? []).flatMap((pivot)=>{
6343
6998
  if (!ownerSheet.id || !spreadsheetPivotValidation(content, ownerSheet.id, pivot).valid) return [];
6344
6999
  const worksheetPart = worksheetParts.get(ownerSheet.name.slice(0, 31) || '工作表');
@@ -6372,17 +7027,17 @@ async function patchXlsxPivotTables(buffer, content) {
6372
7027
  const pivotTablePath = `xl/pivotTables/pivotTable${partIndex}.xml`;
6373
7028
  const pivotCacheDefinitionPath = `xl/pivotCache/pivotCacheDefinition${partIndex}.xml`;
6374
7029
  const pivotCacheRecordsPath = `xl/pivotCache/pivotCacheRecords${partIndex}.xml`;
6375
- 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`);
6376
7031
  const pivotCache = workbook.createElementNS(workbook.documentElement.namespaceURI, 'pivotCache');
6377
7032
  pivotCache.setAttribute('cacheId', String(cacheId));
6378
7033
  pivotCache.setAttributeNS(DOCUMENT_RELATIONSHIP_NAMESPACE, 'r:id', workbookRelationshipId);
6379
7034
  pivotCaches.append(pivotCache);
6380
- 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));
6381
7036
  if (!worksheetRelationships.has(candidate.worksheetPart)) {
6382
7037
  removeRelationships(worksheetRelationshipDocument, '/pivotTable');
6383
7038
  worksheetRelationships.set(candidate.worksheetPart, worksheetRelationshipDocument);
6384
7039
  }
6385
- appendRelationship(worksheetRelationshipDocument, PIVOT_TABLE_RELATIONSHIP, `../pivotTables/pivotTable${partIndex}.xml`);
7040
+ work_xlsx_pivots_appendRelationship(worksheetRelationshipDocument, PIVOT_TABLE_RELATIONSHIP, `../pivotTables/pivotTable${partIndex}.xml`);
6386
7041
  zip.file(pivotTablePath, parts.table);
6387
7042
  zip.file(pivotCacheDefinitionPath, parts.cacheDefinition);
6388
7043
  zip.file(pivotCacheRecordsPath, parts.cacheRecords);
@@ -6433,11 +7088,11 @@ async function inspectXlsxPivotTables(archive) {
6433
7088
  const workbookRelationships = await archive.relationships('xl/workbook.xml');
6434
7089
  const cacheById = new Map();
6435
7090
  for (const cache of directChildren(firstDescendant(workbook, 'pivotCaches') ?? workbook.documentElement, 'pivotCache')){
6436
- const cacheId = integerAttribute(cache, 'cacheId');
7091
+ const cacheId = work_xlsx_pivots_integerAttribute(cache, 'cacheId');
6437
7092
  const relationship = workbookRelationships.get(work_ooxml_package_attribute(cache, 'r:id') ?? work_ooxml_package_attribute(cache, 'id') ?? '');
6438
7093
  if (null !== cacheId && relationship && archive.has(relationship.target)) cacheById.set(cacheId, parsePivotCache(await archive.xml(relationship.target)));
6439
7094
  }
6440
- const worksheetParts = await workbookWorksheetParts(archive);
7095
+ const worksheetParts = await work_xlsx_pivots_workbookWorksheetParts(archive);
6441
7096
  const tables = [];
6442
7097
  const unsupported = [];
6443
7098
  let detected = 0;
@@ -6523,7 +7178,7 @@ function applyImportedXlsxPivotTables(content, imported) {
6523
7178
  sheets
6524
7179
  };
6525
7180
  }
6526
- async function workbookWorksheetParts(archive) {
7181
+ async function work_xlsx_pivots_workbookWorksheetParts(archive) {
6527
7182
  if (!archive.has('xl/workbook.xml')) return new Map();
6528
7183
  const workbook = await archive.xml('xl/workbook.xml');
6529
7184
  const relationships = await archive.relationships('xl/workbook.xml');
@@ -6596,7 +7251,7 @@ function parsePivotReportFilters(root, cache, location) {
6596
7251
  if (!pageFields) return {
6597
7252
  reportFilters: []
6598
7253
  };
6599
- const pageWrap = integerAttribute(root, 'pageWrap') ?? 0;
7254
+ const pageWrap = work_xlsx_pivots_integerAttribute(root, 'pageWrap') ?? 0;
6600
7255
  if (pageWrap > 0 || work_xlsx_pivots_booleanAttribute(root, 'pageOverThenDown')) return {
6601
7256
  unsupported: {
6602
7257
  code: 'xlsx.pivots.report-filter-layout',
@@ -6607,7 +7262,7 @@ function parsePivotReportFilters(root, cache, location) {
6607
7262
  const pivotFields = directChildren(directChild(root, 'pivotFields') ?? root, 'pivotField');
6608
7263
  const reportFilters = [];
6609
7264
  for (const pageField of directChildren(pageFields, 'pageField')){
6610
- const fieldIndex = integerAttribute(pageField, 'fld');
7265
+ const fieldIndex = work_xlsx_pivots_integerAttribute(pageField, 'fld');
6611
7266
  const pivotField = null === fieldIndex ? void 0 : pivotFields[fieldIndex];
6612
7267
  if (null === fieldIndex || !pivotField || !cache.fields[fieldIndex]) return {
6613
7268
  unsupported: {
@@ -6624,7 +7279,7 @@ function parsePivotReportFilters(root, cache, location) {
6624
7279
  location
6625
7280
  }
6626
7281
  };
6627
- const itemIndex = integerAttribute(pageField, 'item');
7282
+ const itemIndex = work_xlsx_pivots_integerAttribute(pageField, 'item');
6628
7283
  if (null === itemIndex) {
6629
7284
  reportFilters.push({
6630
7285
  fieldIndex
@@ -6645,7 +7300,7 @@ function parsePivotReportFilters(root, cache, location) {
6645
7300
  });
6646
7301
  continue;
6647
7302
  }
6648
- const sharedItemIndex = integerAttribute(pivotItem, 'x');
7303
+ const sharedItemIndex = work_xlsx_pivots_integerAttribute(pivotItem, 'x');
6649
7304
  const sharedItems = cache.fieldItems[fieldIndex] ?? [];
6650
7305
  if (null === sharedItemIndex || sharedItemIndex < 0 || sharedItemIndex >= sharedItems.length) return {
6651
7306
  unsupported: {
@@ -6667,7 +7322,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6667
7322
  const root = document1.documentElement;
6668
7323
  const name = work_ooxml_package_attribute(root, 'name')?.trim() || 'PivotTable';
6669
7324
  const locationLabel = destinationSheetName ? `${destinationSheetName} · ${name}` : name;
6670
- const cacheId = integerAttribute(root, 'cacheId');
7325
+ const cacheId = work_xlsx_pivots_integerAttribute(root, 'cacheId');
6671
7326
  const cache = null === cacheId ? void 0 : cacheById.get(cacheId);
6672
7327
  if (!cache || cache.unsupported || !cache.sourceSheetName || !cache.sourceReference) return {
6673
7328
  unsupported: {
@@ -6699,7 +7354,7 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6699
7354
  };
6700
7355
  const values = [];
6701
7356
  for (const dataField of directChildren(directChild(root, 'dataFields') ?? root, 'dataField')){
6702
- const fieldIndex = integerAttribute(dataField, 'fld');
7357
+ const fieldIndex = work_xlsx_pivots_integerAttribute(dataField, 'fld');
6703
7358
  const aggregation = workPivotAggregation(work_ooxml_package_attribute(dataField, 'subtotal'));
6704
7359
  if (null === fieldIndex || !aggregation || !cache.fields[fieldIndex]) return {
6705
7360
  unsupported: {
@@ -6787,17 +7442,17 @@ function parsePivotTable(document1, destinationSheetName, cacheById) {
6787
7442
  function readPivotFieldIndexes(parent) {
6788
7443
  if (!parent) return [];
6789
7444
  return directChildren(parent, 'field').flatMap((field)=>{
6790
- const index = integerAttribute(field, 'x');
7445
+ const index = work_xlsx_pivots_integerAttribute(field, 'x');
6791
7446
  return null === index ? [] : [
6792
7447
  index
6793
7448
  ];
6794
7449
  });
6795
7450
  }
6796
- async function readRelationshipsDocument(zip, path) {
7451
+ async function work_xlsx_pivots_readRelationshipsDocument(zip, path) {
6797
7452
  const entry = zip.file(path);
6798
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);
6799
7454
  }
6800
- function appendRelationship(document1, type, target) {
7455
+ function work_xlsx_pivots_appendRelationship(document1, type, target) {
6801
7456
  const id = work_xlsx_pivots_nextRelationshipId(document1);
6802
7457
  const relationship = document1.createElementNS(work_xlsx_pivots_PACKAGE_RELATIONSHIP_NAMESPACE, 'Relationship');
6803
7458
  relationship.setAttribute('Id', id);
@@ -6865,7 +7520,7 @@ function work_xlsx_pivots_relationshipsPartPath(sourcePart) {
6865
7520
  `${name}.rels`
6866
7521
  ].join('/');
6867
7522
  }
6868
- function integerAttribute(element, name) {
7523
+ function work_xlsx_pivots_integerAttribute(element, name) {
6869
7524
  const source = work_ooxml_package_attribute(element, name);
6870
7525
  if (null === source || !source.trim()) return null;
6871
7526
  const value = Number(source);
@@ -6900,7 +7555,8 @@ async function createWorkSpreadsheetBlob(artifact) {
6900
7555
  compression: true
6901
7556
  });
6902
7557
  const withFeatures = await patchXlsxSheetFeatures(bytes, content);
6903
- const withDrawings = await patchXlsxWorksheetDrawings(withFeatures, content);
7558
+ const withTables = await patchXlsxSpreadsheetTables(withFeatures, content);
7559
+ const withDrawings = await patchXlsxWorksheetDrawings(withTables, content);
6904
7560
  const withFormulas = await patchXlsxFormulaFeatures(withDrawings, content);
6905
7561
  const output = await patchXlsxPivotTables(withFormulas, content);
6906
7562
  return new Blob([
@@ -7731,6 +8387,7 @@ async function importWorkSpreadsheetFile(file, extension, context) {
7731
8387
  luckysheet_conditionformat_save: features?.conditionalFormats.length ? features.conditionalFormats : void 0,
7732
8388
  images: features?.images.length ? xlsxWorksheetImagesToSheet(features.images, config) : void 0,
7733
8389
  charts: features?.charts.length ? xlsxWorksheetChartsToSheet(features.charts, config) : void 0,
8390
+ tables: features?.tables.length ? features.tables : void 0,
7734
8391
  formulaMetadata
7735
8392
  });
7736
8393
  await context.controller.checkpoint('parsing', sheetProgressStart + sheetProgressSize);