@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.
@@ -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,EAEV,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AASpC;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,KAAG,MACd,CAAC;AAEjD;;;;;;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
+ {"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
- if (!(condition === null || condition === void 0 ? void 0 : condition.type))
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 (condition.type === "CUSTOM_FORMULA") {
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, condition.type, locale);
107
- var toExpr = (0, condition_operand_1.normalizeConditionOperand)(toRaw, condition.type, locale);
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 (condition.type === "NUMBER_BETWEEN" ||
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 (condition.type === "NUMBER_NOT_BETWEEN" ||
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[condition.type];
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 (condition.type === "TEXT_CONTAINS") {
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 (condition.type === "TEXT_NOT_CONTAINS") {
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 (condition.type === "TEXT_STARTS_WITH") {
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 (condition.type === "TEXT_ENDS_WITH") {
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 (condition.type === "TEXT_IS_EMAIL") {
219
+ if (type === "TEXT_IS_EMAIL") {
165
220
  return "=ISNUMBER(SEARCH(\"@\",".concat(baseCellRef, "))");
166
221
  }
167
- if (condition.type === "TEXT_IS_URL") {
222
+ if (type === "TEXT_IS_URL") {
168
223
  return "=OR(LEFT(".concat(baseCellRef, ",7)=\"http://\",LEFT(").concat(baseCellRef, ",8)=\"https://\")");
169
224
  }
170
- if (condition.type === "ONE_OF_RANGE") {
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 (condition.type === "ONE_OF_LIST") {
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 (condition.type === "BLANK") {
267
+ if (type === "BLANK") {
209
268
  return "=".concat(baseCellRef, "=\"\"");
210
269
  }
211
- if (condition.type === "NOT_BLANK") {
270
+ if (type === "NOT_BLANK") {
212
271
  return "=".concat(baseCellRef, "<>\"\"");
213
272
  }
214
- if (condition.type === "BOOLEAN") {
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,CAs6KhF,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"}
@@ -1419,6 +1419,7 @@ exports.FORMULA_LOCALE_DATA = {
1419
1419
  "ISNUMBER": "ESTNUM",
1420
1420
  "ISO.CEILING": "ISO.PLAFOND",
1421
1421
  "ISODD": "EST.IMPAIR",
1422
+ "ISOMITTED": "ISOMITTED",
1422
1423
  "ISOWEEKNUM": "NO.SEMAINE.ISO",
1423
1424
  "ISPMT": "ISPMT",
1424
1425
  "ISREF": "ESTREF",
@@ -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,EAEV,kBAAkB,EACnB,MAAM,4BAA4B,CAAC;AASpC;;;;GAIG;AACH,eAAO,MAAM,6BAA6B,GAAI,OAAO,MAAM,KAAG,MACd,CAAC;AAEjD;;;;;;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
+ {"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
- if (!condition?.type)
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 (condition.type === "CUSTOM_FORMULA") {
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, condition.type, locale);
96
- const toExpr = normalizeConditionOperand(toRaw, condition.type, locale);
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 (condition.type === "NUMBER_BETWEEN" ||
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 (condition.type === "NUMBER_NOT_BETWEEN" ||
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[condition.type];
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 (condition.type === "TEXT_CONTAINS") {
181
+ if (type === "TEXT_CONTAINS") {
134
182
  if (!fromExpr)
135
183
  return undefined;
136
184
  return `=ISNUMBER(SEARCH(${fromExpr},${baseCellRef}))`;
137
185
  }
138
- if (condition.type === "TEXT_NOT_CONTAINS") {
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 (condition.type === "TEXT_STARTS_WITH") {
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 (condition.type === "TEXT_ENDS_WITH") {
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 (condition.type === "TEXT_IS_EMAIL") {
201
+ if (type === "TEXT_IS_EMAIL") {
154
202
  return `=ISNUMBER(SEARCH("@",${baseCellRef}))`;
155
203
  }
156
- if (condition.type === "TEXT_IS_URL") {
204
+ if (type === "TEXT_IS_URL") {
157
205
  return `=OR(LEFT(${baseCellRef},7)="http://",LEFT(${baseCellRef},8)="https://")`;
158
206
  }
159
- if (condition.type === "ONE_OF_RANGE") {
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 (condition.type === "ONE_OF_LIST") {
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 (condition.type === "BLANK") {
249
+ if (type === "BLANK") {
198
250
  return `=${baseCellRef}=""`;
199
251
  }
200
- if (condition.type === "NOT_BLANK") {
252
+ if (type === "NOT_BLANK") {
201
253
  return `=${baseCellRef}<>""`;
202
254
  }
203
- if (condition.type === "BOOLEAN") {
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,CAs6KhF,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"}
@@ -1416,6 +1416,7 @@ export const FORMULA_LOCALE_DATA = {
1416
1416
  "ISNUMBER": "ESTNUM",
1417
1417
  "ISO.CEILING": "ISO.PLAFOND",
1418
1418
  "ISODD": "EST.IMPAIR",
1419
+ "ISOMITTED": "ISOMITTED",
1419
1420
  "ISOWEEKNUM": "NO.SEMAINE.ISO",
1420
1421
  "ISPMT": "ISPMT",
1421
1422
  "ISREF": "ESTREF",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@rowsncolumns/utils",
3
- "version": "9.5.5",
3
+ "version": "9.5.7",
4
4
  "author": "Vinay M",
5
5
  "license": "SEE LICENSE IN LICENSE.md",
6
6
  "main": "./dist/cjs/index.js",