@rowsncolumns/utils 9.5.5 → 9.5.7
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/cjs/data-validation.d.ts +29 -1
- package/dist/cjs/data-validation.d.ts.map +1 -1
- package/dist/cjs/data-validation.js +83 -24
- package/dist/cjs/formula-locale/formula-locale-data.generated.d.ts.map +1 -1
- package/dist/cjs/formula-locale/formula-locale-data.generated.js +1 -0
- package/dist/esm/data-validation.d.ts +29 -1
- package/dist/esm/data-validation.d.ts.map +1 -1
- package/dist/esm/data-validation.js +75 -23
- package/dist/esm/formula-locale/formula-locale-data.generated.d.ts.map +1 -1
- package/dist/esm/formula-locale/formula-locale-data.generated.js +1 -0
- package/package.json +1 -1
|
@@ -1,10 +1,38 @@
|
|
|
1
|
-
import type { DataValidationRule } from "@rowsncolumns/common-types";
|
|
1
|
+
import type { BooleanCondition, ConditionType, DataValidationRule } from "@rowsncolumns/common-types";
|
|
2
2
|
/**
|
|
3
3
|
* A leading apostrophe in a data-validation / conditional-format list entry is
|
|
4
4
|
* Excel's text prefix — `'000s` is the text "000s" and a bare `'` is empty
|
|
5
5
|
* text — never part of the value itself.
|
|
6
6
|
*/
|
|
7
7
|
export declare const stripDataValidationTextPrefix: (entry: string) => string;
|
|
8
|
+
/**
|
|
9
|
+
* A `ONE_OF_LIST` value that is a SOURCE FORMULA rather than literal items,
|
|
10
|
+
* returned trimmed with its leading `=` (`=RegionList`, `=$A$2:$A$9`,
|
|
11
|
+
* `=Sheet2!A1:A5`, `=INDIRECT("…")`). Excel's List type has one Source box
|
|
12
|
+
* that takes either literal items (`Yes,No`) or a formula starting with `=`;
|
|
13
|
+
* the "Dropdown" (`ONE_OF_LIST`) / "Dropdown (from a range)" (`ONE_OF_RANGE`)
|
|
14
|
+
* split means a `=…` typed into the literal dropdown is read the way Excel
|
|
15
|
+
* reads it — as a `ONE_OF_RANGE` over that source. A quoted literal
|
|
16
|
+
* (`"=a,b"`, Excel's quoted list), a `=` inside a later item (`a,=b`) and a
|
|
17
|
+
* bare `=` stay literal. Rust twin: `rnc_model::validation::one_of_list_formula_source`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getDataValidationListFormulaSource: (value: string | undefined | null) => string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The condition type a rule behaves as: a `ONE_OF_LIST` whose first value is
|
|
22
|
+
* a source formula (`getDataValidationListFormulaSource`) behaves as
|
|
23
|
+
* `ONE_OF_RANGE`; every other condition is its own type. Rust twin:
|
|
24
|
+
* `rnc_model::validation::effective_condition_kind`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getEffectiveDataValidationConditionType: (condition: BooleanCondition | undefined | null) => ConditionType | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The reference a list rule draws its options from, or `undefined` when the
|
|
29
|
+
* rule is a literal item list (or not a list rule at all). `ONE_OF_RANGE` is
|
|
30
|
+
* always a reference (its value, `""` when missing); a `ONE_OF_LIST` is one
|
|
31
|
+
* when its value is a source formula (`=RegionList`) or a bare A1 reference
|
|
32
|
+
* (`$A$1:$A$5`). Shared by the dropdown options, the commit gate and
|
|
33
|
+
* `checkBooleanRule`, so the three always agree.
|
|
34
|
+
*/
|
|
35
|
+
export declare const getDataValidationListReference: (condition: BooleanCondition | undefined | null) => string | undefined;
|
|
8
36
|
/**
|
|
9
37
|
* Whether a cell's current text matches a ONE_OF_LIST option, with Excel's
|
|
10
38
|
* text-prefix semantics on BOTH sides: the option strips its leading `'`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-validation.d.ts","sourceRoot":"","sources":["../../data-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"data-validation.d.ts","sourceRoot":"","sources":["../../data-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAUpC;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,KAAG,MACd,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC7C,OAAO,MAAM,GAAG,SAAS,GAAG,IAAI,KAC/B,MAAM,GAAG,SAKX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uCAAuC,GAClD,WAAW,gBAAgB,GAAG,SAAS,GAAG,IAAI,KAC7C,aAAa,GAAG,SAIe,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GACzC,WAAW,gBAAgB,GAAG,SAAS,GAAG,IAAI,KAC7C,MAAM,GAAG,SAYX,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,GAC/C,QAAQ,MAAM,GAAG,SAAS,GAAG,IAAI,EACjC,WAAW,MAAM,GAAG,SAAS,GAAG,IAAI,KACnC,OAKF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,2BAA2B,GACtC,MAAM,kBAAkB,GAAG,SAAS,YAKrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACxC,MAAM,kBAAkB,GAAG,SAAS,EACpC,aAAa,MAAM,EACnB,SAAS,MAAM,uBAgBhB,CAAC"}
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.buildDataValidationExpression = exports.isDataValidationFormulaRule = exports.dataValidationOptionMatchesCellValue = exports.stripDataValidationTextPrefix = void 0;
|
|
3
|
+
exports.buildDataValidationExpression = exports.isDataValidationFormulaRule = exports.dataValidationOptionMatchesCellValue = exports.getDataValidationListReference = exports.getEffectiveDataValidationConditionType = exports.getDataValidationListFormulaSource = exports.stripDataValidationTextPrefix = void 0;
|
|
4
4
|
var condition_operand_1 = require("./condition-operand");
|
|
5
|
+
var selection_1 = require("./selection");
|
|
5
6
|
var FORMULA_PREDICATE_BASE_CELL_REF = "A1";
|
|
6
7
|
/**
|
|
7
8
|
* A leading apostrophe in a data-validation / conditional-format list entry is
|
|
@@ -12,6 +13,59 @@ var stripDataValidationTextPrefix = function (entry) {
|
|
|
12
13
|
return entry.startsWith("'") ? entry.slice(1) : entry;
|
|
13
14
|
};
|
|
14
15
|
exports.stripDataValidationTextPrefix = stripDataValidationTextPrefix;
|
|
16
|
+
/**
|
|
17
|
+
* A `ONE_OF_LIST` value that is a SOURCE FORMULA rather than literal items,
|
|
18
|
+
* returned trimmed with its leading `=` (`=RegionList`, `=$A$2:$A$9`,
|
|
19
|
+
* `=Sheet2!A1:A5`, `=INDIRECT("…")`). Excel's List type has one Source box
|
|
20
|
+
* that takes either literal items (`Yes,No`) or a formula starting with `=`;
|
|
21
|
+
* the "Dropdown" (`ONE_OF_LIST`) / "Dropdown (from a range)" (`ONE_OF_RANGE`)
|
|
22
|
+
* split means a `=…` typed into the literal dropdown is read the way Excel
|
|
23
|
+
* reads it — as a `ONE_OF_RANGE` over that source. A quoted literal
|
|
24
|
+
* (`"=a,b"`, Excel's quoted list), a `=` inside a later item (`a,=b`) and a
|
|
25
|
+
* bare `=` stay literal. Rust twin: `rnc_model::validation::one_of_list_formula_source`.
|
|
26
|
+
*/
|
|
27
|
+
var getDataValidationListFormulaSource = function (value) {
|
|
28
|
+
var trimmed = (value !== null && value !== void 0 ? value : "").trim();
|
|
29
|
+
return trimmed.startsWith("=") && trimmed.slice(1).trim()
|
|
30
|
+
? trimmed
|
|
31
|
+
: undefined;
|
|
32
|
+
};
|
|
33
|
+
exports.getDataValidationListFormulaSource = getDataValidationListFormulaSource;
|
|
34
|
+
/**
|
|
35
|
+
* The condition type a rule behaves as: a `ONE_OF_LIST` whose first value is
|
|
36
|
+
* a source formula (`getDataValidationListFormulaSource`) behaves as
|
|
37
|
+
* `ONE_OF_RANGE`; every other condition is its own type. Rust twin:
|
|
38
|
+
* `rnc_model::validation::effective_condition_kind`.
|
|
39
|
+
*/
|
|
40
|
+
var getEffectiveDataValidationConditionType = function (condition) {
|
|
41
|
+
var _a, _b, _c;
|
|
42
|
+
return (condition === null || condition === void 0 ? void 0 : condition.type) === "ONE_OF_LIST" &&
|
|
43
|
+
(0, exports.getDataValidationListFormulaSource)((_b = (_a = condition.values) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.userEnteredValue)
|
|
44
|
+
? "ONE_OF_RANGE"
|
|
45
|
+
: (_c = condition === null || condition === void 0 ? void 0 : condition.type) !== null && _c !== void 0 ? _c : undefined;
|
|
46
|
+
};
|
|
47
|
+
exports.getEffectiveDataValidationConditionType = getEffectiveDataValidationConditionType;
|
|
48
|
+
/**
|
|
49
|
+
* The reference a list rule draws its options from, or `undefined` when the
|
|
50
|
+
* rule is a literal item list (or not a list rule at all). `ONE_OF_RANGE` is
|
|
51
|
+
* always a reference (its value, `""` when missing); a `ONE_OF_LIST` is one
|
|
52
|
+
* when its value is a source formula (`=RegionList`) or a bare A1 reference
|
|
53
|
+
* (`$A$1:$A$5`). Shared by the dropdown options, the commit gate and
|
|
54
|
+
* `checkBooleanRule`, so the three always agree.
|
|
55
|
+
*/
|
|
56
|
+
var getDataValidationListReference = function (condition) {
|
|
57
|
+
var _a, _b, _c, _d;
|
|
58
|
+
var firstValue = (_b = (_a = condition === null || condition === void 0 ? void 0 : condition.values) === null || _a === void 0 ? void 0 : _a[0]) === null || _b === void 0 ? void 0 : _b.userEnteredValue;
|
|
59
|
+
if ((0, exports.getEffectiveDataValidationConditionType)(condition) === "ONE_OF_RANGE") {
|
|
60
|
+
return (_d = (_c = (0, exports.getDataValidationListFormulaSource)(firstValue)) !== null && _c !== void 0 ? _c : firstValue) !== null && _d !== void 0 ? _d : "";
|
|
61
|
+
}
|
|
62
|
+
if ((condition === null || condition === void 0 ? void 0 : condition.type) === "ONE_OF_LIST" &&
|
|
63
|
+
(0, selection_1.checkIfStringIsReference)(firstValue)) {
|
|
64
|
+
return firstValue;
|
|
65
|
+
}
|
|
66
|
+
return undefined;
|
|
67
|
+
};
|
|
68
|
+
exports.getDataValidationListReference = getDataValidationListReference;
|
|
15
69
|
/**
|
|
16
70
|
* Whether a cell's current text matches a ONE_OF_LIST option, with Excel's
|
|
17
71
|
* text-prefix semantics on BOTH sides: the option strips its leading `'`
|
|
@@ -91,20 +145,23 @@ exports.buildDataValidationExpression = buildDataValidationExpression;
|
|
|
91
145
|
var buildDataValidationConditionExpression = function (rule, baseCellRef, locale) {
|
|
92
146
|
var _a, _b, _c;
|
|
93
147
|
var condition = rule === null || rule === void 0 ? void 0 : rule.condition;
|
|
94
|
-
|
|
148
|
+
// A ONE_OF_LIST whose value is a source formula (`=RegionList`) compiles as
|
|
149
|
+
// the ONE_OF_RANGE over that source, as Excel's List type reads it.
|
|
150
|
+
var type = (0, exports.getEffectiveDataValidationConditionType)(condition);
|
|
151
|
+
if (!condition || !type)
|
|
95
152
|
return undefined;
|
|
96
153
|
var values = (_a = condition.values) !== null && _a !== void 0 ? _a : [];
|
|
97
154
|
var fromRaw = (_b = values[0]) === null || _b === void 0 ? void 0 : _b.userEnteredValue;
|
|
98
155
|
var toRaw = (_c = values[1]) === null || _c === void 0 ? void 0 : _c.userEnteredValue;
|
|
99
|
-
if (
|
|
156
|
+
if (type === "CUSTOM_FORMULA") {
|
|
100
157
|
var raw = fromRaw !== null && fromRaw !== void 0 ? fromRaw : "";
|
|
101
158
|
var trimmed = raw.trim();
|
|
102
159
|
if (!trimmed)
|
|
103
160
|
return undefined;
|
|
104
161
|
return trimmed.startsWith("=") ? trimmed : "=".concat(trimmed);
|
|
105
162
|
}
|
|
106
|
-
var fromExpr = (0, condition_operand_1.normalizeConditionOperand)(fromRaw,
|
|
107
|
-
var toExpr = (0, condition_operand_1.normalizeConditionOperand)(toRaw,
|
|
163
|
+
var fromExpr = (0, condition_operand_1.normalizeConditionOperand)(fromRaw, type, locale);
|
|
164
|
+
var toExpr = (0, condition_operand_1.normalizeConditionOperand)(toRaw, type, locale);
|
|
108
165
|
if (!fromExpr && !toExpr)
|
|
109
166
|
return undefined;
|
|
110
167
|
var comparisonOperatorMap = {
|
|
@@ -123,51 +180,49 @@ var buildDataValidationConditionExpression = function (rule, baseCellRef, locale
|
|
|
123
180
|
TEXT_EQ: "=",
|
|
124
181
|
TEXT_NOT_EQ: "<>",
|
|
125
182
|
};
|
|
126
|
-
if (
|
|
127
|
-
condition.type === "DATE_BETWEEN") {
|
|
183
|
+
if (type === "NUMBER_BETWEEN" || type === "DATE_BETWEEN") {
|
|
128
184
|
if (!fromExpr || !toExpr)
|
|
129
185
|
return undefined;
|
|
130
186
|
return "=AND(".concat(baseCellRef, ">=").concat(fromExpr, ",").concat(baseCellRef, "<=").concat(toExpr, ")");
|
|
131
187
|
}
|
|
132
|
-
if (
|
|
133
|
-
condition.type === "DATE_NOT_BETWEEN") {
|
|
188
|
+
if (type === "NUMBER_NOT_BETWEEN" || type === "DATE_NOT_BETWEEN") {
|
|
134
189
|
if (!fromExpr || !toExpr)
|
|
135
190
|
return undefined;
|
|
136
191
|
return "=OR(".concat(baseCellRef, "<").concat(fromExpr, ",").concat(baseCellRef, ">").concat(toExpr, ")");
|
|
137
192
|
}
|
|
138
|
-
var comparisonOperator = comparisonOperatorMap[
|
|
193
|
+
var comparisonOperator = comparisonOperatorMap[type];
|
|
139
194
|
if (comparisonOperator) {
|
|
140
195
|
if (!fromExpr)
|
|
141
196
|
return undefined;
|
|
142
197
|
return "=".concat(baseCellRef).concat(comparisonOperator).concat(fromExpr);
|
|
143
198
|
}
|
|
144
|
-
if (
|
|
199
|
+
if (type === "TEXT_CONTAINS") {
|
|
145
200
|
if (!fromExpr)
|
|
146
201
|
return undefined;
|
|
147
202
|
return "=ISNUMBER(SEARCH(".concat(fromExpr, ",").concat(baseCellRef, "))");
|
|
148
203
|
}
|
|
149
|
-
if (
|
|
204
|
+
if (type === "TEXT_NOT_CONTAINS") {
|
|
150
205
|
if (!fromExpr)
|
|
151
206
|
return undefined;
|
|
152
207
|
return "=NOT(ISNUMBER(SEARCH(".concat(fromExpr, ",").concat(baseCellRef, ")))");
|
|
153
208
|
}
|
|
154
|
-
if (
|
|
209
|
+
if (type === "TEXT_STARTS_WITH") {
|
|
155
210
|
if (!fromExpr)
|
|
156
211
|
return undefined;
|
|
157
212
|
return "=LEFT(".concat(baseCellRef, ",LEN(").concat(fromExpr, "))=").concat(fromExpr);
|
|
158
213
|
}
|
|
159
|
-
if (
|
|
214
|
+
if (type === "TEXT_ENDS_WITH") {
|
|
160
215
|
if (!fromExpr)
|
|
161
216
|
return undefined;
|
|
162
217
|
return "=RIGHT(".concat(baseCellRef, ",LEN(").concat(fromExpr, "))=").concat(fromExpr);
|
|
163
218
|
}
|
|
164
|
-
if (
|
|
219
|
+
if (type === "TEXT_IS_EMAIL") {
|
|
165
220
|
return "=ISNUMBER(SEARCH(\"@\",".concat(baseCellRef, "))");
|
|
166
221
|
}
|
|
167
|
-
if (
|
|
222
|
+
if (type === "TEXT_IS_URL") {
|
|
168
223
|
return "=OR(LEFT(".concat(baseCellRef, ",7)=\"http://\",LEFT(").concat(baseCellRef, ",8)=\"https://\")");
|
|
169
224
|
}
|
|
170
|
-
if (
|
|
225
|
+
if (type === "ONE_OF_RANGE") {
|
|
171
226
|
if (!fromExpr)
|
|
172
227
|
return undefined;
|
|
173
228
|
if (rule === null || rule === void 0 ? void 0 : rule.allowBlank) {
|
|
@@ -175,7 +230,7 @@ var buildDataValidationConditionExpression = function (rule, baseCellRef, locale
|
|
|
175
230
|
}
|
|
176
231
|
return "=COUNTIF(".concat(fromExpr, ",").concat(baseCellRef, ")>0");
|
|
177
232
|
}
|
|
178
|
-
if (
|
|
233
|
+
if (type === "ONE_OF_LIST") {
|
|
179
234
|
var entries = fromRaw
|
|
180
235
|
? fromRaw.split(",").map(function (entry) { return entry.trim(); })
|
|
181
236
|
: [];
|
|
@@ -192,10 +247,14 @@ var buildDataValidationConditionExpression = function (rule, baseCellRef, locale
|
|
|
192
247
|
? [textCondition, "".concat(baseCellRef, "=\"'\"")]
|
|
193
248
|
: [textCondition];
|
|
194
249
|
}
|
|
250
|
+
// A list ITEM is never a formula (a source formula is the whole value,
|
|
251
|
+
// see `getEffectiveDataValidationConditionType`): `"=a,b"` and `a,=b`
|
|
252
|
+
// list the text `=a` / `=b`.
|
|
253
|
+
if (entry.startsWith("=")) {
|
|
254
|
+
return ["".concat(baseCellRef, "=\"").concat((0, condition_operand_1.escapeConditionFormulaText)(entry), "\"")];
|
|
255
|
+
}
|
|
195
256
|
return entry
|
|
196
|
-
? [
|
|
197
|
-
"".concat(baseCellRef, "=").concat((0, condition_operand_1.normalizeConditionOperand)(entry, condition.type, locale)),
|
|
198
|
-
]
|
|
257
|
+
? ["".concat(baseCellRef, "=").concat((0, condition_operand_1.normalizeConditionOperand)(entry, type, locale))]
|
|
199
258
|
: [];
|
|
200
259
|
})
|
|
201
260
|
.filter(function (entry) { return Boolean(entry); });
|
|
@@ -205,13 +264,13 @@ var buildDataValidationConditionExpression = function (rule, baseCellRef, locale
|
|
|
205
264
|
? "=".concat(conditions[0])
|
|
206
265
|
: "=OR(".concat(conditions.join(","), ")");
|
|
207
266
|
}
|
|
208
|
-
if (
|
|
267
|
+
if (type === "BLANK") {
|
|
209
268
|
return "=".concat(baseCellRef, "=\"\"");
|
|
210
269
|
}
|
|
211
|
-
if (
|
|
270
|
+
if (type === "NOT_BLANK") {
|
|
212
271
|
return "=".concat(baseCellRef, "<>\"\"");
|
|
213
272
|
}
|
|
214
|
-
if (
|
|
273
|
+
if (type === "BOOLEAN") {
|
|
215
274
|
return "=OR(".concat(baseCellRef, "=TRUE,").concat(baseCellRef, "=FALSE)");
|
|
216
275
|
}
|
|
217
276
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formula-locale-data.generated.d.ts","sourceRoot":"","sources":["../../../formula-locale/formula-locale-data.generated.ts"],"names":[],"mappings":"AAMA,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;8FAC8F;AAC9F,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,qFAAqF;IACrF,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,iGAAiG;IACjG,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;CAa5B,CAAC;AAEb,yGAAyG;AACzG,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,
|
|
1
|
+
{"version":3,"file":"formula-locale-data.generated.d.ts","sourceRoot":"","sources":["../../../formula-locale/formula-locale-data.generated.ts"],"names":[],"mappings":"AAMA,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;8FAC8F;AAC9F,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,qFAAqF;IACrF,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,iGAAiG;IACjG,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;CAa5B,CAAC;AAEb,yGAAyG;AACzG,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAu6KhF,CAAC"}
|
|
@@ -1,10 +1,38 @@
|
|
|
1
|
-
import type { DataValidationRule } from "@rowsncolumns/common-types";
|
|
1
|
+
import type { BooleanCondition, ConditionType, DataValidationRule } from "@rowsncolumns/common-types";
|
|
2
2
|
/**
|
|
3
3
|
* A leading apostrophe in a data-validation / conditional-format list entry is
|
|
4
4
|
* Excel's text prefix — `'000s` is the text "000s" and a bare `'` is empty
|
|
5
5
|
* text — never part of the value itself.
|
|
6
6
|
*/
|
|
7
7
|
export declare const stripDataValidationTextPrefix: (entry: string) => string;
|
|
8
|
+
/**
|
|
9
|
+
* A `ONE_OF_LIST` value that is a SOURCE FORMULA rather than literal items,
|
|
10
|
+
* returned trimmed with its leading `=` (`=RegionList`, `=$A$2:$A$9`,
|
|
11
|
+
* `=Sheet2!A1:A5`, `=INDIRECT("…")`). Excel's List type has one Source box
|
|
12
|
+
* that takes either literal items (`Yes,No`) or a formula starting with `=`;
|
|
13
|
+
* the "Dropdown" (`ONE_OF_LIST`) / "Dropdown (from a range)" (`ONE_OF_RANGE`)
|
|
14
|
+
* split means a `=…` typed into the literal dropdown is read the way Excel
|
|
15
|
+
* reads it — as a `ONE_OF_RANGE` over that source. A quoted literal
|
|
16
|
+
* (`"=a,b"`, Excel's quoted list), a `=` inside a later item (`a,=b`) and a
|
|
17
|
+
* bare `=` stay literal. Rust twin: `rnc_model::validation::one_of_list_formula_source`.
|
|
18
|
+
*/
|
|
19
|
+
export declare const getDataValidationListFormulaSource: (value: string | undefined | null) => string | undefined;
|
|
20
|
+
/**
|
|
21
|
+
* The condition type a rule behaves as: a `ONE_OF_LIST` whose first value is
|
|
22
|
+
* a source formula (`getDataValidationListFormulaSource`) behaves as
|
|
23
|
+
* `ONE_OF_RANGE`; every other condition is its own type. Rust twin:
|
|
24
|
+
* `rnc_model::validation::effective_condition_kind`.
|
|
25
|
+
*/
|
|
26
|
+
export declare const getEffectiveDataValidationConditionType: (condition: BooleanCondition | undefined | null) => ConditionType | undefined;
|
|
27
|
+
/**
|
|
28
|
+
* The reference a list rule draws its options from, or `undefined` when the
|
|
29
|
+
* rule is a literal item list (or not a list rule at all). `ONE_OF_RANGE` is
|
|
30
|
+
* always a reference (its value, `""` when missing); a `ONE_OF_LIST` is one
|
|
31
|
+
* when its value is a source formula (`=RegionList`) or a bare A1 reference
|
|
32
|
+
* (`$A$1:$A$5`). Shared by the dropdown options, the commit gate and
|
|
33
|
+
* `checkBooleanRule`, so the three always agree.
|
|
34
|
+
*/
|
|
35
|
+
export declare const getDataValidationListReference: (condition: BooleanCondition | undefined | null) => string | undefined;
|
|
8
36
|
/**
|
|
9
37
|
* Whether a cell's current text matches a ONE_OF_LIST option, with Excel's
|
|
10
38
|
* text-prefix semantics on BOTH sides: the option strips its leading `'`
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"data-validation.d.ts","sourceRoot":"","sources":["../../data-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"data-validation.d.ts","sourceRoot":"","sources":["../../data-validation.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,gBAAgB,EAChB,aAAa,EACb,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AAUpC;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,KAAG,MACd,CAAC;AAEjD;;;;;;;;;;GAUG;AACH,eAAO,MAAM,kCAAkC,GAC7C,OAAO,MAAM,GAAG,SAAS,GAAG,IAAI,KAC/B,MAAM,GAAG,SAKX,CAAC;AAEF;;;;;GAKG;AACH,eAAO,MAAM,uCAAuC,GAClD,WAAW,gBAAgB,GAAG,SAAS,GAAG,IAAI,KAC7C,aAAa,GAAG,SAIe,CAAC;AAEnC;;;;;;;GAOG;AACH,eAAO,MAAM,8BAA8B,GACzC,WAAW,gBAAgB,GAAG,SAAS,GAAG,IAAI,KAC7C,MAAM,GAAG,SAYX,CAAC;AAEF;;;;;;GAMG;AACH,eAAO,MAAM,oCAAoC,GAC/C,QAAQ,MAAM,GAAG,SAAS,GAAG,IAAI,EACjC,WAAW,MAAM,GAAG,SAAS,GAAG,IAAI,KACnC,OAKF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAmCG;AACH,eAAO,MAAM,2BAA2B,GACtC,MAAM,kBAAkB,GAAG,SAAS,YAKrC,CAAC;AAEF;;;;;;;;GAQG;AACH,eAAO,MAAM,6BAA6B,GACxC,MAAM,kBAAkB,GAAG,SAAS,EACpC,aAAa,MAAM,EACnB,SAAS,MAAM,uBAgBhB,CAAC"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { escapeConditionFormulaText, normalizeConditionOperand, } from "./condition-operand";
|
|
2
|
+
import { checkIfStringIsReference } from "./selection";
|
|
2
3
|
const FORMULA_PREDICATE_BASE_CELL_REF = "A1";
|
|
3
4
|
/**
|
|
4
5
|
* A leading apostrophe in a data-validation / conditional-format list entry is
|
|
@@ -6,6 +7,52 @@ const FORMULA_PREDICATE_BASE_CELL_REF = "A1";
|
|
|
6
7
|
* text — never part of the value itself.
|
|
7
8
|
*/
|
|
8
9
|
export const stripDataValidationTextPrefix = (entry) => entry.startsWith("'") ? entry.slice(1) : entry;
|
|
10
|
+
/**
|
|
11
|
+
* A `ONE_OF_LIST` value that is a SOURCE FORMULA rather than literal items,
|
|
12
|
+
* returned trimmed with its leading `=` (`=RegionList`, `=$A$2:$A$9`,
|
|
13
|
+
* `=Sheet2!A1:A5`, `=INDIRECT("…")`). Excel's List type has one Source box
|
|
14
|
+
* that takes either literal items (`Yes,No`) or a formula starting with `=`;
|
|
15
|
+
* the "Dropdown" (`ONE_OF_LIST`) / "Dropdown (from a range)" (`ONE_OF_RANGE`)
|
|
16
|
+
* split means a `=…` typed into the literal dropdown is read the way Excel
|
|
17
|
+
* reads it — as a `ONE_OF_RANGE` over that source. A quoted literal
|
|
18
|
+
* (`"=a,b"`, Excel's quoted list), a `=` inside a later item (`a,=b`) and a
|
|
19
|
+
* bare `=` stay literal. Rust twin: `rnc_model::validation::one_of_list_formula_source`.
|
|
20
|
+
*/
|
|
21
|
+
export const getDataValidationListFormulaSource = (value) => {
|
|
22
|
+
const trimmed = (value ?? "").trim();
|
|
23
|
+
return trimmed.startsWith("=") && trimmed.slice(1).trim()
|
|
24
|
+
? trimmed
|
|
25
|
+
: undefined;
|
|
26
|
+
};
|
|
27
|
+
/**
|
|
28
|
+
* The condition type a rule behaves as: a `ONE_OF_LIST` whose first value is
|
|
29
|
+
* a source formula (`getDataValidationListFormulaSource`) behaves as
|
|
30
|
+
* `ONE_OF_RANGE`; every other condition is its own type. Rust twin:
|
|
31
|
+
* `rnc_model::validation::effective_condition_kind`.
|
|
32
|
+
*/
|
|
33
|
+
export const getEffectiveDataValidationConditionType = (condition) => condition?.type === "ONE_OF_LIST" &&
|
|
34
|
+
getDataValidationListFormulaSource(condition.values?.[0]?.userEnteredValue)
|
|
35
|
+
? "ONE_OF_RANGE"
|
|
36
|
+
: condition?.type ?? undefined;
|
|
37
|
+
/**
|
|
38
|
+
* The reference a list rule draws its options from, or `undefined` when the
|
|
39
|
+
* rule is a literal item list (or not a list rule at all). `ONE_OF_RANGE` is
|
|
40
|
+
* always a reference (its value, `""` when missing); a `ONE_OF_LIST` is one
|
|
41
|
+
* when its value is a source formula (`=RegionList`) or a bare A1 reference
|
|
42
|
+
* (`$A$1:$A$5`). Shared by the dropdown options, the commit gate and
|
|
43
|
+
* `checkBooleanRule`, so the three always agree.
|
|
44
|
+
*/
|
|
45
|
+
export const getDataValidationListReference = (condition) => {
|
|
46
|
+
const firstValue = condition?.values?.[0]?.userEnteredValue;
|
|
47
|
+
if (getEffectiveDataValidationConditionType(condition) === "ONE_OF_RANGE") {
|
|
48
|
+
return getDataValidationListFormulaSource(firstValue) ?? firstValue ?? "";
|
|
49
|
+
}
|
|
50
|
+
if (condition?.type === "ONE_OF_LIST" &&
|
|
51
|
+
checkIfStringIsReference(firstValue)) {
|
|
52
|
+
return firstValue;
|
|
53
|
+
}
|
|
54
|
+
return undefined;
|
|
55
|
+
};
|
|
9
56
|
/**
|
|
10
57
|
* Whether a cell's current text matches a ONE_OF_LIST option, with Excel's
|
|
11
58
|
* text-prefix semantics on BOTH sides: the option strips its leading `'`
|
|
@@ -80,20 +127,23 @@ export const buildDataValidationExpression = (rule, baseCellRef, locale) => {
|
|
|
80
127
|
};
|
|
81
128
|
const buildDataValidationConditionExpression = (rule, baseCellRef, locale) => {
|
|
82
129
|
const condition = rule?.condition;
|
|
83
|
-
|
|
130
|
+
// A ONE_OF_LIST whose value is a source formula (`=RegionList`) compiles as
|
|
131
|
+
// the ONE_OF_RANGE over that source, as Excel's List type reads it.
|
|
132
|
+
const type = getEffectiveDataValidationConditionType(condition);
|
|
133
|
+
if (!condition || !type)
|
|
84
134
|
return undefined;
|
|
85
135
|
const values = condition.values ?? [];
|
|
86
136
|
const fromRaw = values[0]?.userEnteredValue;
|
|
87
137
|
const toRaw = values[1]?.userEnteredValue;
|
|
88
|
-
if (
|
|
138
|
+
if (type === "CUSTOM_FORMULA") {
|
|
89
139
|
const raw = fromRaw ?? "";
|
|
90
140
|
const trimmed = raw.trim();
|
|
91
141
|
if (!trimmed)
|
|
92
142
|
return undefined;
|
|
93
143
|
return trimmed.startsWith("=") ? trimmed : `=${trimmed}`;
|
|
94
144
|
}
|
|
95
|
-
const fromExpr = normalizeConditionOperand(fromRaw,
|
|
96
|
-
const toExpr = normalizeConditionOperand(toRaw,
|
|
145
|
+
const fromExpr = normalizeConditionOperand(fromRaw, type, locale);
|
|
146
|
+
const toExpr = normalizeConditionOperand(toRaw, type, locale);
|
|
97
147
|
if (!fromExpr && !toExpr)
|
|
98
148
|
return undefined;
|
|
99
149
|
const comparisonOperatorMap = {
|
|
@@ -112,51 +162,49 @@ const buildDataValidationConditionExpression = (rule, baseCellRef, locale) => {
|
|
|
112
162
|
TEXT_EQ: "=",
|
|
113
163
|
TEXT_NOT_EQ: "<>",
|
|
114
164
|
};
|
|
115
|
-
if (
|
|
116
|
-
condition.type === "DATE_BETWEEN") {
|
|
165
|
+
if (type === "NUMBER_BETWEEN" || type === "DATE_BETWEEN") {
|
|
117
166
|
if (!fromExpr || !toExpr)
|
|
118
167
|
return undefined;
|
|
119
168
|
return `=AND(${baseCellRef}>=${fromExpr},${baseCellRef}<=${toExpr})`;
|
|
120
169
|
}
|
|
121
|
-
if (
|
|
122
|
-
condition.type === "DATE_NOT_BETWEEN") {
|
|
170
|
+
if (type === "NUMBER_NOT_BETWEEN" || type === "DATE_NOT_BETWEEN") {
|
|
123
171
|
if (!fromExpr || !toExpr)
|
|
124
172
|
return undefined;
|
|
125
173
|
return `=OR(${baseCellRef}<${fromExpr},${baseCellRef}>${toExpr})`;
|
|
126
174
|
}
|
|
127
|
-
const comparisonOperator = comparisonOperatorMap[
|
|
175
|
+
const comparisonOperator = comparisonOperatorMap[type];
|
|
128
176
|
if (comparisonOperator) {
|
|
129
177
|
if (!fromExpr)
|
|
130
178
|
return undefined;
|
|
131
179
|
return `=${baseCellRef}${comparisonOperator}${fromExpr}`;
|
|
132
180
|
}
|
|
133
|
-
if (
|
|
181
|
+
if (type === "TEXT_CONTAINS") {
|
|
134
182
|
if (!fromExpr)
|
|
135
183
|
return undefined;
|
|
136
184
|
return `=ISNUMBER(SEARCH(${fromExpr},${baseCellRef}))`;
|
|
137
185
|
}
|
|
138
|
-
if (
|
|
186
|
+
if (type === "TEXT_NOT_CONTAINS") {
|
|
139
187
|
if (!fromExpr)
|
|
140
188
|
return undefined;
|
|
141
189
|
return `=NOT(ISNUMBER(SEARCH(${fromExpr},${baseCellRef})))`;
|
|
142
190
|
}
|
|
143
|
-
if (
|
|
191
|
+
if (type === "TEXT_STARTS_WITH") {
|
|
144
192
|
if (!fromExpr)
|
|
145
193
|
return undefined;
|
|
146
194
|
return `=LEFT(${baseCellRef},LEN(${fromExpr}))=${fromExpr}`;
|
|
147
195
|
}
|
|
148
|
-
if (
|
|
196
|
+
if (type === "TEXT_ENDS_WITH") {
|
|
149
197
|
if (!fromExpr)
|
|
150
198
|
return undefined;
|
|
151
199
|
return `=RIGHT(${baseCellRef},LEN(${fromExpr}))=${fromExpr}`;
|
|
152
200
|
}
|
|
153
|
-
if (
|
|
201
|
+
if (type === "TEXT_IS_EMAIL") {
|
|
154
202
|
return `=ISNUMBER(SEARCH("@",${baseCellRef}))`;
|
|
155
203
|
}
|
|
156
|
-
if (
|
|
204
|
+
if (type === "TEXT_IS_URL") {
|
|
157
205
|
return `=OR(LEFT(${baseCellRef},7)="http://",LEFT(${baseCellRef},8)="https://")`;
|
|
158
206
|
}
|
|
159
|
-
if (
|
|
207
|
+
if (type === "ONE_OF_RANGE") {
|
|
160
208
|
if (!fromExpr)
|
|
161
209
|
return undefined;
|
|
162
210
|
if (rule?.allowBlank) {
|
|
@@ -164,7 +212,7 @@ const buildDataValidationConditionExpression = (rule, baseCellRef, locale) => {
|
|
|
164
212
|
}
|
|
165
213
|
return `=COUNTIF(${fromExpr},${baseCellRef})>0`;
|
|
166
214
|
}
|
|
167
|
-
if (
|
|
215
|
+
if (type === "ONE_OF_LIST") {
|
|
168
216
|
const entries = fromRaw
|
|
169
217
|
? fromRaw.split(",").map((entry) => entry.trim())
|
|
170
218
|
: [];
|
|
@@ -181,10 +229,14 @@ const buildDataValidationConditionExpression = (rule, baseCellRef, locale) => {
|
|
|
181
229
|
? [textCondition, `${baseCellRef}="'"`]
|
|
182
230
|
: [textCondition];
|
|
183
231
|
}
|
|
232
|
+
// A list ITEM is never a formula (a source formula is the whole value,
|
|
233
|
+
// see `getEffectiveDataValidationConditionType`): `"=a,b"` and `a,=b`
|
|
234
|
+
// list the text `=a` / `=b`.
|
|
235
|
+
if (entry.startsWith("=")) {
|
|
236
|
+
return [`${baseCellRef}="${escapeConditionFormulaText(entry)}"`];
|
|
237
|
+
}
|
|
184
238
|
return entry
|
|
185
|
-
? [
|
|
186
|
-
`${baseCellRef}=${normalizeConditionOperand(entry, condition.type, locale)}`,
|
|
187
|
-
]
|
|
239
|
+
? [`${baseCellRef}=${normalizeConditionOperand(entry, type, locale)}`]
|
|
188
240
|
: [];
|
|
189
241
|
})
|
|
190
242
|
.filter((entry) => Boolean(entry));
|
|
@@ -194,13 +246,13 @@ const buildDataValidationConditionExpression = (rule, baseCellRef, locale) => {
|
|
|
194
246
|
? `=${conditions[0]}`
|
|
195
247
|
: `=OR(${conditions.join(",")})`;
|
|
196
248
|
}
|
|
197
|
-
if (
|
|
249
|
+
if (type === "BLANK") {
|
|
198
250
|
return `=${baseCellRef}=""`;
|
|
199
251
|
}
|
|
200
|
-
if (
|
|
252
|
+
if (type === "NOT_BLANK") {
|
|
201
253
|
return `=${baseCellRef}<>""`;
|
|
202
254
|
}
|
|
203
|
-
if (
|
|
255
|
+
if (type === "BOOLEAN") {
|
|
204
256
|
return `=OR(${baseCellRef}=TRUE,${baseCellRef}=FALSE)`;
|
|
205
257
|
}
|
|
206
258
|
return undefined;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"formula-locale-data.generated.d.ts","sourceRoot":"","sources":["../../../formula-locale/formula-locale-data.generated.ts"],"names":[],"mappings":"AAMA,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;8FAC8F;AAC9F,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,qFAAqF;IACrF,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,iGAAiG;IACjG,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;CAa5B,CAAC;AAEb,yGAAyG;AACzG,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,
|
|
1
|
+
{"version":3,"file":"formula-locale-data.generated.d.ts","sourceRoot":"","sources":["../../../formula-locale/formula-locale-data.generated.ts"],"names":[],"mappings":"AAMA,oFAAoF;AACpF,MAAM,WAAW,uBAAuB;IACtC,2DAA2D;IAC3D,gBAAgB,EAAE,MAAM,CAAC;IACzB,+FAA+F;IAC/F,iBAAiB,EAAE,MAAM,CAAC;IAC1B,8EAA8E;IAC9E,oBAAoB,EAAE,MAAM,CAAC;IAC7B,2EAA2E;IAC3E,iBAAiB,EAAE,MAAM,CAAC;CAC3B;AAED;8FAC8F;AAC9F,MAAM,WAAW,sBAAsB;IACrC,qDAAqD;IACrD,IAAI,EAAE,MAAM,CAAC;IACb,+FAA+F;IAC/F,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,MAAM,EAAE,uBAAuB,CAAC;IAChC,qFAAqF;IACrF,SAAS,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC7C,iFAAiF;IACjF,MAAM,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;IAC1C,iGAAiG;IACjG,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CAC/B;AAED,qDAAqD;AACrD,eAAO,MAAM,2BAA2B;;;;;;;;;;;;;CAa5B,CAAC;AAEb,yGAAyG;AACzG,eAAO,MAAM,mBAAmB,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAu6KhF,CAAC"}
|