@marktiderman/genesis-forms 0.4.0 → 0.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/README.md +12 -2
- package/dist/destinations.cjs.map +1 -1
- package/dist/destinations.js.map +1 -1
- package/dist/index.cjs +124 -20
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +12 -2
- package/dist/index.d.ts +12 -2
- package/dist/index.js +123 -21
- package/dist/index.js.map +1 -1
- package/dist/server.cjs +121 -23
- package/dist/server.cjs.map +1 -1
- package/dist/server.js +121 -23
- package/dist/server.js.map +1 -1
- package/dist/testing.cjs +121 -23
- package/dist/testing.cjs.map +1 -1
- package/dist/testing.js +121 -23
- package/dist/testing.js.map +1 -1
- package/package.json +1 -1
package/dist/index.d.cts
CHANGED
|
@@ -553,6 +553,8 @@ declare const CALCULATED_TYPE = "calculated";
|
|
|
553
553
|
*/
|
|
554
554
|
declare const COMPUTED_FIELD_TYPES: readonly ["calculated"];
|
|
555
555
|
type CalculatedFormat = "number" | "percent" | "text";
|
|
556
|
+
/** Longest the formulas of one form may be, all together (`parseForm` checks it). */
|
|
557
|
+
declare const MAX_FORM_FORMULA_LENGTH = 20000;
|
|
556
558
|
/** Most decimal places a calculated value may keep. */
|
|
557
559
|
declare const MAX_CALCULATED_DECIMALS = 10;
|
|
558
560
|
interface CalculatedProps {
|
|
@@ -577,10 +579,18 @@ declare function formatCalculated(value: Json | undefined, field: FieldBlock): s
|
|
|
577
579
|
* server can't make every formula over it slow.
|
|
578
580
|
*/
|
|
579
581
|
declare const MAX_FORMULA_ITEMS = 10000;
|
|
582
|
+
/**
|
|
583
|
+
* Most list items and table rows all of a form's formulas read in one go
|
|
584
|
+
* (each answer and column counted once, in form order). A formula that reads
|
|
585
|
+
* an answer past the limit, or one over `MAX_FORMULA_ITEMS`, has no value
|
|
586
|
+
* (blank, never a partial total), so many big answers can't make working
|
|
587
|
+
* the values out slow either.
|
|
588
|
+
*/
|
|
589
|
+
declare const MAX_SETTLE_ITEMS = 50000;
|
|
580
590
|
/**
|
|
581
591
|
* The value a formula reads for an answer: numbers and text as they are, a
|
|
582
592
|
* list's items, one table column's cells. A list or table of more than
|
|
583
|
-
* `MAX_FORMULA_ITEMS` reads as blank.
|
|
593
|
+
* `MAX_FORMULA_ITEMS` reads as blank. Each call builds a new list.
|
|
584
594
|
*/
|
|
585
595
|
declare function formulaInput(value: Json | undefined, column?: string): FormulaValue;
|
|
586
596
|
|
|
@@ -666,4 +676,4 @@ declare function explain(source: FormEngine | ExplainInput, blockId: string, opt
|
|
|
666
676
|
/** A condition as a plain-English clause: `contact_me is not Yes`. */
|
|
667
677
|
declare function describeCondition(condition: Condition, def: FormDefinition, fields?: Map<string, FieldBlock>): string;
|
|
668
678
|
|
|
669
|
-
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|
|
679
|
+
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_FORM_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_SETTLE_ITEMS, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|
package/dist/index.d.ts
CHANGED
|
@@ -553,6 +553,8 @@ declare const CALCULATED_TYPE = "calculated";
|
|
|
553
553
|
*/
|
|
554
554
|
declare const COMPUTED_FIELD_TYPES: readonly ["calculated"];
|
|
555
555
|
type CalculatedFormat = "number" | "percent" | "text";
|
|
556
|
+
/** Longest the formulas of one form may be, all together (`parseForm` checks it). */
|
|
557
|
+
declare const MAX_FORM_FORMULA_LENGTH = 20000;
|
|
556
558
|
/** Most decimal places a calculated value may keep. */
|
|
557
559
|
declare const MAX_CALCULATED_DECIMALS = 10;
|
|
558
560
|
interface CalculatedProps {
|
|
@@ -577,10 +579,18 @@ declare function formatCalculated(value: Json | undefined, field: FieldBlock): s
|
|
|
577
579
|
* server can't make every formula over it slow.
|
|
578
580
|
*/
|
|
579
581
|
declare const MAX_FORMULA_ITEMS = 10000;
|
|
582
|
+
/**
|
|
583
|
+
* Most list items and table rows all of a form's formulas read in one go
|
|
584
|
+
* (each answer and column counted once, in form order). A formula that reads
|
|
585
|
+
* an answer past the limit, or one over `MAX_FORMULA_ITEMS`, has no value
|
|
586
|
+
* (blank, never a partial total), so many big answers can't make working
|
|
587
|
+
* the values out slow either.
|
|
588
|
+
*/
|
|
589
|
+
declare const MAX_SETTLE_ITEMS = 50000;
|
|
580
590
|
/**
|
|
581
591
|
* The value a formula reads for an answer: numbers and text as they are, a
|
|
582
592
|
* list's items, one table column's cells. A list or table of more than
|
|
583
|
-
* `MAX_FORMULA_ITEMS` reads as blank.
|
|
593
|
+
* `MAX_FORMULA_ITEMS` reads as blank. Each call builds a new list.
|
|
584
594
|
*/
|
|
585
595
|
declare function formulaInput(value: Json | undefined, column?: string): FormulaValue;
|
|
586
596
|
|
|
@@ -666,4 +676,4 @@ declare function explain(source: FormEngine | ExplainInput, blockId: string, opt
|
|
|
666
676
|
/** A condition as a plain-English clause: `contact_me is not Yes`. */
|
|
667
677
|
declare function describeCondition(condition: Condition, def: FormDefinition, fields?: Map<string, FieldBlock>): string;
|
|
668
678
|
|
|
669
|
-
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|
|
679
|
+
export { type AnswersOf, Block, CALCULATED_TYPE, COMPUTED_FIELD_TYPES, type CalculatedFormat, type CalculatedProps, type ChoiceFieldOptions, type ChoiceOption, type CoerceHiddenOptions, type CoercedHidden, Condition, ContentBlock, Ending, type ExplainInput, type ExplainOptions, type Explanation, FORMULA_FUNCTIONS, FieldBlock, type FieldOptions, type FieldSpec, type FieldTypeManifest, type FieldValidation, FieldValidator, type Form, FormDefinition, FormEngine, type FormInput, type FormIssue, FormLayout, FormSettings, type FormulaFunction, type FormulaNode, type FormulaParseResult, type FormulaReader, type FormulaRef, type FormulaValue, HIGHLIGHT_NOTE_MESSAGE, HiddenInput, type Highlight, Json, type JumpTrace, type KeyResolver, LogicRule, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_FORM_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_SETTLE_ITEMS, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, type MediaNote, Operator, PageBreakBlock, type ParseResult, type PathResult, type RuleSpec, type RuleTrace, STRUCTURED_FIELD_TYPES, type TableColumn, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isIsoDate, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, when };
|
package/dist/index.js
CHANGED
|
@@ -62,6 +62,7 @@ function tokenize(source) {
|
|
|
62
62
|
i++;
|
|
63
63
|
while (isDigit(source[i] ?? "")) i++;
|
|
64
64
|
}
|
|
65
|
+
if (isIdStart(source[i] ?? "")) throw new FormulaError("Write a number in digits only, like 1000000.", at);
|
|
65
66
|
const v = Number(source.slice(at, i));
|
|
66
67
|
if (!Number.isFinite(v)) throw new FormulaError("This number is too large.", at);
|
|
67
68
|
tokens.push({ t: "num", v, at });
|
|
@@ -291,6 +292,27 @@ function numbersIn(values, out = []) {
|
|
|
291
292
|
}
|
|
292
293
|
return out;
|
|
293
294
|
}
|
|
295
|
+
var listTotals = /* @__PURE__ */ new WeakMap();
|
|
296
|
+
var ownLists = /* @__PURE__ */ new WeakSet();
|
|
297
|
+
function ownFormulaList(list) {
|
|
298
|
+
Object.freeze(list);
|
|
299
|
+
ownLists.add(list);
|
|
300
|
+
return list;
|
|
301
|
+
}
|
|
302
|
+
function totalsOf(list) {
|
|
303
|
+
const own2 = ownLists.has(list);
|
|
304
|
+
let t = own2 ? listTotals.get(list) : void 0;
|
|
305
|
+
if (t) return t;
|
|
306
|
+
const nums = numbersIn(list);
|
|
307
|
+
t = { sum: 0, count: nums.length, min: Infinity, max: -Infinity };
|
|
308
|
+
for (const n of nums) {
|
|
309
|
+
t.sum += n;
|
|
310
|
+
if (n < t.min) t.min = n;
|
|
311
|
+
if (n > t.max) t.max = n;
|
|
312
|
+
}
|
|
313
|
+
if (own2) listTotals.set(list, t);
|
|
314
|
+
return t;
|
|
315
|
+
}
|
|
294
316
|
function compare(op, a, b) {
|
|
295
317
|
const blank2 = (v) => v === null || Array.isArray(v) || typeof v === "string" && v.trim() === "";
|
|
296
318
|
if (blank2(a) || blank2(b)) return op === "!=";
|
|
@@ -315,7 +337,7 @@ function evaluateFormula(ast, read) {
|
|
|
315
337
|
case "text":
|
|
316
338
|
return node.value;
|
|
317
339
|
case "ref":
|
|
318
|
-
return read(node
|
|
340
|
+
return read(node);
|
|
319
341
|
case "unary": {
|
|
320
342
|
const n = formulaNumber(scalar(run(node.arg)));
|
|
321
343
|
return n === null ? null : -n;
|
|
@@ -323,12 +345,31 @@ function evaluateFormula(ast, read) {
|
|
|
323
345
|
case "if":
|
|
324
346
|
return truthy(run(node.test)) ? run(node.then) : run(node.else);
|
|
325
347
|
case "call": {
|
|
326
|
-
|
|
327
|
-
|
|
348
|
+
let total = 0;
|
|
349
|
+
let count = 0;
|
|
350
|
+
let min = Infinity;
|
|
351
|
+
let max = -Infinity;
|
|
352
|
+
for (const arg of node.args) {
|
|
353
|
+
const v = run(arg);
|
|
354
|
+
if (Array.isArray(v)) {
|
|
355
|
+
const t = totalsOf(v);
|
|
356
|
+
total += t.sum;
|
|
357
|
+
count += t.count;
|
|
358
|
+
if (t.min < min) min = t.min;
|
|
359
|
+
if (t.max > max) max = t.max;
|
|
360
|
+
continue;
|
|
361
|
+
}
|
|
362
|
+
const n = formulaNumber(v);
|
|
363
|
+
if (n === null) continue;
|
|
364
|
+
total += n;
|
|
365
|
+
count++;
|
|
366
|
+
if (n < min) min = n;
|
|
367
|
+
if (n > max) max = n;
|
|
368
|
+
}
|
|
328
369
|
if (node.fn === "sum") return finite(total);
|
|
329
|
-
if (!
|
|
330
|
-
if (node.fn === "avg") return finite(total /
|
|
331
|
-
return
|
|
370
|
+
if (!count) return null;
|
|
371
|
+
if (node.fn === "avg") return finite(total / count);
|
|
372
|
+
return node.fn === "min" ? min : max;
|
|
332
373
|
}
|
|
333
374
|
case "binary": {
|
|
334
375
|
const a = run(node.left);
|
|
@@ -356,6 +397,7 @@ function evaluateFormula(ast, read) {
|
|
|
356
397
|
// src/calculated.ts
|
|
357
398
|
var CALCULATED_TYPE = "calculated";
|
|
358
399
|
var COMPUTED_FIELD_TYPES = [CALCULATED_TYPE];
|
|
400
|
+
var MAX_FORM_FORMULA_LENGTH = 2e4;
|
|
359
401
|
var MAX_CALCULATED_DECIMALS = 10;
|
|
360
402
|
function calculatedProps(field2) {
|
|
361
403
|
const p = field2.props ?? {};
|
|
@@ -394,23 +436,45 @@ function formatCalculated(value, field2) {
|
|
|
394
436
|
return typeof value === "string" ? value : "";
|
|
395
437
|
}
|
|
396
438
|
var MAX_FORMULA_ITEMS = 1e4;
|
|
439
|
+
var MAX_SETTLE_ITEMS = 5e4;
|
|
440
|
+
var extract = (value, column) => column !== void 0 ? value.flatMap((row) => {
|
|
441
|
+
if (!row || typeof row !== "object" || Array.isArray(row)) return [];
|
|
442
|
+
const cell = row[column];
|
|
443
|
+
return typeof cell === "string" || typeof cell === "number" ? [cell] : [];
|
|
444
|
+
}) : value.flatMap((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" ? [v] : []);
|
|
445
|
+
var extracted = /* @__PURE__ */ new WeakMap();
|
|
446
|
+
function cachedList(value, column) {
|
|
447
|
+
let byColumn = extracted.get(value);
|
|
448
|
+
if (!byColumn) extracted.set(value, byColumn = /* @__PURE__ */ new Map());
|
|
449
|
+
const key = column ?? "";
|
|
450
|
+
let list = byColumn.get(key);
|
|
451
|
+
if (!list) byColumn.set(key, list = ownFormulaList(extract(value, column)));
|
|
452
|
+
return list;
|
|
453
|
+
}
|
|
454
|
+
function readAnswer(value, column) {
|
|
455
|
+
if (Array.isArray(value)) return cachedList(value, column);
|
|
456
|
+
return column !== void 0 ? null : formulaInput(value);
|
|
457
|
+
}
|
|
397
458
|
function formulaInput(value, column) {
|
|
398
459
|
if (value === void 0 || value === null) return null;
|
|
399
460
|
if (Array.isArray(value) && value.length > MAX_FORMULA_ITEMS) return null;
|
|
400
461
|
if (column !== void 0) {
|
|
401
462
|
if (!Array.isArray(value)) return null;
|
|
402
|
-
return value
|
|
403
|
-
if (!row || typeof row !== "object" || Array.isArray(row)) return [];
|
|
404
|
-
const cell = row[column];
|
|
405
|
-
return typeof cell === "string" || typeof cell === "number" ? [cell] : [];
|
|
406
|
-
});
|
|
407
|
-
}
|
|
408
|
-
if (Array.isArray(value)) {
|
|
409
|
-
return value.flatMap((v) => typeof v === "string" || typeof v === "number" || typeof v === "boolean" ? [v] : []);
|
|
463
|
+
return extract(value, column);
|
|
410
464
|
}
|
|
465
|
+
if (Array.isArray(value)) return extract(value, void 0);
|
|
411
466
|
return typeof value === "object" ? null : value;
|
|
412
467
|
}
|
|
468
|
+
function refNodes(node, out = []) {
|
|
469
|
+
if (node.kind === "ref") out.push(node);
|
|
470
|
+
else if (node.kind === "unary") refNodes(node.arg, out);
|
|
471
|
+
else if (node.kind === "binary") refNodes(node.left, out), refNodes(node.right, out);
|
|
472
|
+
else if (node.kind === "if") refNodes(node.test, out), refNodes(node.then, out), refNodes(node.else, out);
|
|
473
|
+
else if (node.kind === "call") for (const a of node.args) refNodes(a, out);
|
|
474
|
+
return out;
|
|
475
|
+
}
|
|
413
476
|
var UNREAD = /* @__PURE__ */ Symbol("unread");
|
|
477
|
+
var OVER = /* @__PURE__ */ Symbol("over");
|
|
414
478
|
function calculator(definition) {
|
|
415
479
|
const compiled = [];
|
|
416
480
|
const idByKey = /* @__PURE__ */ new Map();
|
|
@@ -421,14 +485,39 @@ function calculator(definition) {
|
|
|
421
485
|
for (const block of definition.blocks) {
|
|
422
486
|
if (block.kind !== "field" || !isCalculated(block)) continue;
|
|
423
487
|
const parsed = parseFormula(calculatedProps(block).formula);
|
|
424
|
-
const reads =
|
|
425
|
-
|
|
488
|
+
const reads = [];
|
|
489
|
+
const slots = /* @__PURE__ */ new Map();
|
|
490
|
+
const byKey = /* @__PURE__ */ new Map();
|
|
491
|
+
for (const ref of parsed.ok ? refNodes(parsed.ast) : []) {
|
|
492
|
+
const id = idByKey.get(ref.key);
|
|
493
|
+
const key = `${id ?? ""}\0${ref.column ?? ""}`;
|
|
494
|
+
let slot = byKey.get(key);
|
|
495
|
+
if (slot === void 0) {
|
|
496
|
+
slot = reads.push({ id, column: ref.column, key }) - 1;
|
|
497
|
+
byKey.set(key, slot);
|
|
498
|
+
}
|
|
499
|
+
slots.set(ref, slot);
|
|
500
|
+
}
|
|
501
|
+
compiled.push({ field: block, ast: parsed.ok ? parsed.ast : null, reads, slots, last: null });
|
|
426
502
|
}
|
|
427
503
|
const withCalculated = (values, path) => {
|
|
428
504
|
if (!compiled.length) return values;
|
|
429
505
|
const visible = new Set(path);
|
|
430
506
|
let next = values;
|
|
431
|
-
|
|
507
|
+
let budget = MAX_SETTLE_ITEMS;
|
|
508
|
+
const within = /* @__PURE__ */ new Map();
|
|
509
|
+
const input = ({ id, key }) => {
|
|
510
|
+
if (id === void 0 || !visible.has(id) || !Object.prototype.hasOwnProperty.call(next, id)) return UNREAD;
|
|
511
|
+
const value = next[id];
|
|
512
|
+
if (!Array.isArray(value)) return value;
|
|
513
|
+
let ok = within.get(key);
|
|
514
|
+
if (ok === void 0) {
|
|
515
|
+
ok = value.length <= MAX_FORMULA_ITEMS && value.length <= budget;
|
|
516
|
+
if (ok) budget -= value.length;
|
|
517
|
+
within.set(key, ok);
|
|
518
|
+
}
|
|
519
|
+
return ok ? value : OVER;
|
|
520
|
+
};
|
|
432
521
|
for (const entry of compiled) {
|
|
433
522
|
const { field: field2, ast } = entry;
|
|
434
523
|
const inputs = entry.reads.map(input);
|
|
@@ -436,11 +525,18 @@ function calculator(definition) {
|
|
|
436
525
|
if (entry.last && entry.last.inputs.length === inputs.length && entry.last.inputs.every((v, i) => v === inputs[i])) {
|
|
437
526
|
value = entry.last.value;
|
|
438
527
|
} else {
|
|
528
|
+
const resolved = new Array(inputs.length);
|
|
439
529
|
const read = (ref) => {
|
|
440
|
-
const
|
|
441
|
-
|
|
530
|
+
const slot = entry.slots.get(ref);
|
|
531
|
+
if (slot === void 0) return null;
|
|
532
|
+
let v = resolved[slot];
|
|
533
|
+
if (v === void 0) {
|
|
534
|
+
const raw = inputs[slot];
|
|
535
|
+
v = resolved[slot] = raw === UNREAD ? null : readAnswer(raw, entry.reads[slot].column);
|
|
536
|
+
}
|
|
537
|
+
return v;
|
|
442
538
|
};
|
|
443
|
-
value = ast ? calculatedValue(evaluateFormula(ast, read), field2) : void 0;
|
|
539
|
+
value = ast && !inputs.includes(OVER) ? calculatedValue(evaluateFormula(ast, read), field2) : void 0;
|
|
444
540
|
entry.last = { inputs, value };
|
|
445
541
|
}
|
|
446
542
|
const current = Object.prototype.hasOwnProperty.call(next, field2.id) ? next[field2.id] : void 0;
|
|
@@ -1421,9 +1517,15 @@ function parseForm(input) {
|
|
|
1421
1517
|
issue(`${path}.kind`, "Unknown block kind.");
|
|
1422
1518
|
}
|
|
1423
1519
|
});
|
|
1520
|
+
let formulaChars = 0;
|
|
1424
1521
|
input.blocks.forEach((block, i) => {
|
|
1425
1522
|
if (!isObject2(block) || block.kind !== "field" || block.type !== CALCULATED_TYPE) return;
|
|
1426
1523
|
const path = `blocks[${i}].props.formula`;
|
|
1524
|
+
const source = isObject2(block.props) && typeof block.props.formula === "string" ? block.props.formula : "";
|
|
1525
|
+
formulaChars += source.length;
|
|
1526
|
+
if (formulaChars > MAX_FORM_FORMULA_LENGTH && formulaChars - source.length <= MAX_FORM_FORMULA_LENGTH) {
|
|
1527
|
+
issue(path, `The form's formulas together are over ${MAX_FORM_FORMULA_LENGTH} characters; shorten some, or work part out once in an earlier calculated field.`);
|
|
1528
|
+
}
|
|
1427
1529
|
if (block.required === true) {
|
|
1428
1530
|
warnings.push({ path: `blocks[${i}].required`, message: "A calculated field is worked out, not answered, so it is never required." });
|
|
1429
1531
|
}
|
|
@@ -2258,6 +2360,6 @@ function describeCondition(condition, def, fields = fieldMap(def)) {
|
|
|
2258
2360
|
return `${left} ${op} ${right}`;
|
|
2259
2361
|
}
|
|
2260
2362
|
|
|
2261
|
-
export { CALCULATED_TYPE, COMPUTED_FIELD_TYPES, FORMULA_FUNCTIONS, HIGHLIGHT_NOTE_MESSAGE, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, REQUIRED_MESSAGE, STRUCTURED_FIELD_TYPES, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, createForm, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isFormEvent, isIsoDate, isJson, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, replay, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, validateField, when };
|
|
2363
|
+
export { CALCULATED_TYPE, COMPUTED_FIELD_TYPES, FORMULA_FUNCTIONS, HIGHLIGHT_NOTE_MESSAGE, MAX_CALCULATED_DECIMALS, MAX_FORMULA_ITEMS, MAX_FORMULA_LENGTH, MAX_FORM_FORMULA_LENGTH, MAX_HIDDEN_STRING_LENGTH, MAX_HIGHLIGHT_NOTE_LENGTH, MAX_HIGHLIGHT_QUOTE_LENGTH, MAX_SETTLE_ITEMS, MAX_TABLE_CELL_LENGTH, MAX_TABLE_COLUMNS, MAX_TIMESTAMP_SECONDS, REQUIRED_MESSAGE, STRUCTURED_FIELD_TYPES, calculatedProps, calculatedValue, canonicalJson, choiceOptions, coerceHidden, coerceHiddenValue, computePath, createForm, dateLimits, defineForm, describeCondition, evaluate, evaluateFormula, explain, f, fingerprint, formatCalculated, formatTimestamp, formulaInput, formulaNumber, formulaRefs, getFieldType, isEmptyValue, isFormEvent, isIsoDate, isJson, isSensitive, listFieldTypes, listLimits, normalizeValue, numberLimits, parseForm, parseFormula, parseTimestamp, ratingDisplay, recall, registerFieldType, renameFormulaKey, replay, ruleVisible, scaleLabels, steps, summarizeValue, tableColumns, tableLimits, validateField, when };
|
|
2262
2364
|
//# sourceMappingURL=index.js.map
|
|
2263
2365
|
//# sourceMappingURL=index.js.map
|