@cj-tech-master/excelts 1.4.0 → 1.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/browser/excelts.iife.js +41 -10
- package/dist/browser/excelts.iife.js.map +1 -1
- package/dist/browser/excelts.iife.min.js +3 -3
- package/dist/cjs/doc/data-validations.js +29 -1
- package/dist/cjs/xlsx/xform/sheet/data-validations-xform.js +46 -7
- package/dist/esm/doc/data-validations.js +29 -1
- package/dist/esm/xlsx/xform/sheet/data-validations-xform.js +46 -7
- package/package.json +1 -1
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DataValidations = void 0;
|
|
4
|
+
const col_cache_js_1 = require("../utils/col-cache");
|
|
4
5
|
class DataValidations {
|
|
5
6
|
constructor(model) {
|
|
6
7
|
this.model = model || {};
|
|
@@ -9,7 +10,34 @@ class DataValidations {
|
|
|
9
10
|
return (this.model[address] = validation);
|
|
10
11
|
}
|
|
11
12
|
find(address) {
|
|
12
|
-
|
|
13
|
+
// First check direct address match
|
|
14
|
+
const direct = this.model[address];
|
|
15
|
+
if (direct !== undefined) {
|
|
16
|
+
return direct;
|
|
17
|
+
}
|
|
18
|
+
// Check range: prefixed keys in model (from parsing large ranges)
|
|
19
|
+
// Only decode address if we have range keys to check
|
|
20
|
+
const keys = Object.keys(this.model);
|
|
21
|
+
const rangeKeys = keys.filter(k => k.startsWith("range:"));
|
|
22
|
+
if (rangeKeys.length === 0) {
|
|
23
|
+
return undefined;
|
|
24
|
+
}
|
|
25
|
+
const decoded = col_cache_js_1.colCache.decodeAddress(address);
|
|
26
|
+
for (const key of rangeKeys) {
|
|
27
|
+
const rangeStr = key.slice(6); // Remove "range:" prefix
|
|
28
|
+
const rangeDecoded = col_cache_js_1.colCache.decodeEx(rangeStr);
|
|
29
|
+
if (rangeDecoded.dimensions) {
|
|
30
|
+
const tl = rangeDecoded.tl;
|
|
31
|
+
const br = rangeDecoded.br;
|
|
32
|
+
if (decoded.row >= tl.row &&
|
|
33
|
+
decoded.row <= br.row &&
|
|
34
|
+
decoded.col >= tl.col &&
|
|
35
|
+
decoded.col <= br.col) {
|
|
36
|
+
return this.model[key];
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return undefined;
|
|
13
41
|
}
|
|
14
42
|
remove(address) {
|
|
15
43
|
this.model[address] = undefined;
|
|
@@ -30,7 +30,32 @@ function optimiseDataValidations(model) {
|
|
|
30
30
|
if (!model) {
|
|
31
31
|
return [];
|
|
32
32
|
}
|
|
33
|
-
|
|
33
|
+
// First, handle range: prefixed keys directly (large ranges stored during parsing)
|
|
34
|
+
const rangeValidations = [];
|
|
35
|
+
const regularModel = {};
|
|
36
|
+
for (const [key, value] of Object.entries(model)) {
|
|
37
|
+
// Skip undefined/null values (removed validations)
|
|
38
|
+
if (value === undefined || value === null) {
|
|
39
|
+
continue;
|
|
40
|
+
}
|
|
41
|
+
if (key.startsWith("range:")) {
|
|
42
|
+
// Large range stored during parsing - output directly
|
|
43
|
+
const rangeStr = key.slice(6); // Remove "range:" prefix
|
|
44
|
+
const { sqref: _sqref, ...rest } = value;
|
|
45
|
+
rangeValidations.push({
|
|
46
|
+
...rest,
|
|
47
|
+
sqref: rangeStr
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
regularModel[key] = value;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
// If no regular entries, just return range validations
|
|
55
|
+
if (Object.keys(regularModel).length === 0) {
|
|
56
|
+
return rangeValidations;
|
|
57
|
+
}
|
|
58
|
+
const dvList = Object.entries(regularModel)
|
|
34
59
|
.map(([address, dataValidation]) => ({
|
|
35
60
|
address,
|
|
36
61
|
dataValidation,
|
|
@@ -41,13 +66,14 @@ function optimiseDataValidations(model) {
|
|
|
41
66
|
const matchCol = (addr, height, col) => {
|
|
42
67
|
for (let i = 0; i < height; i++) {
|
|
43
68
|
const otherAddress = col_cache_js_1.colCache.encodeAddress(addr.row + i, col);
|
|
44
|
-
if (!
|
|
69
|
+
if (!regularModel[otherAddress] ||
|
|
70
|
+
!(0, under_dash_js_1.isEqual)(regularModel[addr.address], regularModel[otherAddress])) {
|
|
45
71
|
return false;
|
|
46
72
|
}
|
|
47
73
|
}
|
|
48
74
|
return true;
|
|
49
75
|
};
|
|
50
|
-
|
|
76
|
+
const optimized = dvList
|
|
51
77
|
.map(dv => {
|
|
52
78
|
if (!dv.marked) {
|
|
53
79
|
const addr = col_cache_js_1.colCache.decodeEx(dv.address);
|
|
@@ -61,7 +87,8 @@ function optimiseDataValidations(model) {
|
|
|
61
87
|
// iterate downwards - finding matching cells
|
|
62
88
|
let height = 1;
|
|
63
89
|
let otherAddress = col_cache_js_1.colCache.encodeAddress(addr.row + height, addr.col);
|
|
64
|
-
while (
|
|
90
|
+
while (regularModel[otherAddress] &&
|
|
91
|
+
(0, under_dash_js_1.isEqual)(dv.dataValidation, regularModel[otherAddress])) {
|
|
65
92
|
height++;
|
|
66
93
|
otherAddress = col_cache_js_1.colCache.encodeAddress(addr.row + height, addr.col);
|
|
67
94
|
}
|
|
@@ -93,6 +120,7 @@ function optimiseDataValidations(model) {
|
|
|
93
120
|
return null;
|
|
94
121
|
})
|
|
95
122
|
.filter(Boolean);
|
|
123
|
+
return [...rangeValidations, ...optimized];
|
|
96
124
|
}
|
|
97
125
|
class DataValidationsXform extends base_xform_js_1.BaseXform {
|
|
98
126
|
get tag() {
|
|
@@ -207,9 +235,20 @@ class DataValidationsXform extends base_xform_js_1.BaseXform {
|
|
|
207
235
|
list.forEach((addr) => {
|
|
208
236
|
if (addr.includes(":")) {
|
|
209
237
|
const range = new range_js_1.Range(addr);
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
238
|
+
// Only expand small ranges to avoid performance issues with large ranges
|
|
239
|
+
// like B2:B1048576 (entire column validations)
|
|
240
|
+
const rangeSize = (range.bottom - range.top + 1) * (range.right - range.left + 1);
|
|
241
|
+
if (rangeSize <= 1000) {
|
|
242
|
+
// Small range: expand to individual cells for backward compatibility
|
|
243
|
+
range.forEachAddress((address) => {
|
|
244
|
+
this.model[address] = this._dataValidation;
|
|
245
|
+
});
|
|
246
|
+
}
|
|
247
|
+
else {
|
|
248
|
+
// Large range: store as range string with special marker
|
|
249
|
+
// The key format "range:A1:Z100" allows DataValidations.find() to detect it
|
|
250
|
+
this.model[`range:${addr}`] = this._dataValidation;
|
|
251
|
+
}
|
|
213
252
|
}
|
|
214
253
|
else {
|
|
215
254
|
this.model[addr] = this._dataValidation;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { colCache } from "../utils/col-cache.js";
|
|
1
2
|
class DataValidations {
|
|
2
3
|
constructor(model) {
|
|
3
4
|
this.model = model || {};
|
|
@@ -6,7 +7,34 @@ class DataValidations {
|
|
|
6
7
|
return (this.model[address] = validation);
|
|
7
8
|
}
|
|
8
9
|
find(address) {
|
|
9
|
-
|
|
10
|
+
// First check direct address match
|
|
11
|
+
const direct = this.model[address];
|
|
12
|
+
if (direct !== undefined) {
|
|
13
|
+
return direct;
|
|
14
|
+
}
|
|
15
|
+
// Check range: prefixed keys in model (from parsing large ranges)
|
|
16
|
+
// Only decode address if we have range keys to check
|
|
17
|
+
const keys = Object.keys(this.model);
|
|
18
|
+
const rangeKeys = keys.filter(k => k.startsWith("range:"));
|
|
19
|
+
if (rangeKeys.length === 0) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
const decoded = colCache.decodeAddress(address);
|
|
23
|
+
for (const key of rangeKeys) {
|
|
24
|
+
const rangeStr = key.slice(6); // Remove "range:" prefix
|
|
25
|
+
const rangeDecoded = colCache.decodeEx(rangeStr);
|
|
26
|
+
if (rangeDecoded.dimensions) {
|
|
27
|
+
const tl = rangeDecoded.tl;
|
|
28
|
+
const br = rangeDecoded.br;
|
|
29
|
+
if (decoded.row >= tl.row &&
|
|
30
|
+
decoded.row <= br.row &&
|
|
31
|
+
decoded.col >= tl.col &&
|
|
32
|
+
decoded.col <= br.col) {
|
|
33
|
+
return this.model[key];
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
return undefined;
|
|
10
38
|
}
|
|
11
39
|
remove(address) {
|
|
12
40
|
this.model[address] = undefined;
|
|
@@ -27,7 +27,32 @@ function optimiseDataValidations(model) {
|
|
|
27
27
|
if (!model) {
|
|
28
28
|
return [];
|
|
29
29
|
}
|
|
30
|
-
|
|
30
|
+
// First, handle range: prefixed keys directly (large ranges stored during parsing)
|
|
31
|
+
const rangeValidations = [];
|
|
32
|
+
const regularModel = {};
|
|
33
|
+
for (const [key, value] of Object.entries(model)) {
|
|
34
|
+
// Skip undefined/null values (removed validations)
|
|
35
|
+
if (value === undefined || value === null) {
|
|
36
|
+
continue;
|
|
37
|
+
}
|
|
38
|
+
if (key.startsWith("range:")) {
|
|
39
|
+
// Large range stored during parsing - output directly
|
|
40
|
+
const rangeStr = key.slice(6); // Remove "range:" prefix
|
|
41
|
+
const { sqref: _sqref, ...rest } = value;
|
|
42
|
+
rangeValidations.push({
|
|
43
|
+
...rest,
|
|
44
|
+
sqref: rangeStr
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
else {
|
|
48
|
+
regularModel[key] = value;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
// If no regular entries, just return range validations
|
|
52
|
+
if (Object.keys(regularModel).length === 0) {
|
|
53
|
+
return rangeValidations;
|
|
54
|
+
}
|
|
55
|
+
const dvList = Object.entries(regularModel)
|
|
31
56
|
.map(([address, dataValidation]) => ({
|
|
32
57
|
address,
|
|
33
58
|
dataValidation,
|
|
@@ -38,13 +63,14 @@ function optimiseDataValidations(model) {
|
|
|
38
63
|
const matchCol = (addr, height, col) => {
|
|
39
64
|
for (let i = 0; i < height; i++) {
|
|
40
65
|
const otherAddress = colCache.encodeAddress(addr.row + i, col);
|
|
41
|
-
if (!
|
|
66
|
+
if (!regularModel[otherAddress] ||
|
|
67
|
+
!isEqual(regularModel[addr.address], regularModel[otherAddress])) {
|
|
42
68
|
return false;
|
|
43
69
|
}
|
|
44
70
|
}
|
|
45
71
|
return true;
|
|
46
72
|
};
|
|
47
|
-
|
|
73
|
+
const optimized = dvList
|
|
48
74
|
.map(dv => {
|
|
49
75
|
if (!dv.marked) {
|
|
50
76
|
const addr = colCache.decodeEx(dv.address);
|
|
@@ -58,7 +84,8 @@ function optimiseDataValidations(model) {
|
|
|
58
84
|
// iterate downwards - finding matching cells
|
|
59
85
|
let height = 1;
|
|
60
86
|
let otherAddress = colCache.encodeAddress(addr.row + height, addr.col);
|
|
61
|
-
while (
|
|
87
|
+
while (regularModel[otherAddress] &&
|
|
88
|
+
isEqual(dv.dataValidation, regularModel[otherAddress])) {
|
|
62
89
|
height++;
|
|
63
90
|
otherAddress = colCache.encodeAddress(addr.row + height, addr.col);
|
|
64
91
|
}
|
|
@@ -90,6 +117,7 @@ function optimiseDataValidations(model) {
|
|
|
90
117
|
return null;
|
|
91
118
|
})
|
|
92
119
|
.filter(Boolean);
|
|
120
|
+
return [...rangeValidations, ...optimized];
|
|
93
121
|
}
|
|
94
122
|
class DataValidationsXform extends BaseXform {
|
|
95
123
|
get tag() {
|
|
@@ -204,9 +232,20 @@ class DataValidationsXform extends BaseXform {
|
|
|
204
232
|
list.forEach((addr) => {
|
|
205
233
|
if (addr.includes(":")) {
|
|
206
234
|
const range = new Range(addr);
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
235
|
+
// Only expand small ranges to avoid performance issues with large ranges
|
|
236
|
+
// like B2:B1048576 (entire column validations)
|
|
237
|
+
const rangeSize = (range.bottom - range.top + 1) * (range.right - range.left + 1);
|
|
238
|
+
if (rangeSize <= 1000) {
|
|
239
|
+
// Small range: expand to individual cells for backward compatibility
|
|
240
|
+
range.forEachAddress((address) => {
|
|
241
|
+
this.model[address] = this._dataValidation;
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
else {
|
|
245
|
+
// Large range: store as range string with special marker
|
|
246
|
+
// The key format "range:A1:Z100" allows DataValidations.find() to detect it
|
|
247
|
+
this.model[`range:${addr}`] = this._dataValidation;
|
|
248
|
+
}
|
|
210
249
|
}
|
|
211
250
|
else {
|
|
212
251
|
this.model[addr] = this._dataValidation;
|