form0-core 0.3.1 → 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 (59) 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/evaluator.js +56 -18
  38. package/src/engine/event-operation-scope.js +61 -0
  39. package/src/engine/event-source.js +164 -0
  40. package/src/engine/events.js +105 -19
  41. package/src/engine/form-engine.js +61 -16
  42. package/src/engine/warning-system.js +7 -5
  43. package/src/schema/field-specs.js +2 -2
  44. package/src/security/validation.js +10 -8
  45. package/src/utilities/calculation-editor.js +42 -6
  46. package/src/utilities/date-utils.js +72 -0
  47. package/src/builtins/docs/choice/choicelabel.mdx +0 -110
  48. package/src/builtins/docs/choice/choicelabels.mdx +0 -230
  49. package/src/builtins/docs/choice/choicevalue.mdx +0 -109
  50. package/src/builtins/docs/choice/choicevalues.mdx +0 -196
  51. package/src/builtins/docs/choice/hasother.mdx +0 -133
  52. package/src/builtins/docs/choice/other.mdx +0 -150
  53. package/src/builtins/docs/control/setresult.mdx +0 -203
  54. package/src/builtins/docs/event/field/setvalue.mdx +0 -239
  55. package/src/builtins/docs/index.mdx +0 -234
  56. package/src/builtins/docs/logical/and.mdx +0 -141
  57. package/src/builtins/docs/logical/if.mdx +0 -94
  58. package/src/builtins/docs/logical/or.mdx +0 -191
  59. package/src/builtins/docs/overview.mdx +0 -258
package/README.md CHANGED
@@ -81,6 +81,69 @@ console.log(engine.getState());
81
81
  The engine API exposes `eval()` for calculations, conditions, and validation; `trigger()` for form
82
82
  events; and `getState()` for current values and evaluated field state.
83
83
 
84
+ Schema event callbacks retain their authored source, so ordinary functions and arrows defined in
85
+ `form.events.code` also work on Hermes. Each dispatch uses current scoped field values; initialization
86
+ runs once. Local initialization variables are not captured. Callbacks supplied by host helpers still
87
+ require executable `toString()` output; unavailable source produces an event warning.
88
+
89
+ ## Calculation diagnostics
90
+
91
+ Diagnostics are collected automatically, including when console reporting is disabled:
92
+
93
+ ```js
94
+ const engine = createFormEngine({ schema });
95
+ console.log(engine.getDiagnostics()); // [] before the first evaluation
96
+ engine.eval();
97
+ console.log(engine.getDiagnostics()); // latest evaluation, returned as a defensive copy
98
+ ```
99
+
100
+ Configure reporting in application code:
101
+
102
+ ```js
103
+ const engine = createFormEngine({
104
+ schema,
105
+ diagnostics: { console: false },
106
+ onDiagnostics(snapshot) {
107
+ for (const diagnostic of snapshot) {
108
+ reportCalculationDiagnostic(diagnostic);
109
+ }
110
+ },
111
+ });
112
+
113
+ engine.eval();
114
+ // For a schema calculating quotient from divisor, correct the input and evaluate again:
115
+ engine.getState().values.divisor = 4;
116
+ engine.eval(); // replaces the snapshot; recovered failures disappear
117
+ ```
118
+
119
+ `onDiagnostics` runs once after every completed evaluation, including identical snapshots and
120
+ `[]`. Observer exceptions cannot interrupt evaluation and are reported according to the console
121
+ policy. Each diagnostic has `code`, `severity`, `message`, `fieldName`, `phase`, `suggestion`, and
122
+ `context`. Context identifies the schema parent path, related/referenced fields, and `expression`
123
+ versus `EVAL` origin. The engine adds no expression source, field values, or stack traces.
124
+
125
+ Identical diagnostics are deduplicated within an evaluation. Distinct failures are retained,
126
+ including failures observed in intermediate stabilization passes even if a later pass succeeds.
127
+ The snapshot records that evaluation; it is not a history or just the final unresolved errors.
128
+ Legitimate `null`, `undefined`, `NaN`, and `Infinity` results do not produce errors by themselves.
129
+ Diagnostics stay separate from `state.errors` and do not change submission validity.
130
+
131
+ Omit `diagnostics.console` to preserve existing defaults and supplied `WarningSystem` settings.
132
+ `false` silences calculation-owned reporting, including `EVAL()` warnings and debug logs; `true`
133
+ prints diagnostic reporting in development and production. Event reporting retains its existing
134
+ behavior. `WarningSystem` remains compatible.
135
+
136
+ The append-only `runtimeDiagnostics` option is deprecated but remains supported for compatibility.
137
+ For new integrations, omit that option and use `engine.getDiagnostics()` for the latest evaluation,
138
+ or `onDiagnostics(snapshot)` to receive every completed evaluation, including recovery (`[]`).
139
+ This is not a drop-in replacement for the legacy array: snapshots use the structured diagnostic
140
+ contract above and replace prior results rather than accumulating them. If you need a history,
141
+ store snapshots in application code. No removal version is scheduled.
142
+
143
+ See [calculation diagnostics](https://docs.form0.dev/core/engine/calculations-dependencies#seeing-errors-and-warnings)
144
+ for stable codes and the reporting contract. CLI and renderer diagnostics adoption is separate
145
+ from this core API.
146
+
84
147
  ## Schema and record ownership
85
148
 
86
149
  `form0-core` owns behavioral schema concerns such as fields, conditions, calculations, events, and
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "form0-core",
3
- "version": "0.3.1",
3
+ "version": "0.4.0",
4
4
  "publishConfig": {
5
5
  "registry": "https://registry.npmjs.org/"
6
6
  },
@@ -12,7 +12,7 @@
12
12
  "SECURITY.md"
13
13
  ],
14
14
  "scripts": {
15
- "test": "node tests/form0-core.test.js && node tests/conditions.test.js && node tests/numeric-field-schema.test.js && node tests/dataset-descriptors.test.js && node tests/structured-record.test.js && node tests/title-fields.test.js && node tests/builtin-metadata.test.js && node tests/calculation-expression-utils.test.js && node tests/calculation-editor.test.js && node tests/form-event-editor.test.js && node tests/form-authoring.test.js && node tests/security-test.js",
15
+ "test": "node tests/form0-core.test.js && node tests/conditions.test.js && node tests/numeric-field-schema.test.js && node tests/dataset-descriptors.test.js && node tests/structured-record.test.js && node tests/title-fields.test.js && node tests/builtin-metadata.test.js && node tests/builtin-import-isolation.test.js && node tests/builtin-catalog-examples.test.js && node tests/date-builtins.test.js && node tests/calculation-expression-utils.test.js && node tests/calculation-editor.test.js && node tests/form-event-editor.test.js && node tests/form-authoring.test.js && node tests/calculation-dependency-engine.test.js && node tests/calculation-diagnostics.characterization.test.js && node tests/calculation-diagnostics.test.js && node tests/calculation-missing-result.test.js && node tests/evaluator-reentry.test.js && node tests/event-compatibility.characterization.test.js && node tests/event-hermes.test.js && node tests/event-async-isolation.test.js && node tests/security-test.js",
16
16
  "format": "prettier --write \"src/**/*.{js,jsx}\" \"tests/**/*.{js,jsx}\" \"scripts/**/*.{js,mjs}\" package.json README.md SECURITY.md SUPPORT.md CONTRIBUTING.md eslint.config.js .github/workflows/ci.yml .github/workflows/publish.yml",
17
17
  "format:check": "prettier --check \"src/**/*.{js,jsx}\" \"tests/**/*.{js,jsx}\" \"scripts/**/*.{js,mjs}\" package.json README.md SECURITY.md SUPPORT.md CONTRIBUTING.md eslint.config.js .github/workflows/ci.yml .github/workflows/publish.yml",
18
18
  "lint:check": "eslint src tests",
@@ -63,5 +63,8 @@
63
63
  "globals": "^17.12.0",
64
64
  "ignore": "^7.0.5",
65
65
  "prettier": "^3.5.3"
66
+ },
67
+ "dependencies": {
68
+ "acorn": "8.18.0"
66
69
  }
67
70
  }
@@ -0,0 +1,320 @@
1
+ import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from './builtin-metadata.js';
2
+
3
+ // Authoritative builtin metadata. Keep this catalog independent of implementations
4
+ // so security validation can inspect names and contexts without loading EVAL().
5
+
6
+ export const IF_METADATA = defineBuiltinMetadata({
7
+ name: 'IF',
8
+ category: 'logical',
9
+ signature: 'IF(condition, trueValue, falseValue)',
10
+ description: 'Return one of two values based on a condition.',
11
+ examples: [
12
+ 'IF($age >= 18, "adult", "minor")',
13
+ 'IF($country === "US", IF($state === "CA", 8.99, 5.99), 15.99)',
14
+ ],
15
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
16
+ });
17
+
18
+ export const AND_METADATA = defineBuiltinMetadata({
19
+ name: 'AND',
20
+ category: 'logical',
21
+ signature: 'AND(...conditions)',
22
+ description: 'Return true only when all arguments are truthy.',
23
+ examples: ['AND($age >= 18, $country === "it")'],
24
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
+ });
26
+
27
+ export const OR_METADATA = defineBuiltinMetadata({
28
+ name: 'OR',
29
+ category: 'logical',
30
+ signature: 'OR(...conditions)',
31
+ description: 'Return true when at least one argument is truthy.',
32
+ examples: ['OR($email, $phone)'],
33
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
34
+ });
35
+
36
+ export const COUNT_METADATA = defineBuiltinMetadata({
37
+ name: 'COUNT',
38
+ category: 'logical',
39
+ signature: 'COUNT(values)',
40
+ description: 'Count numeric values.',
41
+ examples: ['COUNT(ARRAY($score_1, $score_2, $score_3))'],
42
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
43
+ });
44
+
45
+ export const COUNTA_METADATA = defineBuiltinMetadata({
46
+ name: 'COUNTA',
47
+ category: 'logical',
48
+ signature: 'COUNTA(values)',
49
+ description: 'Count non-empty values.',
50
+ examples: ['COUNTA(ARRAY($first_name, $last_name, $email))'],
51
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
52
+ });
53
+
54
+ export const COUNTBLANK_METADATA = defineBuiltinMetadata({
55
+ name: 'COUNTBLANK',
56
+ category: 'logical',
57
+ signature: 'COUNTBLANK(values)',
58
+ description: 'Count blank values.',
59
+ examples: ['COUNTBLANK(ARRAY($first_name, $last_name, $email))'],
60
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
61
+ });
62
+
63
+ export const ARRAY_METADATA = defineBuiltinMetadata({
64
+ name: 'ARRAY',
65
+ category: 'logical',
66
+ signature: 'ARRAY(...values)',
67
+ description: 'Build an array from individual arguments.',
68
+ examples: ['ARRAY($city, $country)'],
69
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
70
+ });
71
+
72
+ export const EVAL_METADATA = defineBuiltinMetadata({
73
+ name: 'EVAL',
74
+ category: 'control',
75
+ signature: 'EVAL(expression)',
76
+ description: 'Evaluate a dynamically built expression string in a restricted context.',
77
+ examples: ['EVAL("$" + dynamicFieldName)'],
78
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
79
+ });
80
+
81
+ export const CHOICEVALUE_METADATA = defineBuiltinMetadata({
82
+ name: 'CHOICEVALUE',
83
+ category: 'choice',
84
+ signature: 'CHOICEVALUE(fieldValue)',
85
+ description: 'Return the selected choice value from a choice field.',
86
+ examples: [
87
+ 'CHOICEVALUE($city)',
88
+ 'IF(CHOICEVALUE($city) === "bogota", "Welcome to Bogota!", "Welcome!")',
89
+ ],
90
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
91
+ });
92
+
93
+ export const CHOICELABEL_METADATA = defineBuiltinMetadata({
94
+ name: 'CHOICELABEL',
95
+ category: 'choice',
96
+ signature: 'CHOICELABEL(fieldValue)',
97
+ description: 'Return the selected choice label from a choice field.',
98
+ examples: ['CHOICELABEL($city)'],
99
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
100
+ });
101
+
102
+ export const HASOTHER_METADATA = defineBuiltinMetadata({
103
+ name: 'HASOTHER',
104
+ category: 'choice',
105
+ signature: 'HASOTHER(fieldValue)',
106
+ description: 'Return true when the field has an "other" value.',
107
+ examples: ['HASOTHER($city)'],
108
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
109
+ });
110
+
111
+ export const OTHER_METADATA = defineBuiltinMetadata({
112
+ name: 'OTHER',
113
+ category: 'choice',
114
+ signature: 'OTHER(fieldValue)',
115
+ description: 'Return the "other" label from a choice field.',
116
+ examples: ['OTHER($city)'],
117
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
118
+ });
119
+
120
+ export const CHOICEVALUES_METADATA = defineBuiltinMetadata({
121
+ name: 'CHOICEVALUES',
122
+ category: 'choice',
123
+ signature: 'CHOICEVALUES(fieldValue)',
124
+ description: 'Return all selected values from a MultiChoiceField.',
125
+ examples: ['CHOICEVALUES($colors)', 'CHOICEVALUES($colors).includes("red")'],
126
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
127
+ });
128
+
129
+ export const CHOICELABELS_METADATA = defineBuiltinMetadata({
130
+ name: 'CHOICELABELS',
131
+ category: 'choice',
132
+ signature: 'CHOICELABELS(fieldValue)',
133
+ description: 'Return all selected labels from a MultiChoiceField.',
134
+ examples: ['CHOICELABELS($colors)'],
135
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
136
+ });
137
+
138
+ export const FORM_METADATA = defineBuiltinMetadata({
139
+ name: 'FORM',
140
+ category: 'schema',
141
+ signature: 'FORM()',
142
+ description: 'Access the form definition. Reserved for a future implementation.',
143
+ examples: ['FORM()'],
144
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
145
+ });
146
+
147
+ export const DATANAMES_METADATA = defineBuiltinMetadata({
148
+ name: 'DATANAMES',
149
+ category: 'schema',
150
+ signature: "DATANAMES(type = 'any')",
151
+ description: 'Return form field data names, optionally filtered by field type.',
152
+ examples: ["DATANAMES('NumericField')"],
153
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
154
+ });
155
+
156
+ export const ABS_METADATA = defineBuiltinMetadata({
157
+ name: 'ABS',
158
+ category: 'math',
159
+ signature: 'ABS(value)',
160
+ description: 'Return the absolute value of a number.',
161
+ examples: ['ABS($variance)'],
162
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
163
+ });
164
+
165
+ export const CEILING_METADATA = defineBuiltinMetadata({
166
+ name: 'CEILING',
167
+ category: 'math',
168
+ signature: 'CEILING(value, factor)',
169
+ description: 'Round a number up to the nearest multiple.',
170
+ examples: ['CEILING($amount, 5)'],
171
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
172
+ });
173
+
174
+ export const COS_METADATA = defineBuiltinMetadata({
175
+ name: 'COS',
176
+ category: 'math',
177
+ signature: 'COS(value)',
178
+ description: 'Return the cosine of a value in radians.',
179
+ examples: ['COS($angle_radians)'],
180
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
181
+ });
182
+
183
+ export const SIN_METADATA = defineBuiltinMetadata({
184
+ name: 'SIN',
185
+ category: 'math',
186
+ signature: 'SIN(value)',
187
+ description: 'Return the sine of a value in radians.',
188
+ examples: ['SIN($angle_radians)'],
189
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
190
+ });
191
+
192
+ export const ROUND_METADATA = defineBuiltinMetadata({
193
+ name: 'ROUND',
194
+ category: 'math',
195
+ signature: 'ROUND(value, places)',
196
+ description: 'Round a number to a fixed number of decimal places.',
197
+ examples: ['ROUND($total, 2)'],
198
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
199
+ });
200
+
201
+ export const DATEADD_METADATA = defineBuiltinMetadata({
202
+ name: 'DATEADD',
203
+ category: 'date',
204
+ signature: 'DATEADD(date, days)',
205
+ description:
206
+ 'Add whole days to a YYYY-MM-DD date from 0001-01-01 through 9999-12-31. Returns null when an argument is blank.',
207
+ examples: ['DATEADD($start_date, 30)', 'DATEADD($due_date, -7)'],
208
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
209
+ });
210
+
211
+ export const DAYS_METADATA = defineBuiltinMetadata({
212
+ name: 'DAYS',
213
+ category: 'date',
214
+ signature: 'DAYS(endDate, startDate)',
215
+ description:
216
+ 'Return the days between YYYY-MM-DD dates from 0001-01-01 through 9999-12-31. Returns null when an argument is blank.',
217
+ examples: ['DAYS($end_date, $start_date)'],
218
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
219
+ });
220
+
221
+ export const UPPER_METADATA = defineBuiltinMetadata({
222
+ name: 'UPPER',
223
+ category: 'string',
224
+ signature: 'UPPER(value)',
225
+ description: 'Convert a string to uppercase.',
226
+ examples: ['UPPER($city_name)'],
227
+ contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
228
+ });
229
+
230
+ export const SETRESULT_METADATA = defineBuiltinMetadata({
231
+ name: 'SETRESULT',
232
+ category: 'control',
233
+ signature: 'SETRESULT(value)',
234
+ description: 'Set the final return value for multiline calculations.',
235
+ examples: ['SETRESULT($price * $quantity)'],
236
+ contexts: [BUILTIN_CONTEXTS.CALCULATION],
237
+ });
238
+
239
+ export const ALERT_METADATA = defineBuiltinMetadata({
240
+ name: 'ALERT',
241
+ category: 'event',
242
+ signature: "ALERT(title, message = '')",
243
+ description: 'Display an alert from a form event handler.',
244
+ examples: ["ALERT('Saved', 'The record was saved successfully.')"],
245
+ contexts: [BUILTIN_CONTEXTS.EVENT],
246
+ });
247
+
248
+ export const SETVALUE_METADATA = defineBuiltinMetadata({
249
+ name: 'SETVALUE',
250
+ category: 'event',
251
+ signature: 'SETVALUE(fieldDataName, valueToSet)',
252
+ description: 'Set a field value from a form event handler.',
253
+ examples: ["SETVALUE('field_dataname', 'value_to_set')"],
254
+ contexts: [BUILTIN_CONTEXTS.EVENT],
255
+ });
256
+
257
+ export const ON_METADATA = defineBuiltinMetadata({
258
+ name: 'ON',
259
+ category: 'event',
260
+ signature: 'ON(eventType, fieldKeyOrCallback, callback)',
261
+ description: 'Register an event handler within form event code.',
262
+ examples: ["ON('change', 'city', function(event) { ALERT('City changed!'); })"],
263
+ contexts: [BUILTIN_CONTEXTS.EVENT],
264
+ });
265
+
266
+ export const OFF_METADATA = defineBuiltinMetadata({
267
+ name: 'OFF',
268
+ category: 'event',
269
+ signature: 'OFF(eventType, fieldKeyOrCallback, callback)',
270
+ description: 'Remove event handlers within form event code.',
271
+ examples: ["OFF('change', 'city', specificCallback)"],
272
+ contexts: [BUILTIN_CONTEXTS.EVENT],
273
+ });
274
+
275
+ export const BUILTIN_DEFINITIONS = Object.freeze([
276
+ IF_METADATA,
277
+ AND_METADATA,
278
+ OR_METADATA,
279
+ COUNT_METADATA,
280
+ COUNTA_METADATA,
281
+ COUNTBLANK_METADATA,
282
+ ARRAY_METADATA,
283
+ EVAL_METADATA,
284
+ CHOICEVALUE_METADATA,
285
+ CHOICELABEL_METADATA,
286
+ HASOTHER_METADATA,
287
+ OTHER_METADATA,
288
+ CHOICEVALUES_METADATA,
289
+ CHOICELABELS_METADATA,
290
+ FORM_METADATA,
291
+ DATANAMES_METADATA,
292
+ ABS_METADATA,
293
+ CEILING_METADATA,
294
+ COS_METADATA,
295
+ SIN_METADATA,
296
+ ROUND_METADATA,
297
+ DATEADD_METADATA,
298
+ DAYS_METADATA,
299
+ UPPER_METADATA,
300
+ SETRESULT_METADATA,
301
+ ALERT_METADATA,
302
+ SETVALUE_METADATA,
303
+ ON_METADATA,
304
+ OFF_METADATA,
305
+ ]);
306
+
307
+ function filterDefinitionsByContext(context) {
308
+ return Object.freeze(
309
+ BUILTIN_DEFINITIONS.filter((definition) => definition.contexts.includes(context))
310
+ );
311
+ }
312
+
313
+ export const CALCULATION_BUILTIN_DEFINITIONS = filterDefinitionsByContext(
314
+ BUILTIN_CONTEXTS.CALCULATION
315
+ );
316
+ export const EVENT_BUILTIN_DEFINITIONS = filterDefinitionsByContext(BUILTIN_CONTEXTS.EVENT);
317
+
318
+ export const BUILTIN_DEFINITION_BY_NAME = new Map(
319
+ BUILTIN_DEFINITIONS.map((definition) => [definition.name, definition])
320
+ );
@@ -1,26 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { CHOICELABEL_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin CHOICELABEL
5
- * @description Retrieves the currently selected choice field label, preserving the type (if the label is a number preserves the number type, otherwise string). If no selection it returns null.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} choiceField - The choice field object with choice and other arrays
7
7
  * @returns {*} The selected choice label with preserved type, or null if no selection
8
- * @example
9
- * // Get the selected city label
10
- * CHOICELABEL($city)
11
- * @example
12
- * // Use in display logic
13
- * "You selected: " + CHOICELABEL($city)
14
8
  */
15
- export const CHOICELABEL_METADATA = defineBuiltinMetadata({
16
- name: 'CHOICELABEL',
17
- category: 'choice',
18
- signature: 'CHOICELABEL(fieldValue)',
19
- description: 'Return the selected choice label from a choice field.',
20
- examples: ['CHOICELABEL($city)'],
21
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
22
- });
23
-
24
9
  export const CHOICELABEL = (choiceField) => {
25
10
  // Handle null/undefined input
26
11
  if (!choiceField || typeof choiceField !== 'object') {
@@ -1,26 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { CHOICELABELS_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin CHOICELABELS
5
- * @description Retrieves an array of all selected choice field labels from a MultiChoiceField, preserving the type of each label. Returns an empty array if no selections.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} multiChoiceField - The multi choice field object with choices and other arrays
7
7
  * @returns {Array} Array of selected choice labels with preserved types
8
- * @example
9
- * // Get all selected color labels
10
- * CHOICELABELS($colors)
11
- * @example
12
- * // Display selected colors
13
- * "Selected colors: " + CHOICELABELS($colors).join(", ")
14
8
  */
15
- export const CHOICELABELS_METADATA = defineBuiltinMetadata({
16
- name: 'CHOICELABELS',
17
- category: 'choice',
18
- signature: 'CHOICELABELS(fieldValue)',
19
- description: 'Return all selected labels from a MultiChoiceField.',
20
- examples: ['CHOICELABELS($colors)'],
21
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
22
- });
23
-
24
9
  export const CHOICELABELS = (multiChoiceField) => {
25
10
  // Handle null/undefined input
26
11
  if (!multiChoiceField || typeof multiChoiceField !== 'object') {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { CHOICEVALUE_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin CHOICEVALUE
5
- * @description Retrieves the currently selected choice field value, preserving the type (if the value is a number preserves the number type, otherwise string). If no selection it returns null.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} choiceField - The choice field object with choice and other arrays
7
7
  * @returns {*} The selected choice value with preserved type, or null if no selection
8
- * @example
9
- * // Get the selected city value
10
- * CHOICEVALUE($city)
11
- * @example
12
- * // Use in conditional logic
13
- * IF(CHOICEVALUE($city) === "bogota", "Welcome to Bogotá!", "Welcome!")
14
8
  */
15
- export const CHOICEVALUE_METADATA = defineBuiltinMetadata({
16
- name: 'CHOICEVALUE',
17
- category: 'choice',
18
- signature: 'CHOICEVALUE(fieldValue)',
19
- description: 'Return the selected choice value from a choice field.',
20
- examples: [
21
- 'CHOICEVALUE($city)',
22
- 'IF(CHOICEVALUE($city) === "bogota", "Welcome to Bogota!", "Welcome!")',
23
- ],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const CHOICEVALUE = (choiceField) => {
28
10
  // Handle null/undefined input
29
11
  if (!choiceField || typeof choiceField !== 'object') {
@@ -1,26 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { CHOICEVALUES_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin CHOICEVALUES
5
- * @description Retrieves an array of all selected choice field values from a MultiChoiceField, preserving the type of each value. Returns an empty array if no selections.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} multiChoiceField - The multi choice field object with choices and other arrays
7
7
  * @returns {Array} Array of selected choice values with preserved types
8
- * @example
9
- * // Get all selected color values
10
- * CHOICEVALUES($colors)
11
- * @example
12
- * // Check if "red" is selected
13
- * CHOICEVALUES($colors).includes("red")
14
8
  */
15
- export const CHOICEVALUES_METADATA = defineBuiltinMetadata({
16
- name: 'CHOICEVALUES',
17
- category: 'choice',
18
- signature: 'CHOICEVALUES(fieldValue)',
19
- description: 'Return all selected values from a MultiChoiceField.',
20
- examples: ['CHOICEVALUES($colors)', 'CHOICEVALUES($colors).includes("red")'],
21
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
22
- });
23
-
24
9
  export const CHOICEVALUES = (multiChoiceField) => {
25
10
  // Handle null/undefined input
26
11
  if (!multiChoiceField || typeof multiChoiceField !== 'object') {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { HASOTHER_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin HASOTHER
5
- * @description Returns true if user entered an other option, false otherwise. Works with both SingleChoiceField and MultiChoiceField.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} choiceField - The choice field object (SingleChoiceField with choice array or MultiChoiceField with choices array) and other array
7
7
  * @returns {boolean} True if user entered an other option, false otherwise
8
- * @example
9
- * // Check if user entered other option in single choice field
10
- * HASOTHER($city)
11
- * @example
12
- * // Check if user entered other option in multi choice field
13
- * HASOTHER($colors)
14
- * @example
15
- * // Use in conditional logic
16
- * IF(HASOTHER($city), "Custom city: " + OTHER($city), "Selected city: " + CHOICELABEL($city))
17
8
  */
18
- export const HASOTHER_METADATA = defineBuiltinMetadata({
19
- name: 'HASOTHER',
20
- category: 'choice',
21
- signature: 'HASOTHER(fieldValue)',
22
- description: 'Return true when the field has an "other" value.',
23
- examples: ['HASOTHER($city)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const HASOTHER = (choiceField) => {
28
10
  // Handle null/undefined input
29
11
  if (!choiceField || typeof choiceField !== 'object') {
@@ -1,29 +1,11 @@
1
- import { BUILTIN_CONTEXTS, defineBuiltinMetadata } from '../builtin-metadata.js';
1
+ export { OTHER_METADATA } from '../builtin-definitions.js';
2
2
 
3
3
  /**
4
4
  * @builtin OTHER
5
- * @description Retrieves the other label if user entered the other option, otherwise null. Works with both SingleChoiceField and MultiChoiceField.
5
+ * Name, signature, description, examples, and contexts: see builtin-definitions.js.
6
6
  * @param {Object} choiceField - The choice field object (SingleChoiceField with choice array or MultiChoiceField with choices array) and other array
7
7
  * @returns {string|null} The other label if user entered an other option, null otherwise
8
- * @example
9
- * // Get the other value from single choice field
10
- * OTHER($city)
11
- * @example
12
- * // Get the other value from multi choice field
13
- * OTHER($colors)
14
- * @example
15
- * // Use in conditional logic
16
- * IF(HASOTHER($city), "Custom city: " + OTHER($city), "No custom city entered")
17
8
  */
18
- export const OTHER_METADATA = defineBuiltinMetadata({
19
- name: 'OTHER',
20
- category: 'choice',
21
- signature: 'OTHER(fieldValue)',
22
- description: 'Return the "other" label from a choice field.',
23
- examples: ['OTHER($city)'],
24
- contexts: [BUILTIN_CONTEXTS.CALCULATION, BUILTIN_CONTEXTS.EVENT],
25
- });
26
-
27
9
  export const OTHER = (choiceField) => {
28
10
  // Handle null/undefined input
29
11
  if (!choiceField || typeof choiceField !== 'object') {