form0-core 0.3.0 → 0.4.0

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 +63 -0
  2. package/package.json +5 -2
  3. package/src/builtins/builtin-definitions.js +320 -0
  4. package/src/builtins/choice/choicelabel.js +2 -17
  5. package/src/builtins/choice/choicelabels.js +2 -17
  6. package/src/builtins/choice/choicevalue.js +2 -20
  7. package/src/builtins/choice/choicevalues.js +2 -17
  8. package/src/builtins/choice/hasother.js +2 -20
  9. package/src/builtins/choice/other.js +2 -20
  10. package/src/builtins/control/eval.js +78 -31
  11. package/src/builtins/control/setresult.js +29 -17
  12. package/src/builtins/date/dateadd.js +24 -0
  13. package/src/builtins/date/days.js +22 -0
  14. package/src/builtins/event/control/off.js +3 -27
  15. package/src/builtins/event/control/on.js +3 -19
  16. package/src/builtins/event/event-operations-collector.js +33 -9
  17. package/src/builtins/event/field/setvalue.js +3 -32
  18. package/src/builtins/event/ui/alert.js +3 -11
  19. package/src/builtins/logical/and.js +2 -17
  20. package/src/builtins/logical/array.js +2 -35
  21. package/src/builtins/logical/count.js +2 -20
  22. package/src/builtins/logical/counta.js +2 -20
  23. package/src/builtins/logical/countblank.js +2 -20
  24. package/src/builtins/logical/if.js +2 -20
  25. package/src/builtins/logical/or.js +2 -17
  26. package/src/builtins/math/abs.js +2 -20
  27. package/src/builtins/math/ceiling.js +2 -20
  28. package/src/builtins/math/cos.js +2 -20
  29. package/src/builtins/math/round.js +2 -23
  30. package/src/builtins/math/sin.js +2 -20
  31. package/src/builtins/registry.js +23 -40
  32. package/src/builtins/schema/datanames.js +9 -20
  33. package/src/builtins/schema/form.js +2 -20
  34. package/src/builtins/string/upper.js +2 -20
  35. package/src/engine/calculation-diagnostics.js +107 -0
  36. package/src/engine/calculation.js +65 -32
  37. package/src/engine/conditions.js +69 -3
  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 +111 -23
  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 -255
@@ -1,40 +1,33 @@
1
1
  import { validateExpression } from '../../security/validation.js';
2
2
  import { SAFE_SECURITY_CONFIG } from '../../security/config.js';
3
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
3
+ export { EVAL_METADATA } from '../builtin-definitions.js';
4
4
 
5
5
  /**
6
6
  * @builtin EVAL
7
- * @description Evaluates a dynamic expression in a controlled, secure context
7
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
8
8
  * @param {string} expression - The dynamic expression to evaluate
9
9
  * @returns {*} The result of the evaluated expression
10
- * @example
11
- * // Dynamic field access
12
- * EVAL('$' + dynamicFieldName)
13
- * @example
14
- * // Dynamic builtin calls
15
- * EVAL('CHOICEVALUE($' + fieldVar + ')')
16
- * @example
17
- * // Computed field references
18
- * EVAL('$city' + '_suffix')
19
10
  */
20
- export const EVAL_METADATA = defineBuiltinMetadata({
21
- name: 'EVAL',
22
- category: 'control',
23
- signature: 'EVAL(expression)',
24
- description: 'Evaluate a dynamically built expression string in a restricted context.',
25
- examples: ['EVAL("$" + dynamicFieldName)'],
26
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
27
- });
28
-
29
11
  // Global context for EVAL() - set during expression evaluation
30
12
  let _evalContext = null;
13
+ let _evalReporting = null;
31
14
 
32
15
  /**
33
16
  * Set the context for EVAL() during expression evaluation
34
17
  * Called internally by the expression evaluator
35
18
  */
36
- export function __setEvalContext(context) {
19
+ export function __setEvalContext(context, reporting = null) {
20
+ const previousContext = _evalContext;
21
+ const previousReporting = _evalReporting;
37
22
  _evalContext = context;
23
+ _evalReporting = reporting;
24
+ let restored = false;
25
+ return () => {
26
+ if (restored) return;
27
+ restored = true;
28
+ _evalContext = previousContext;
29
+ _evalReporting = previousReporting;
30
+ };
38
31
  }
39
32
 
40
33
  /**
@@ -43,24 +36,54 @@ export function __setEvalContext(context) {
43
36
  */
44
37
  export function __clearEvalContext() {
45
38
  _evalContext = null;
39
+ _evalReporting = null;
40
+ }
41
+
42
+ function reportFailure(code, phase, message, consoleArgs, context = {}) {
43
+ _evalReporting?.onDiagnostic?.({
44
+ code,
45
+ phase,
46
+ message,
47
+ context: { source: 'EVAL', ...context },
48
+ });
49
+ if (!_evalReporting?.suppressConsole) console.warn(...consoleArgs);
50
+ }
51
+
52
+ function logDebug(...args) {
53
+ if (!_evalReporting?.suppressConsole) console.log(...args);
54
+ }
55
+
56
+ function referenceContext(reference) {
57
+ // Legacy EVAL also treats strings starting with '$' as reference lookups.
58
+ // Do not copy a whole expression into diagnostic metadata in that case.
59
+ return /^\$[a-zA-Z_][a-zA-Z0-9_]*$/.test(reference)
60
+ ? { referencedFieldName: reference.slice(1) }
61
+ : {};
46
62
  }
47
63
 
48
64
  export const EVAL = (expression) => {
49
65
  // Step 1: Basic validation
50
66
  if (typeof expression !== 'string') {
51
- console.warn('[form0] EVAL() requires a string expression');
67
+ reportFailure('eval_invalid_argument', 'validation', 'EVAL() requires a string expression', [
68
+ '[form0] EVAL() requires a string expression',
69
+ ]);
52
70
  return null;
53
71
  }
54
72
 
55
73
  if (!expression || expression.trim() === '') {
56
- console.warn('[form0] EVAL() requires a non-empty expression');
74
+ reportFailure('eval_invalid_argument', 'validation', 'EVAL() requires a non-empty expression', [
75
+ '[form0] EVAL() requires a non-empty expression',
76
+ ]);
57
77
  return null;
58
78
  }
59
79
 
60
80
  // Step 2: Security validation for EVAL() expressions
61
81
  const securityValidation = validateEvalExpression(expression);
62
82
  if (!securityValidation.valid) {
63
- console.warn('[form0] EVAL() security validation failed:', securityValidation.reason);
83
+ reportFailure('expression_validation_failed', 'validation', securityValidation.reason, [
84
+ '[form0] EVAL() security validation failed:',
85
+ securityValidation.reason,
86
+ ]);
64
87
  return null;
65
88
  }
66
89
 
@@ -147,12 +170,13 @@ function validateEvalExpression(expression) {
147
170
  * @returns {*} The evaluation result
148
171
  */
149
172
  function evaluateHybridExpression(expression, formContext) {
173
+ let phase = 'runtime';
150
174
  try {
151
175
  // Step 3a: Handle simple string literals and field references directly
152
176
  if (isSimpleStringLiteral(expression)) {
153
177
  // Simple string literal - return as is
154
178
  const result = expression;
155
- console.log('[form0] EVAL() simple string:', expression, '→', result);
179
+ logDebug('[form0] EVAL() simple string:', expression, '→', result);
156
180
  return result;
157
181
  }
158
182
 
@@ -160,10 +184,16 @@ function evaluateHybridExpression(expression, formContext) {
160
184
  // Field reference - resolve from context
161
185
  const fieldValue = formContext?.[expression];
162
186
  if (fieldValue !== undefined) {
163
- console.log('[form0] EVAL() resolved field reference:', expression, '→', fieldValue);
187
+ logDebug('[form0] EVAL() resolved field reference:', expression, '→', fieldValue);
164
188
  return fieldValue;
165
189
  } else {
166
- console.warn('[form0] EVAL() field reference not found:', expression);
190
+ reportFailure(
191
+ 'eval_reference_unavailable',
192
+ 'scope',
193
+ 'EVAL() field reference is unavailable.',
194
+ ['[form0] EVAL() field reference not found:', expression],
195
+ referenceContext(expression)
196
+ );
167
197
  return null;
168
198
  }
169
199
  }
@@ -183,7 +213,9 @@ function evaluateHybridExpression(expression, formContext) {
183
213
  const keys = Object.keys(basicContext);
184
214
  const values = Object.values(basicContext);
185
215
 
216
+ phase = 'syntax';
186
217
  const fn = new Function(...keys, `return (${expression});`);
218
+ phase = 'runtime';
187
219
  const result = fn(...values);
188
220
 
189
221
  // Step 3e: Check if result should be resolved as field reference
@@ -191,7 +223,7 @@ function evaluateHybridExpression(expression, formContext) {
191
223
  // This is a field reference - resolve it from context
192
224
  const fieldValue = formContext?.[result];
193
225
  if (fieldValue !== undefined) {
194
- console.log(
226
+ logDebug(
195
227
  '[form0] EVAL() resolved field reference:',
196
228
  expression,
197
229
  '→',
@@ -201,16 +233,31 @@ function evaluateHybridExpression(expression, formContext) {
201
233
  );
202
234
  return fieldValue;
203
235
  } else {
204
- console.warn('[form0] EVAL() field reference not found:', result);
236
+ reportFailure(
237
+ 'eval_reference_unavailable',
238
+ 'scope',
239
+ 'EVAL() field reference is unavailable.',
240
+ ['[form0] EVAL() field reference not found:', result],
241
+ referenceContext(result)
242
+ );
205
243
  return null;
206
244
  }
207
245
  }
208
246
 
209
247
  // Step 3f: Return string result for dataname references
210
- console.log('[form0] EVAL() built string:', expression, '→', result);
248
+ logDebug('[form0] EVAL() built string:', expression, '→', result);
211
249
  return result;
212
250
  } catch (error) {
213
- console.warn('[form0] EVAL() execution failed:', error.message);
251
+ reportFailure(
252
+ phase === 'syntax'
253
+ ? error instanceof SyntaxError
254
+ ? 'invalid_syntax'
255
+ : 'compilation_error'
256
+ : 'runtime_exception',
257
+ phase,
258
+ error instanceof Error && error.message ? error.message : 'Unknown EVAL() runtime error.',
259
+ ['[form0] EVAL() execution failed:', error.message]
260
+ );
214
261
  return null;
215
262
  }
216
263
  }
@@ -1,30 +1,16 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { SETRESULT_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  // Global state for result management
4
4
  let _resultSet = false;
5
5
  let _resultValue;
6
+ let _resultScopeDepth = 0;
6
7
 
7
8
  /**
8
9
  * @builtin SETRESULT
9
- * @description Sets a result value that can be consumed by the form engine
10
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
10
11
  * @param {*} value - The value to set as the result
11
12
  * @returns {*} The same value that was passed in
12
- * @example
13
- * // Set a calculation result
14
- * SETRESULT(price * quantity * (1 + taxRate))
15
- * @example
16
- * // Set a conditional result
17
- * SETRESULT(IF(isEligible, discount, 0))
18
13
  */
19
- export const SETRESULT_METADATA = defineBuiltinMetadata({
20
- name: 'SETRESULT',
21
- category: 'control',
22
- signature: 'SETRESULT(value)',
23
- description: 'Set the final return value for multiline calculations.',
24
- examples: ['SETRESULT($price * $quantity)'],
25
- contexts: [BUILTIN_CONTEXTS.CALCULATION],
26
- });
27
-
28
14
  export const SETRESULT = (value) => {
29
15
  _resultSet = true;
30
16
  _resultValue = value;
@@ -43,6 +29,32 @@ export function __consumeResult() {
43
29
  return { called, value };
44
30
  }
45
31
 
32
+ /**
33
+ * Start an isolated synchronous result scope and return its restoration function.
34
+ * Nested scopes restore the enclosing SETRESULT state; top-level scopes retain the
35
+ * legacy behavior of clearing stale state at both evaluation boundaries.
36
+ * @returns {() => void}
37
+ */
38
+ export function __beginResultScope() {
39
+ const previous = { called: _resultSet, value: _resultValue };
40
+ const restorePrevious = _resultScopeDepth > 0;
41
+ _resultScopeDepth += 1;
42
+ __resetResult();
43
+
44
+ let restored = false;
45
+ return () => {
46
+ if (restored) return;
47
+ restored = true;
48
+ _resultScopeDepth = Math.max(0, _resultScopeDepth - 1);
49
+ if (restorePrevious) {
50
+ _resultSet = previous.called;
51
+ _resultValue = previous.value;
52
+ } else {
53
+ __resetResult();
54
+ }
55
+ };
56
+ }
57
+
46
58
  /** Clear calculation result state without consuming it. */
47
59
  export function __resetResult() {
48
60
  _resultSet = false;
@@ -0,0 +1,24 @@
1
+ import { formatIsoDate, isBlankDateArgument, parseIsoDate } from '../../utilities/date-utils.js';
2
+
3
+ export { DATEADD_METADATA } from '../builtin-definitions.js';
4
+
5
+ /**
6
+ * @builtin DATEADD
7
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
8
+ * @param {string | null} date - A YYYY-MM-DD date
9
+ * @param {number | null} days - Whole number of days to add; negative values subtract
10
+ * @returns {string | null} The resulting YYYY-MM-DD date, or null when an argument is blank
11
+ */
12
+ export const DATEADD = (date, days) => {
13
+ if (isBlankDateArgument(date) || isBlankDateArgument(days)) return null;
14
+
15
+ const dayNumber = parseIsoDate(date);
16
+ if (dayNumber === null) {
17
+ throw new Error('DATEADD requires a date in YYYY-MM-DD format');
18
+ }
19
+ if (!Number.isInteger(days)) {
20
+ throw new Error('DATEADD requires a whole number of days');
21
+ }
22
+
23
+ return formatIsoDate(dayNumber + days);
24
+ };
@@ -0,0 +1,22 @@
1
+ import { isBlankDateArgument, parseIsoDate } from '../../utilities/date-utils.js';
2
+
3
+ export { DAYS_METADATA } from '../builtin-definitions.js';
4
+
5
+ /**
6
+ * @builtin DAYS
7
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
8
+ * @param {string | null} endDate - A YYYY-MM-DD date
9
+ * @param {string | null} startDate - A YYYY-MM-DD date
10
+ * @returns {number | null} Days from startDate to endDate, or null when an argument is blank
11
+ */
12
+ export const DAYS = (endDate, startDate) => {
13
+ if (isBlankDateArgument(endDate) || isBlankDateArgument(startDate)) return null;
14
+
15
+ const end = parseIsoDate(endDate);
16
+ const start = parseIsoDate(startDate);
17
+ if (end === null || start === null) {
18
+ throw new Error('DAYS requires dates in YYYY-MM-DD format');
19
+ }
20
+
21
+ return end - start;
22
+ };
@@ -1,9 +1,10 @@
1
1
  import { __collectEventOperation } from '../event-operations-collector.js';
2
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../../builtin-metadata.js';
2
+ export { OFF_METADATA } from '../../builtin-definitions.js';
3
3
  import { isValidEventType } from '../../../engine/event-registry.js';
4
4
 
5
5
  /**
6
- * OFF builtin for form events
6
+ * @builtin OFF
7
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
7
8
  * Removes event handlers within event context
8
9
  * Automatically collects operation for platform execution
9
10
  *
@@ -11,32 +12,7 @@ import { isValidEventType } from '../../../engine/event-registry.js';
11
12
  * @param {string|Function} [fieldKeyOrCallback] - Field key for field events, or callback for global events
12
13
  * @param {Function} [callback] - Callback function for field events (when fieldKeyOrCallback is a field key)
13
14
  * @returns {Object} Operation descriptor for platform execution (for backward compatibility)
14
- *
15
- * @example
16
- * // Remove specific global event handler
17
- * OFF('load-record', specificCallback);
18
- *
19
- * @example
20
- * // Remove all global event handlers
21
- * OFF('load-record');
22
- *
23
- * @example
24
- * // Remove specific field event handler
25
- * OFF('change', 'city', specificCallback);
26
- *
27
- * @example
28
- * // Remove all field event handlers
29
- * OFF('change', 'city');
30
15
  */
31
- export const OFF_METADATA = defineBuiltinMetadata({
32
- name: 'OFF',
33
- category: 'event',
34
- signature: 'OFF(eventType, fieldKeyOrCallback, callback)',
35
- description: 'Remove event handlers within form event code.',
36
- examples: ["OFF('change', 'city', specificCallback)"],
37
- contexts: [BUILTIN_CONTEXTS.EVENT],
38
- });
39
-
40
16
  export function OFF(eventType, fieldKeyOrCallback, callback) {
41
17
  if (typeof eventType !== 'string' || eventType.trim().length === 0) {
42
18
  console.warn('[form0] OFF() requires a non-empty event type string');
@@ -1,9 +1,10 @@
1
1
  import { __collectEventOperation } from '../event-operations-collector.js';
2
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../../builtin-metadata.js';
2
+ export { ON_METADATA } from '../../builtin-definitions.js';
3
3
  import { isValidEventType } from '../../../engine/event-registry.js';
4
4
 
5
5
  /**
6
- * ON builtin for form events
6
+ * @builtin ON
7
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
7
8
  * Registers an event handler within event context
8
9
  * Automatically collects operation for platform execution
9
10
  *
@@ -11,24 +12,7 @@ import { isValidEventType } from '../../../engine/event-registry.js';
11
12
  * @param {string|Function} fieldKeyOrCallback - Field key for field events, or callback for global events
12
13
  * @param {Function} [callback] - Callback function for field events
13
14
  * @returns {Object} Operation descriptor for platform execution (for backward compatibility)
14
- *
15
- * @example
16
- * // Register global event handler
17
- * ON('load-record', function() { ALERT('Record loaded!'); });
18
- *
19
- * @example
20
- * // Register field-specific event handler
21
- * ON('change', 'city', function(event) { ALERT('City changed!'); });
22
15
  */
23
- export const ON_METADATA = defineBuiltinMetadata({
24
- name: 'ON',
25
- category: 'event',
26
- signature: 'ON(eventType, fieldKeyOrCallback, callback)',
27
- description: 'Register an event handler within form event code.',
28
- examples: ["ON('change', 'city', function(event) { ALERT('City changed!'); })"],
29
- contexts: [BUILTIN_CONTEXTS.EVENT],
30
- });
31
-
32
16
  export function ON(eventType, fieldKeyOrCallback, callback) {
33
17
  if (typeof eventType !== 'string' || eventType.trim().length === 0) {
34
18
  console.warn('[form0] ON() requires a non-empty event type string');
@@ -1,20 +1,44 @@
1
- // Global state for event operations collection
2
- let _eventOperations = [];
1
+ let activeScope = null;
2
+ let boundScope = null;
3
3
 
4
4
  /**
5
5
  * Internal function to collect event operations
6
6
  * @param {Object} operation - The operation descriptor to collect
7
7
  */
8
8
  export function __collectEventOperation(operation) {
9
- _eventOperations.push(operation);
9
+ const scope = boundScope || activeScope;
10
+ scope?.collect(operation);
10
11
  }
11
12
 
12
13
  /**
13
- * Internal function to consume all collected event operations
14
- * @returns {Array} Array of collected operations
14
+ * Run synchronous event work with a dispatch-owned operation scope.
15
+ * @param {Object} scope - The scope receiving operations
16
+ * @param {Function} work - Synchronous work to execute
17
+ * @returns {*} The work result
15
18
  */
16
- export function __consumeEventOperations() {
17
- const operations = [..._eventOperations]; // Copy array
18
- _eventOperations = []; // Clear for next execution
19
- return operations;
19
+ export function __runWithEventOperationScope(scope, work) {
20
+ const enclosingScope = activeScope;
21
+ activeScope = scope;
22
+ try {
23
+ return work();
24
+ } finally {
25
+ activeScope = enclosingScope;
26
+ }
27
+ }
28
+
29
+ /**
30
+ * Invoke a canonical builtin with the scope it was bound to.
31
+ * @param {Object} scope - The builtin's originating scope
32
+ * @param {Function} builtin - Canonical event builtin
33
+ * @param {Array} args - Builtin arguments
34
+ * @returns {*} The builtin result
35
+ */
36
+ export function __invokeBoundEventBuiltin(scope, builtin, args) {
37
+ const enclosingScope = boundScope;
38
+ boundScope = scope;
39
+ try {
40
+ return builtin(...args);
41
+ } finally {
42
+ boundScope = enclosingScope;
43
+ }
20
44
  }
@@ -1,45 +1,16 @@
1
1
  import { __collectEventOperation } from '../event-operations-collector.js';
2
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../../builtin-metadata.js';
2
+ export { SETVALUE_METADATA } from '../../builtin-definitions.js';
3
3
 
4
4
  /**
5
- * SETVALUE builtin for form events
5
+ * @builtin SETVALUE
6
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
7
  * Sets a field value within event context
7
8
  * Automatically collects operation for platform execution
8
- * Supports multiple field types:
9
- * - TextField: string values
10
- * - NumericField: numeric values
11
- * - SingleChoiceField: string choice values
12
- * - MultiChoiceField: array of string choice values
13
9
  *
14
10
  * @param {string} fieldDataName - The data name of the field to set
15
11
  * @param {any} valueToSet - The value to set (string, number, array, etc.)
16
12
  * @returns {Object} Operation descriptor for platform execution (for backward compatibility)
17
- *
18
- * @example
19
- * // Set TextField value
20
- * SETVALUE('field_dataname', 'value_to_set')
21
- *
22
- * @example
23
- * // Set NumericField value
24
- * SETVALUE('field_dataname', 12)
25
- *
26
- * @example
27
- * // Set SingleChoiceField value
28
- * SETVALUE('field_dataname', 'choicefield_value_to_set')
29
- *
30
- * @example
31
- * // Set MultiChoiceField value
32
- * SETVALUE('field_dataname', ['value1', 'value2', 'value3'])
33
13
  */
34
- export const SETVALUE_METADATA = defineBuiltinMetadata({
35
- name: 'SETVALUE',
36
- category: 'event',
37
- signature: 'SETVALUE(fieldDataName, valueToSet)',
38
- description: 'Set a field value from a form event handler.',
39
- examples: ["SETVALUE('field_dataname', 'value_to_set')"],
40
- contexts: [BUILTIN_CONTEXTS.EVENT],
41
- });
42
-
43
14
  export function SETVALUE(fieldDataName, valueToSet) {
44
15
  // Create operation descriptor
45
16
  const operation = {
@@ -1,22 +1,14 @@
1
1
  import { __collectEventOperation } from '../event-operations-collector.js';
2
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../../builtin-metadata.js';
2
+ export { ALERT_METADATA } from '../../builtin-definitions.js';
3
3
 
4
4
  /**
5
- * ALERT builtin for form events
5
+ * @builtin ALERT
6
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
7
  * Automatically collects operation for platform execution
7
8
  * @param {string} title - The title to display in the alert
8
9
  * @param {string} message - The message to display in the alert (optional)
9
10
  * @returns {Object} Operation descriptor for platform execution (for backward compatibility)
10
11
  */
11
- export const ALERT_METADATA = defineBuiltinMetadata({
12
- name: 'ALERT',
13
- category: 'event',
14
- signature: "ALERT(title, message = '')",
15
- description: 'Display an alert from a form event handler.',
16
- examples: ["ALERT('Saved', 'The record was saved successfully.')"],
17
- contexts: [BUILTIN_CONTEXTS.EVENT],
18
- });
19
-
20
12
  export function ALERT(title, message = '') {
21
13
  // Create operation descriptor
22
14
  const operation = {
@@ -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)) {