form0-core 0.3.1 → 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.
Files changed (60) hide show
  1. package/README.md +75 -0
  2. package/package.json +5 -2
  3. package/src/authoring/form-authoring.js +124 -13
  4. package/src/builtins/builtin-definitions.js +320 -0
  5. package/src/builtins/choice/choicelabel.js +2 -17
  6. package/src/builtins/choice/choicelabels.js +2 -17
  7. package/src/builtins/choice/choicevalue.js +2 -20
  8. package/src/builtins/choice/choicevalues.js +2 -17
  9. package/src/builtins/choice/hasother.js +2 -20
  10. package/src/builtins/choice/other.js +2 -20
  11. package/src/builtins/control/eval.js +78 -31
  12. package/src/builtins/control/setresult.js +29 -17
  13. package/src/builtins/date/dateadd.js +24 -0
  14. package/src/builtins/date/days.js +22 -0
  15. package/src/builtins/event/control/off.js +3 -27
  16. package/src/builtins/event/control/on.js +3 -19
  17. package/src/builtins/event/event-operations-collector.js +33 -9
  18. package/src/builtins/event/field/setvalue.js +3 -32
  19. package/src/builtins/event/ui/alert.js +3 -11
  20. package/src/builtins/logical/and.js +2 -17
  21. package/src/builtins/logical/array.js +2 -35
  22. package/src/builtins/logical/count.js +2 -20
  23. package/src/builtins/logical/counta.js +2 -20
  24. package/src/builtins/logical/countblank.js +2 -20
  25. package/src/builtins/logical/if.js +2 -20
  26. package/src/builtins/logical/or.js +2 -17
  27. package/src/builtins/math/abs.js +2 -20
  28. package/src/builtins/math/ceiling.js +2 -20
  29. package/src/builtins/math/cos.js +2 -20
  30. package/src/builtins/math/round.js +2 -23
  31. package/src/builtins/math/sin.js +2 -20
  32. package/src/builtins/registry.js +23 -40
  33. package/src/builtins/schema/datanames.js +9 -20
  34. package/src/builtins/schema/form.js +2 -20
  35. package/src/builtins/string/upper.js +2 -20
  36. package/src/engine/calculation-diagnostics.js +107 -0
  37. package/src/engine/calculation.js +65 -32
  38. package/src/engine/evaluator.js +56 -18
  39. package/src/engine/event-operation-scope.js +61 -0
  40. package/src/engine/event-source.js +164 -0
  41. package/src/engine/events.js +105 -19
  42. package/src/engine/form-engine.js +61 -16
  43. package/src/engine/warning-system.js +7 -5
  44. package/src/schema/field-specs.js +2 -2
  45. package/src/security/validation.js +10 -8
  46. package/src/utilities/calculation-editor.js +42 -6
  47. package/src/utilities/date-utils.js +72 -0
  48. package/src/builtins/docs/choice/choicelabel.mdx +0 -110
  49. package/src/builtins/docs/choice/choicelabels.mdx +0 -230
  50. package/src/builtins/docs/choice/choicevalue.mdx +0 -109
  51. package/src/builtins/docs/choice/choicevalues.mdx +0 -196
  52. package/src/builtins/docs/choice/hasother.mdx +0 -133
  53. package/src/builtins/docs/choice/other.mdx +0 -150
  54. package/src/builtins/docs/control/setresult.mdx +0 -203
  55. package/src/builtins/docs/event/field/setvalue.mdx +0 -239
  56. package/src/builtins/docs/index.mdx +0 -234
  57. package/src/builtins/docs/logical/and.mdx +0 -141
  58. package/src/builtins/docs/logical/if.mdx +0 -94
  59. package/src/builtins/docs/logical/or.mdx +0 -191
  60. package/src/builtins/docs/overview.mdx +0 -258
@@ -1,24 +1,9 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { AND_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin AND
5
- * @description Logical AND operation that returns true only if all arguments are truthy
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {...*} args - Any number of arguments to evaluate
7
7
  * @returns {boolean} True if all arguments are truthy, false otherwise
8
- * @example
9
- * // Check if user is adult and has premium account
10
- * AND(user.age >= 18, user.isPremium)
11
- * @example
12
- * // Multiple conditions
13
- * AND(name.length > 0, email.includes("@"), age >= 13)
14
8
  */
15
- export const AND_METADATA = defineBuiltinMetadata({
16
- name: 'AND',
17
- category: 'logical',
18
- signature: 'AND(...conditions)',
19
- description: 'Return true only when all arguments are truthy.',
20
- examples: ['AND($age >= 18, $country === "it")'],
21
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
22
- });
23
-
24
9
  export const AND = (...args) => args.every(Boolean);
@@ -1,44 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { ARRAY_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin ARRAY
5
- * @description Returns an array from its arguments. Can parse string representations of arrays (with single or double quotes) and comma-separated values.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {...*} args - Values to create an array from. Accepts multiple arguments or a single string to parse
7
7
  * @returns {Array} An array containing the arguments
8
- * @example
9
- * // Create array from multiple arguments
10
- * ARRAY(1, 2, 3) // returns [1, 2, 3]
11
- * @example
12
- * // Pass an existing array (no flattening)
13
- * ARRAY([1, 2, 3]) // returns [1, 2, 3]
14
- * @example
15
- * // Parse JSON array string (double quotes)
16
- * ARRAY("[1, 2, 3]") // returns [1, 2, 3]
17
- * @example
18
- * // Parse array string with single quotes
19
- * ARRAY("['a', 'b', 'c']") // returns ['a', 'b', 'c']
20
- * @example
21
- * // Parse simple comma-separated string (becomes array of strings)
22
- * ARRAY("one, two, three") // returns ["one", "two", "three"]
23
- * @example
24
- * // Nested arrays are preserved (no flattening)
25
- * ARRAY([1, [2, 3]]) // returns [1, [2, 3]]
26
- * @example
27
- * // Empty arguments
28
- * ARRAY() // returns []
29
- * @example
30
- * // For complex parsing, JSON.parse() can be used:
31
- * // EVAL('JSON.parse("[1,2,3]")')
32
8
  */
33
- export const ARRAY_METADATA = defineBuiltinMetadata({
34
- name: 'ARRAY',
35
- category: 'logical',
36
- signature: 'ARRAY(...values)',
37
- description: 'Build an array from individual arguments.',
38
- examples: ['ARRAY($city, $country)'],
39
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
40
- });
41
-
42
9
  export const ARRAY = (...args) => {
43
10
  // Handle empty arguments
44
11
  if (args.length === 0) {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { COUNT_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin COUNT
5
- * @description Returns a count of the number of numeric values in a dataset
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Array} values - An array of values to count
7
7
  * @returns {number} The count of numeric values in the array
8
- * @example
9
- * // Returns 5
10
- * COUNT([11, 22, 33, 44, 55])
11
- * @example
12
- * // Returns 0 (only counts numeric values)
13
- * COUNT(['a', 'b', 'c', 'd', 'e'])
14
- * @example
15
- * // Returns 3 (mixed array)
16
- * COUNT([1, 'a', 2, null, 3])
17
8
  */
18
- export const COUNT_METADATA = defineBuiltinMetadata({
19
- name: 'COUNT',
20
- category: 'logical',
21
- signature: 'COUNT(values)',
22
- description: 'Count numeric values.',
23
- examples: ['COUNT(ARRAY($score_1, $score_2, $score_3))'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const COUNT = (values) => {
28
10
  // Handle null/undefined input
29
11
  if (!Array.isArray(values)) {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { COUNTA_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin COUNTA
5
- * @description Returns a count of values in a dataset
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Array} values - An array of values to count
7
7
  * @returns {number} The total count of items in the array
8
- * @example
9
- * // Returns 5
10
- * COUNTA([11, 22, 33, 44, 55])
11
- * @example
12
- * // Returns 5 (counts all values regardless of type)
13
- * COUNTA(['a', 'b', 'c', 'd', 'e'])
14
- * @example
15
- * // Returns 4 (counts all items including null)
16
- * COUNTA([1, 'a', null, true])
17
8
  */
18
- export const COUNTA_METADATA = defineBuiltinMetadata({
19
- name: 'COUNTA',
20
- category: 'logical',
21
- signature: 'COUNTA(values)',
22
- description: 'Count non-empty values.',
23
- examples: ['COUNTA(ARRAY($first_name, $last_name, $email))'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const COUNTA = (values) => {
28
10
  // Handle null/undefined input
29
11
  if (!Array.isArray(values)) {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { COUNTBLANK_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin COUNTBLANK
5
- * @description Returns the number of blank values in a dataset
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Array} values - An array of items to check
7
7
  * @returns {number} The count of blank items in the array
8
- * @example
9
- * // Returns 3
10
- * COUNTBLANK([null, null, '', 1])
11
- * @example
12
- * // Returns 2
13
- * COUNTBLANK([undefined, '', 'a', 0])
14
- * @example
15
- * // Returns 0 (no blank values)
16
- * COUNTBLANK([1, 2, 'a', true])
17
8
  */
18
- export const COUNTBLANK_METADATA = defineBuiltinMetadata({
19
- name: 'COUNTBLANK',
20
- category: 'logical',
21
- signature: 'COUNTBLANK(values)',
22
- description: 'Count blank values.',
23
- examples: ['COUNTBLANK(ARRAY($first_name, $last_name, $email))'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const COUNTBLANK = (values) => {
28
10
  // Handle null/undefined input
29
11
  if (!Array.isArray(values)) {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { IF_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin IF
5
- * @description Conditional logic function that returns one of two values based on a condition
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {boolean} condition - The condition to evaluate
7
7
  * @param {*} trueValue - Value returned if condition is true
8
8
  * @param {*} falseValue - Value returned if condition is false
9
9
  * @returns {*} Either trueValue or falseValue
10
- * @example
11
- * // Returns "Yes" if age >= 18, otherwise "No"
12
- * IF(age >= 18, "Yes", "No")
13
- * @example
14
- * // Nested conditions for shipping cost
15
- * IF(country === "US", IF(state === "CA", 8.99, 5.99), 15.99)
16
10
  */
17
- export const IF_METADATA = defineBuiltinMetadata({
18
- name: 'IF',
19
- category: 'logical',
20
- signature: 'IF(condition, trueValue, falseValue)',
21
- description: 'Return one of two values based on a condition.',
22
- examples: [
23
- 'IF($age >= 18, "adult", "minor")',
24
- 'IF($country === "US", IF($state === "CA", 8.99, 5.99), 15.99)',
25
- ],
26
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
27
- });
28
-
29
11
  export const IF = (cond, a, b) => (cond ? a : b);
@@ -1,24 +1,9 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { OR_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin OR
5
- * @description Logical OR operation that returns true if at least one argument is truthy
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {...*} args - Any number of arguments to evaluate
7
7
  * @returns {boolean} True if at least one argument is truthy, false otherwise
8
- * @example
9
- * // Check if user has any premium feature
10
- * OR(user.isPremium, user.isVip, user.hasSubscription)
11
- * @example
12
- * // Validation - either email or phone is required
13
- * OR(email.length > 0, phone.length > 0)
14
8
  */
15
- export const OR_METADATA = defineBuiltinMetadata({
16
- name: 'OR',
17
- category: 'logical',
18
- signature: 'OR(...conditions)',
19
- description: 'Return true when at least one argument is truthy.',
20
- examples: ['OR($email, $phone)'],
21
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
22
- });
23
-
24
9
  export const OR = (...args) => args.some(Boolean);
@@ -1,27 +1,9 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { ABS_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin ABS
5
- * @description Returns the absolute value of a number
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {number} value - The number of which to return the absolute value
7
7
  * @returns {number} The absolute value of the input number
8
- * @example
9
- * // Returns 1
10
- * ABS(-1)
11
- * @example
12
- * // Returns 42
13
- * ABS(42)
14
- * @example
15
- * // Returns 3.14
16
- * ABS(-3.14)
17
8
  */
18
- export const ABS_METADATA = defineBuiltinMetadata({
19
- name: 'ABS',
20
- category: 'math',
21
- signature: 'ABS(value)',
22
- description: 'Return the absolute value of a number.',
23
- examples: ['ABS($variance)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const ABS = (value) => Math.abs(value);
@@ -1,30 +1,12 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { CEILING_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin CEILING
5
- * @description Rounds a value up to the nearest integer multiple of factor
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {number} value - The value to round up to the nearest integer multiple of factor
7
7
  * @param {number} [factor=1] - The number to whose multiples value will be rounded
8
8
  * @returns {number} The value rounded up to the nearest multiple of factor
9
- * @example
10
- * // Returns 139.9
11
- * CEILING(139.85, 0.1)
12
- * @example
13
- * // Returns 140
14
- * CEILING(139.001)
15
- * @example
16
- * // Returns 15
17
- * CEILING(12.3, 5)
18
9
  */
19
- export const CEILING_METADATA = defineBuiltinMetadata({
20
- name: 'CEILING',
21
- category: 'math',
22
- signature: 'CEILING(value, factor)',
23
- description: 'Round a number up to the nearest multiple.',
24
- examples: ['CEILING($amount, 5)'],
25
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
26
- });
27
-
28
10
  export const CEILING = (value, factor = 1) => {
29
11
  if (factor === 0) {
30
12
  throw new Error('CEILING factor cannot be zero');
@@ -1,27 +1,9 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { COS_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin COS
5
- * @description Returns the cosine of a value, in radians
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {number} value - The value for which to calculate the cosine
7
7
  * @returns {number} The cosine of the input value
8
- * @example
9
- * // Returns 0.15425144988758405
10
- * COS(30)
11
- * @example
12
- * // Returns 1
13
- * COS(0)
14
- * @example
15
- * // Returns -1
16
- * COS(Math.PI)
17
8
  */
18
- export const COS_METADATA = defineBuiltinMetadata({
19
- name: 'COS',
20
- category: 'math',
21
- signature: 'COS(value)',
22
- description: 'Return the cosine of a value in radians.',
23
- examples: ['COS($angle_radians)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const COS = (value) => Math.cos(value);
@@ -1,33 +1,12 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { ROUND_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin ROUND
5
- * @description Rounds a number to a specified number of decimal places according to standard rounding rules
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {number} value - The numeric value to be rounded
7
7
  * @param {number} places - The number of decimal places to round to
8
8
  * @returns {number} The value rounded to the specified number of decimal places
9
- * @example
10
- * // Returns 179.8
11
- * ROUND(179.848, 1)
12
- * @example
13
- * // Returns 900
14
- * ROUND(918.268, -2)
15
- * @example
16
- * // Returns 3
17
- * ROUND(3.14159, 0)
18
- * @example
19
- * // Returns 3.14
20
- * ROUND(3.14159, 2)
21
9
  */
22
- export const ROUND_METADATA = defineBuiltinMetadata({
23
- name: 'ROUND',
24
- category: 'math',
25
- signature: 'ROUND(value, places)',
26
- description: 'Round a number to a fixed number of decimal places.',
27
- examples: ['ROUND($total, 2)'],
28
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
29
- });
30
-
31
10
  export const ROUND = (value, places) => {
32
11
  if (typeof value !== 'number' || typeof places !== 'number') {
33
12
  throw new Error('ROUND requires two numeric arguments');
@@ -1,27 +1,9 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { SIN_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin SIN
5
- * @description Returns the sine of a value, in radians
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {number} value - The value for which to calculate the sine
7
7
  * @returns {number} The sine of the input value
8
- * @example
9
- * // Returns -0.9880316240928618
10
- * SIN(30)
11
- * @example
12
- * // Returns 0
13
- * SIN(0)
14
- * @example
15
- * // Returns 1
16
- * SIN(Math.PI / 2)
17
8
  */
18
- export const SIN_METADATA = defineBuiltinMetadata({
19
- name: 'SIN',
20
- category: 'math',
21
- signature: 'SIN(value)',
22
- description: 'Return the sine of a value in radians.',
23
- examples: ['SIN($angle_radians)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const SIN = (value) => Math.sin(value);
@@ -1,4 +1,12 @@
1
1
  import { cloneBuiltinMetadata, BUILTIN_CONTEXTS } from './builtin-metadata.js';
2
+ import { BUILTIN_DEFINITIONS } from './builtin-definitions.js';
3
+
4
+ export {
5
+ BUILTIN_DEFINITIONS,
6
+ CALCULATION_BUILTIN_DEFINITIONS,
7
+ EVENT_BUILTIN_DEFINITIONS,
8
+ BUILTIN_DEFINITION_BY_NAME,
9
+ } from './builtin-definitions.js';
2
10
 
3
11
  import { IF, IF_METADATA } from './logical/if.js';
4
12
  import { AND, AND_METADATA } from './logical/and.js';
@@ -10,6 +18,7 @@ import { ARRAY, ARRAY_METADATA } from './logical/array.js';
10
18
  import {
11
19
  SETRESULT,
12
20
  SETRESULT_METADATA,
21
+ __beginResultScope,
13
22
  __consumeResult,
14
23
  __resetResult,
15
24
  } from './control/setresult.js';
@@ -27,13 +36,14 @@ import { CEILING, CEILING_METADATA } from './math/ceiling.js';
27
36
  import { COS, COS_METADATA } from './math/cos.js';
28
37
  import { SIN, SIN_METADATA } from './math/sin.js';
29
38
  import { ROUND, ROUND_METADATA } from './math/round.js';
39
+ import { DATEADD, DATEADD_METADATA } from './date/dateadd.js';
40
+ import { DAYS, DAYS_METADATA } from './date/days.js';
30
41
  import { UPPER, UPPER_METADATA } from './string/upper.js';
31
42
 
32
43
  import { ALERT, ALERT_METADATA } from './event/ui/alert.js';
33
44
  import { SETVALUE, SETVALUE_METADATA } from './event/field/setvalue.js';
34
45
  import { ON, ON_METADATA } from './event/control/on.js';
35
46
  import { OFF, OFF_METADATA } from './event/control/off.js';
36
- import { __consumeEventOperations } from './event/event-operations-collector.js';
37
47
 
38
48
  export { IF, IF_METADATA } from './logical/if.js';
39
49
  export { AND, AND_METADATA } from './logical/and.js';
@@ -45,6 +55,7 @@ export { ARRAY, ARRAY_METADATA } from './logical/array.js';
45
55
  export {
46
56
  SETRESULT,
47
57
  SETRESULT_METADATA,
58
+ __beginResultScope,
48
59
  __consumeResult,
49
60
  __resetResult,
50
61
  } from './control/setresult.js';
@@ -67,15 +78,16 @@ export { CEILING, CEILING_METADATA } from './math/ceiling.js';
67
78
  export { COS, COS_METADATA } from './math/cos.js';
68
79
  export { SIN, SIN_METADATA } from './math/sin.js';
69
80
  export { ROUND, ROUND_METADATA } from './math/round.js';
81
+ export { DATEADD, DATEADD_METADATA } from './date/dateadd.js';
82
+ export { DAYS, DAYS_METADATA } from './date/days.js';
70
83
  export { UPPER, UPPER_METADATA } from './string/upper.js';
71
84
 
72
85
  export { ALERT, ALERT_METADATA } from './event/ui/alert.js';
73
86
  export { SETVALUE, SETVALUE_METADATA } from './event/field/setvalue.js';
74
87
  export { ON, ON_METADATA } from './event/control/on.js';
75
88
  export { OFF, OFF_METADATA } from './event/control/off.js';
76
- export { __consumeEventOperations } from './event/event-operations-collector.js';
77
89
 
78
- const COMMON_RUNTIME_ENTRIES = Object.freeze([
90
+ const RUNTIME_ENTRIES = Object.freeze([
79
91
  { implementation: IF, definition: IF_METADATA },
80
92
  { implementation: AND, definition: AND_METADATA },
81
93
  { implementation: OR, definition: OR_METADATA },
@@ -97,62 +109,33 @@ const COMMON_RUNTIME_ENTRIES = Object.freeze([
97
109
  { implementation: COS, definition: COS_METADATA },
98
110
  { implementation: SIN, definition: SIN_METADATA },
99
111
  { implementation: ROUND, definition: ROUND_METADATA },
112
+ { implementation: DATEADD, definition: DATEADD_METADATA },
113
+ { implementation: DAYS, definition: DAYS_METADATA },
100
114
  { implementation: UPPER, definition: UPPER_METADATA },
101
- ]);
102
-
103
- const CALCULATION_ONLY_ENTRIES = Object.freeze([
104
115
  { implementation: SETRESULT, definition: SETRESULT_METADATA },
105
- ]);
106
-
107
- const EVENT_ONLY_ENTRIES = Object.freeze([
108
116
  { implementation: ALERT, definition: ALERT_METADATA },
109
117
  { implementation: SETVALUE, definition: SETVALUE_METADATA },
110
118
  { implementation: ON, definition: ON_METADATA },
111
119
  { implementation: OFF, definition: OFF_METADATA },
112
120
  ]);
113
121
 
114
- function buildBuiltinObject(entries) {
122
+ function buildBuiltinObject(context) {
115
123
  return Object.freeze(
116
124
  Object.fromEntries(
117
- entries.map(({ implementation, definition }) => [definition.name, implementation])
125
+ RUNTIME_ENTRIES.filter(({ definition }) => definition.contexts.includes(context)).map(
126
+ ({ implementation, definition }) => [definition.name, implementation]
127
+ )
118
128
  )
119
129
  );
120
130
  }
121
131
 
122
- function filterDefinitionsByContext(definitions, context) {
123
- return Object.freeze(definitions.filter((definition) => definition.contexts.includes(context)));
124
- }
125
-
126
- export const calculationBuiltins = buildBuiltinObject([
127
- ...COMMON_RUNTIME_ENTRIES,
128
- ...CALCULATION_ONLY_ENTRIES,
129
- ]);
132
+ export const calculationBuiltins = buildBuiltinObject(BUILTIN_CONTEXTS.CALCULATION);
130
133
 
131
- export const eventBuiltins = buildBuiltinObject([...COMMON_RUNTIME_ENTRIES, ...EVENT_ONLY_ENTRIES]);
134
+ export const eventBuiltins = buildBuiltinObject(BUILTIN_CONTEXTS.EVENT);
132
135
 
133
136
  // Backward-compatible alias for calculation runtime helpers.
134
137
  export const builtins = calculationBuiltins;
135
138
 
136
- export const BUILTIN_DEFINITIONS = Object.freeze(
137
- [...COMMON_RUNTIME_ENTRIES, ...CALCULATION_ONLY_ENTRIES, ...EVENT_ONLY_ENTRIES].map(
138
- ({ definition }) => definition
139
- )
140
- );
141
-
142
- export const CALCULATION_BUILTIN_DEFINITIONS = filterDefinitionsByContext(
143
- BUILTIN_DEFINITIONS,
144
- BUILTIN_CONTEXTS.CALCULATION
145
- );
146
-
147
- export const EVENT_BUILTIN_DEFINITIONS = filterDefinitionsByContext(
148
- BUILTIN_DEFINITIONS,
149
- BUILTIN_CONTEXTS.EVENT
150
- );
151
-
152
- export const BUILTIN_DEFINITION_BY_NAME = new Map(
153
- BUILTIN_DEFINITIONS.map((definition) => [definition.name, definition])
154
- );
155
-
156
139
  export function getBuiltinDefinitions() {
157
140
  return BUILTIN_DEFINITIONS.map(cloneBuiltinMetadata);
158
141
  }
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { DATANAMES_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin DATANAMES
5
- * @description Returns the data names of form fields, optionally filtered by field type
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {string} type - Optional field type to filter by (e.g., 'TextField', 'RepeatableSection', etc.). Defaults to 'any' (all fields)
7
7
  * @returns {Array<string>} Array of field data names
8
- * @example
9
- * // Get all field data names
10
- * DATANAMES()
11
- * @example
12
- * // Get only RepeatableSection data names
13
- * DATANAMES('RepeatableSection')
14
- * @example
15
- * // Get only TextField data names
16
- * DATANAMES('TextField')
17
8
  */
18
- export const DATANAMES_METADATA = defineBuiltinMetadata({
19
- name: 'DATANAMES',
20
- category: 'schema',
21
- signature: "DATANAMES(type = 'any')",
22
- description: 'Return form field data names, optionally filtered by field type.',
23
- examples: ["DATANAMES('NumericField')"],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  // Global schema context for DATANAMES() - set during expression evaluation
28
10
  let _dataNamesSchema = null;
29
11
 
@@ -32,7 +14,14 @@ let _dataNamesSchema = null;
32
14
  * Called internally by the expression evaluator
33
15
  */
34
16
  export function __setDataNamesContext(schema) {
17
+ const previousSchema = _dataNamesSchema;
35
18
  _dataNamesSchema = schema;
19
+ let restored = false;
20
+ return () => {
21
+ if (restored) return;
22
+ restored = true;
23
+ _dataNamesSchema = previousSchema;
24
+ };
36
25
  }
37
26
 
38
27
  /**
@@ -1,28 +1,10 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { FORM_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin FORM
5
- * @description Access to the nested JSON form definition (future implementation)
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @returns {Object} The form schema object
7
- * @example
8
- * // Get form title
9
- * FORM().title
10
- * @example
11
- * // Access field definitions
12
- * FORM().elements[0].label
13
- * @example
14
- * // Check if form has RepeatableSections
15
- * FORM().elements.some(el => el.type === 'RepeatableSection')
16
7
  */
17
- export const FORM_METADATA = defineBuiltinMetadata({
18
- name: 'FORM',
19
- category: 'schema',
20
- signature: 'FORM()',
21
- description: 'Access the form definition. Reserved for a future implementation.',
22
- examples: ['FORM()'],
23
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
24
- });
25
-
26
8
  export function FORM() {
27
9
  // Placeholder for future implementation
28
10
  // Will provide access to nested JSON form definition
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { UPPER_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin UPPER
5
- * @description Returns the uppercase version of a string
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {string} value - The string to convert to uppercase
7
7
  * @returns {string} The uppercase version of the input string
8
- * @example
9
- * // Returns "HELLO WORLD"
10
- * UPPER("hello world")
11
- * @example
12
- * // Returns "FORM0"
13
- * UPPER("form0")
14
- * @example
15
- * // Returns "ABC123"
16
- * UPPER("abc123")
17
8
  */
18
- export const UPPER_METADATA = defineBuiltinMetadata({
19
- name: 'UPPER',
20
- category: 'string',
21
- signature: 'UPPER(value)',
22
- description: 'Convert a string to uppercase.',
23
- examples: ['UPPER($city_name)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const UPPER = (value) => {
28
10
  if (value == null) {
29
11
  return '';