@case-framework/survey-assistant 0.8.0 → 0.9.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.
- package/dist/{authoring-references-DbuOKerg.mjs → authoring-references-CmwLc_C8.mjs} +40 -32
- package/dist/authoring-references-CmwLc_C8.mjs.map +1 -0
- package/dist/capabilities-D55dq-fO.mjs +582 -0
- package/dist/capabilities-D55dq-fO.mjs.map +1 -0
- package/dist/capabilities-default.d.mts +4 -12
- package/dist/capabilities-default.d.mts.map +1 -1
- package/dist/capabilities-default.mjs +2 -2
- package/dist/capabilities-z95e1mti.d.mts +117 -0
- package/dist/capabilities-z95e1mti.d.mts.map +1 -0
- package/dist/{constants-B6HzpEsx.d.mts → constants-HL_klgJl.d.mts} +4 -4
- package/dist/{constants-B6HzpEsx.d.mts.map → constants-HL_klgJl.d.mts.map} +1 -1
- package/dist/{controller-proxy-DEeFl9IA.mjs → controller-proxy-BQ1YsVxJ.mjs} +4 -3
- package/dist/controller-proxy-BQ1YsVxJ.mjs.map +1 -0
- package/dist/{controller-proxy-D7uQfm5f.d.mts → controller-proxy-Cmzdr9tV.d.mts} +4 -4
- package/dist/{controller-proxy-D7uQfm5f.d.mts.map → controller-proxy-Cmzdr9tV.d.mts.map} +1 -1
- package/dist/default-D22AKTqE.mjs +233 -0
- package/dist/default-D22AKTqE.mjs.map +1 -0
- package/dist/{digest-C39WyAWG.d.mts → digest-FnTTDBq2.d.mts} +2 -2
- package/dist/digest-FnTTDBq2.d.mts.map +1 -0
- package/dist/digest.d.mts +1 -1
- package/dist/engine-D950TfvC.mjs +3098 -0
- package/dist/engine-D950TfvC.mjs.map +1 -0
- package/dist/engine.d.mts +4 -3
- package/dist/engine.mjs +3 -3
- package/dist/{index-WB5kfnz0.d.mts → index-B8TLBd1G.d.mts} +8 -6
- package/dist/index-B8TLBd1G.d.mts.map +1 -0
- package/dist/index-CaX3hZmr.d.mts +23813 -0
- package/dist/index-CaX3hZmr.d.mts.map +1 -0
- package/dist/{index-r5riv4md.d.mts → index-CeUlGkoU.d.mts} +27 -6
- package/dist/index-CeUlGkoU.d.mts.map +1 -0
- package/dist/{index-D7wT6P3t.d.mts → index-DYHdvSE8.d.mts} +83 -41
- package/dist/index-DYHdvSE8.d.mts.map +1 -0
- package/dist/lifecycle-DFzxVxpq.d.mts +54346 -0
- package/dist/lifecycle-DFzxVxpq.d.mts.map +1 -0
- package/dist/{memory-thread-repository-DAnOGIB3.mjs → memory-thread-repository-DmLadygY.mjs} +15 -9
- package/dist/{memory-thread-repository-DAnOGIB3.mjs.map → memory-thread-repository-DmLadygY.mjs.map} +1 -1
- package/dist/protocol-BQ7uIDYT.mjs +569 -0
- package/dist/protocol-BQ7uIDYT.mjs.map +1 -0
- package/dist/protocol.d.mts +4 -4
- package/dist/protocol.mjs +3 -2
- package/dist/{react-C_GY-Fsc.mjs → react-DybJ5pWw.mjs} +17 -11
- package/dist/react-DybJ5pWw.mjs.map +1 -0
- package/dist/react-integration.d.mts +1 -1
- package/dist/react-integration.mjs +1 -1
- package/dist/react.d.mts +2 -2
- package/dist/react.mjs +2 -2
- package/dist/references/assistant-operations.md +190 -215
- package/dist/references/core-rules.md +2 -2
- package/dist/references/element-types.md +189 -0
- package/dist/references/expressions.md +215 -238
- package/dist/references/follow-ups.md +151 -0
- package/dist/references/localization.md +26 -12
- package/dist/references/response-variables.md +3 -3
- package/dist/references/rich-text-content.md +22 -43
- package/dist/references/source-material-surveys.md +20 -25
- package/dist/references/survey-data-model.md +36 -117
- package/dist/{request-context-Dg4jSwN1.mjs → request-context-KVh8VjgH.mjs} +4 -4
- package/dist/request-context-KVh8VjgH.mjs.map +1 -0
- package/dist/server-agent.d.mts +28 -7
- package/dist/server-agent.d.mts.map +1 -1
- package/dist/server-agent.mjs +33 -25
- package/dist/server-agent.mjs.map +1 -1
- package/dist/server-runtime.d.mts +6 -5
- package/dist/server-runtime.d.mts.map +1 -1
- package/dist/server-runtime.mjs +3 -3
- package/dist/server-tasks.d.mts +1 -1
- package/dist/server-tasks.mjs +1 -1
- package/dist/server-tools.d.mts +1 -1
- package/dist/server-tools.mjs +1 -1
- package/dist/server.d.mts +7 -6
- package/dist/server.d.mts.map +1 -1
- package/dist/server.mjs +3 -3
- package/dist/{tasks-BZEiwgxA.mjs → tasks-Coh5N027.mjs} +16 -15
- package/dist/tasks-Coh5N027.mjs.map +1 -0
- package/dist/{tasks-B9h3LPam.d.mts → tasks-wb9M-bak.d.mts} +11 -11
- package/dist/{tasks-B9h3LPam.d.mts.map → tasks-wb9M-bak.d.mts.map} +1 -1
- package/dist/{thread-handlers-Bef0td9N.d.mts → thread-handlers-C3Iya92v.d.mts} +6 -5
- package/dist/thread-handlers-C3Iya92v.d.mts.map +1 -0
- package/dist/{tools-CEsv-WoO.mjs → tools-D0KBDolR.mjs} +435 -408
- package/dist/tools-D0KBDolR.mjs.map +1 -0
- package/dist/turn-survey-draft-B34lggSG.d.mts +185 -0
- package/dist/turn-survey-draft-B34lggSG.d.mts.map +1 -0
- package/dist/ui.d.mts +3 -3
- package/dist/ui.d.mts.map +1 -1
- package/dist/ui.mjs +35 -23
- package/dist/ui.mjs.map +1 -1
- package/package.json +7 -7
- package/dist/authoring-references-DbuOKerg.mjs.map +0 -1
- package/dist/capabilities-CmeeAjEc.d.mts +0 -192
- package/dist/capabilities-CmeeAjEc.d.mts.map +0 -1
- package/dist/capabilities-DCMA71PP.mjs +0 -58
- package/dist/capabilities-DCMA71PP.mjs.map +0 -1
- package/dist/controller-proxy-DEeFl9IA.mjs.map +0 -1
- package/dist/default-fhSon2RM.mjs +0 -760
- package/dist/default-fhSon2RM.mjs.map +0 -1
- package/dist/digest-C39WyAWG.d.mts.map +0 -1
- package/dist/engine-nXoCWYpQ.mjs +0 -6888
- package/dist/engine-nXoCWYpQ.mjs.map +0 -1
- package/dist/index-Ciq7vHIs.d.mts +0 -716
- package/dist/index-Ciq7vHIs.d.mts.map +0 -1
- package/dist/index-D7wT6P3t.d.mts.map +0 -1
- package/dist/index-WB5kfnz0.d.mts.map +0 -1
- package/dist/index-r5riv4md.d.mts.map +0 -1
- package/dist/lifecycle-Dm8u7QFh.d.mts +0 -545
- package/dist/lifecycle-Dm8u7QFh.d.mts.map +0 -1
- package/dist/protocol-CF4Bh_Ch.mjs +0 -1255
- package/dist/protocol-CF4Bh_Ch.mjs.map +0 -1
- package/dist/react-C_GY-Fsc.mjs.map +0 -1
- package/dist/references/embedded-forms.md +0 -146
- package/dist/references/item-types.md +0 -641
- package/dist/request-context-Dg4jSwN1.mjs.map +0 -1
- package/dist/tasks-BZEiwgxA.mjs.map +0 -1
- package/dist/thread-handlers-Bef0td9N.d.mts.map +0 -1
- package/dist/tools-CEsv-WoO.mjs.map +0 -1
|
@@ -10,16 +10,17 @@ Use `survey_expression` for expression work. It is the expression capability bun
|
|
|
10
10
|
|
|
11
11
|
## JsonExpression
|
|
12
12
|
|
|
13
|
-
Expression JSON has
|
|
13
|
+
Expression JSON has five node types:
|
|
14
14
|
|
|
15
15
|
```json
|
|
16
16
|
{ "type": "const", "value": { "type": "boolean", "value": true } }
|
|
17
17
|
{ "type": "responseVariable", "variableRef": { "slotId": "<slotId>", "method": "get" } }
|
|
18
18
|
{ "type": "contextVariable", "contextType": "locale" }
|
|
19
19
|
{ "type": "function", "functionName": "and", "arguments": [] }
|
|
20
|
+
{ "type": "ownerState", "state": "disabled", "targetRef": { "ownerId": "<ownerId>" } }
|
|
20
21
|
```
|
|
21
22
|
|
|
22
|
-
Optional `editorConfig`
|
|
23
|
+
Optional `editorConfig` contains only `usedTemplate`, `label`, and `description`; unknown keys are rejected. Missing argument-array operands are `null`, preserving their positions across JSON round trips. Required gaps are unfinished expressions, not false values. Optional single children such as a context key are omitted properties.
|
|
23
24
|
|
|
24
25
|
## Response Values And Variables
|
|
25
26
|
|
|
@@ -57,8 +58,7 @@ component's visibility. Repair rejected changes using the returned retry linkage
|
|
|
57
58
|
Hidden answers remain stored for the session and return when shown again, but are unavailable
|
|
58
59
|
to expressions, validation, scoring and submission while hidden. `get` returns undefined and
|
|
59
60
|
`isDefined` returns false for an inactive answer. This includes hidden groups, matrix rows,
|
|
60
|
-
|
|
61
|
-
undefined or non-boolean results hide their target. Visibility cannot use `customExpression`
|
|
61
|
+
semantic sections, hidden choice options and unselected follow-up inputs. With no visibility condition the target is visible. An authored visibility expression returning missing or false makes it inactive; a defined non-boolean result is inactive with a diagnostic. Visibility cannot use `customExpression`
|
|
62
62
|
callbacks; supply serialized `customValue` context instead.
|
|
63
63
|
|
|
64
64
|
Never invent response refs. Use the current context response-slots scope or item details.
|
|
@@ -87,15 +87,30 @@ Always check the response slot value type before choosing a function:
|
|
|
87
87
|
- Multiple-choice choice items return `reference[]`; check selected options with `list_contains` and a `reference` const.
|
|
88
88
|
- `list_contains` must receive `string[]` + `string` or `reference[]` + `reference`. Never use it with a single `reference` response.
|
|
89
89
|
|
|
90
|
-
Context variable types are `locale`, `
|
|
90
|
+
Context variable types are `locale`, `currentDate`, `participantFlag`, and `customValue`.
|
|
91
|
+
`{ "type": "contextVariable", "contextType": "currentDate" }` returns the participant's current
|
|
92
|
+
day as a full `date`. It takes no key; the host fixes it when the session starts and records it with
|
|
93
|
+
the response, so submission validation and export replay see the same day. Opaque callbacks (`customExpression`) are not part of the grammar; use recorded custom values so player, submission validation and export replay agree.
|
|
91
94
|
|
|
92
95
|
## Functions
|
|
93
96
|
|
|
94
97
|
Boolean: `and`, `or`, `not`.
|
|
95
98
|
List containment: `list_contains`.
|
|
99
|
+
List counting: `list_count(list)` returns the number of entries in any array value;
|
|
100
|
+
`list_count(list, filter)` counts only entries that also appear in `filter`, a list of the same
|
|
101
|
+
type. A missing list (for example an unanswered multiple choice) counts as `0`; use `isDefined`
|
|
102
|
+
to tell unanswered from none selected. For "at least two of these options selected":
|
|
103
|
+
`gte(list_count(<reference[] ref>, const(reference[], ["<optionId>", ...])), const(number, 2))`.
|
|
104
|
+
Filter option ids must be declared option identities, as with `list_contains`.
|
|
96
105
|
Equality/comparison: `eq`, `gt`, `gte`, `lt`, `lte`, `in_range`.
|
|
97
106
|
Numeric aggregation: `sum`, `min`, `max`.
|
|
98
107
|
String equality: `str_eq`.
|
|
108
|
+
Conditional value: `if(condition, then, else)` returns `then` when the boolean condition is true
|
|
109
|
+
and `else` when it is false; only the chosen branch is evaluated. `else` is optional (missing when
|
|
110
|
+
omitted), and a missing condition returns missing rather than `else`. The result type is the
|
|
111
|
+
branches' type: both branches must have the same type, and the usage checks it like any other
|
|
112
|
+
result (e.g. a score uses number branches, a visibility condition boolean branches). Nest `if`
|
|
113
|
+
calls for more than two cases, e.g. `if(c1, a, if(c2, b, c))`.
|
|
99
114
|
Calendar dates use `YYYY`, `YYYY-MM`, or `YYYY-MM-DD`; numeric timestamps and date-time strings are invalid. Preserve the answer's precision.
|
|
100
115
|
|
|
101
116
|
Date comparisons: `date_eq`, `date_gt`, `date_gte`, `date_lt`, `date_lte` (two date arguments).
|
|
@@ -104,18 +119,34 @@ Equality includes precision; ordering requires matching precision and returns un
|
|
|
104
119
|
`date_add_days`, `date_add_months`, `date_add_years` take a date and a signed integer number.
|
|
105
120
|
Offsets retain precision; month/year offsets clamp to the last day of the destination month.
|
|
106
121
|
Nonzero day offsets require full dates, nonzero month offsets require at least month precision.
|
|
107
|
-
`date_diff(a, b)` returns signed
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
122
|
+
`date_diff(a, b, unit)` returns the signed number of completed units in `a - b`. `unit` is a
|
|
123
|
+
required string const: `"years"`, `"months"`, or `"days"`. Mixed precisions are compared at the
|
|
124
|
+
coarser one (a year-only birth date gives calendar-year differences), and a unit finer than that
|
|
125
|
+
precision returns undefined. Missing values propagate undefined; do not use timestamps or divide
|
|
126
|
+
days to calculate ages. Age in years:
|
|
127
|
+
`date_diff(contextVariable(currentDate), responseVariable(<birth date>), const(string, "years"))`.
|
|
128
|
+
For an "at least N years old" check, use `gte(date_diff(...), const(number, N))`, which works
|
|
129
|
+
for every birth-date precision. The anniversary form
|
|
130
|
+
`date_lte(date_add_years(<birth date>, N), currentDate)` only works for full `YYYY-MM-DD` birth
|
|
131
|
+
dates: for a year or month birth date it compares mismatched precisions and returns undefined.
|
|
132
|
+
For full dates the two agree except on February 29 birthdays, which reach an anniversary on
|
|
133
|
+
February 28 with the anniversary form and on March 1 with `date_diff`.
|
|
134
|
+
|
|
135
|
+
Number and date inputs (and form-matrix number/date fields) take `min` / `max` bounds that are a
|
|
136
|
+
literal or `{expression, fallback?}`. Use a response reference or arithmetic expression of the
|
|
137
|
+
input's type. For example, a latest date seven days after another answer uses
|
|
138
|
+
`date_add_days(responseVariable(...), const(number, 7))`. When the expression has no value (for
|
|
139
|
+
example the referenced answer is empty), the bound does not apply, unless it has a `fallback`.
|
|
140
|
+
Slider bounds from an expression require a `fallback`.
|
|
141
|
+
Use set-config-expression with path `/min/expression` or `/max/expression` relative to the element
|
|
142
|
+
config; an existing literal bound becomes the fallback. clear-config-expression on the same path
|
|
143
|
+
restores the fallback, or removes a bound without one. The normal expression operations remain
|
|
144
|
+
appropriate for item validations, prefills, and display conditions.
|
|
145
|
+
Date bounds are inclusive: minimum uses the start of its calendar period, maximum uses its end.
|
|
146
|
+
The entire answer period must fit within the bound. An unanswered optional date remains valid.
|
|
147
|
+
A bound whose expression has no value does not apply, unless it has a `fallback`; then the
|
|
148
|
+
fallback applies. Fixed bounds and fallbacks must leave at least one valid answer at the input's
|
|
149
|
+
precision.
|
|
119
150
|
|
|
120
151
|
Example: show an item when option "yes" is selected on choice item q1:
|
|
121
152
|
|
|
@@ -169,51 +200,72 @@ Example: multiple-select contains option "apple" when the inspected response slo
|
|
|
169
200
|
|
|
170
201
|
## New Items With Dependencies
|
|
171
202
|
|
|
172
|
-
For a newly created source and dependent, use this operation order and expression placement.
|
|
173
|
-
This pattern is item-type independent: `displayConditions` is a sibling of `config` on the
|
|
174
|
-
raw item, never inside `config` or `translations`.
|
|
203
|
+
For a newly created source and dependent, use this operation order and expression placement. This pattern is element-type independent: `visibility` is on its owner, beside `config`, never inside translations. A flow item condition applies to its complete body; an element condition applies only to that element. Replace `<root-group-id>` with the inspected root group ID.
|
|
175
204
|
|
|
176
205
|
```json
|
|
177
206
|
[
|
|
178
207
|
{
|
|
179
208
|
"kind": "create-item",
|
|
180
209
|
"target": {
|
|
181
|
-
"parentItemId": "<
|
|
210
|
+
"parentItemId": "<root-group-id>"
|
|
182
211
|
},
|
|
183
212
|
"item": {
|
|
184
|
-
"id": "
|
|
185
|
-
"itemType": "
|
|
213
|
+
"id": "routing",
|
|
214
|
+
"itemType": "content",
|
|
186
215
|
"config": {
|
|
187
|
-
"
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
216
|
+
"body": {
|
|
217
|
+
"blocks": [
|
|
218
|
+
{
|
|
219
|
+
"kind": "layout",
|
|
220
|
+
"id": "routing-layout",
|
|
221
|
+
"layout": {
|
|
222
|
+
"mode": "automatic",
|
|
223
|
+
"maxColumns": 1
|
|
224
|
+
},
|
|
225
|
+
"elements": [
|
|
226
|
+
{
|
|
227
|
+
"kind": "element",
|
|
228
|
+
"id": "routing-choice",
|
|
229
|
+
"elementType": "choice",
|
|
230
|
+
"config": {
|
|
231
|
+
"slotId": "routing-slot",
|
|
232
|
+
"variableName": "routing_choice",
|
|
233
|
+
"presentation": "radio",
|
|
234
|
+
"options": [
|
|
235
|
+
{
|
|
236
|
+
"id": "routing-a",
|
|
237
|
+
"code": "A"
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
"id": "routing-b",
|
|
241
|
+
"code": "B"
|
|
242
|
+
}
|
|
243
|
+
]
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
]
|
|
247
|
+
}
|
|
248
|
+
]
|
|
249
|
+
}
|
|
201
250
|
}
|
|
202
251
|
},
|
|
203
252
|
"translations": [
|
|
204
253
|
{
|
|
254
|
+
"ownerId": "routing",
|
|
255
|
+
"role": "title",
|
|
205
256
|
"locale": "en",
|
|
206
|
-
"contentKey": "title",
|
|
207
257
|
"plainText": "Choose an option"
|
|
208
258
|
},
|
|
209
259
|
{
|
|
260
|
+
"ownerId": "routing-a",
|
|
261
|
+
"role": "label",
|
|
210
262
|
"locale": "en",
|
|
211
|
-
"contentKey": "options.option_a.label",
|
|
212
263
|
"plainText": "Option A"
|
|
213
264
|
},
|
|
214
265
|
{
|
|
266
|
+
"ownerId": "routing-b",
|
|
267
|
+
"role": "label",
|
|
215
268
|
"locale": "en",
|
|
216
|
-
"contentKey": "options.option_b.label",
|
|
217
269
|
"plainText": "Option B"
|
|
218
270
|
}
|
|
219
271
|
]
|
|
@@ -221,259 +273,184 @@ raw item, never inside `config` or `translations`.
|
|
|
221
273
|
{
|
|
222
274
|
"kind": "create-item",
|
|
223
275
|
"target": {
|
|
224
|
-
"parentItemId": "<
|
|
276
|
+
"parentItemId": "<root-group-id>"
|
|
225
277
|
},
|
|
226
278
|
"item": {
|
|
227
|
-
"id": "
|
|
228
|
-
"itemType": "
|
|
279
|
+
"id": "routing-followup-a",
|
|
280
|
+
"itemType": "content",
|
|
229
281
|
"config": {
|
|
230
|
-
"
|
|
231
|
-
|
|
232
|
-
"shuffleOptions": false,
|
|
233
|
-
"options": [
|
|
234
|
-
{
|
|
235
|
-
"id": "yes",
|
|
236
|
-
"code": "yes"
|
|
237
|
-
},
|
|
238
|
-
{
|
|
239
|
-
"id": "no",
|
|
240
|
-
"code": "no"
|
|
241
|
-
}
|
|
242
|
-
],
|
|
243
|
-
"variableName": "follow_up_a"
|
|
244
|
-
},
|
|
245
|
-
"displayConditions": {
|
|
246
|
-
"root": {
|
|
247
|
-
"type": "function",
|
|
248
|
-
"functionName": "eq",
|
|
249
|
-
"arguments": [
|
|
282
|
+
"body": {
|
|
283
|
+
"blocks": [
|
|
250
284
|
{
|
|
251
|
-
"
|
|
252
|
-
"
|
|
253
|
-
|
|
254
|
-
"
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
285
|
+
"kind": "layout",
|
|
286
|
+
"id": "routing-followup-a-layout",
|
|
287
|
+
"layout": {
|
|
288
|
+
"mode": "automatic",
|
|
289
|
+
"maxColumns": 1
|
|
290
|
+
},
|
|
291
|
+
"elements": [
|
|
292
|
+
{
|
|
293
|
+
"kind": "element",
|
|
294
|
+
"id": "routing-followup-a-text",
|
|
295
|
+
"elementType": "text",
|
|
296
|
+
"config": {
|
|
297
|
+
"slotId": "routing-followup-a-slot",
|
|
298
|
+
"variableName": "followup_a",
|
|
299
|
+
"presentation": "long"
|
|
300
|
+
}
|
|
301
|
+
}
|
|
302
|
+
]
|
|
263
303
|
}
|
|
264
304
|
]
|
|
265
305
|
}
|
|
306
|
+
},
|
|
307
|
+
"visibility": {
|
|
308
|
+
"type": "function",
|
|
309
|
+
"functionName": "eq",
|
|
310
|
+
"arguments": [
|
|
311
|
+
{
|
|
312
|
+
"type": "responseVariable",
|
|
313
|
+
"variableRef": {
|
|
314
|
+
"slotId": "routing-slot",
|
|
315
|
+
"method": "get"
|
|
316
|
+
}
|
|
317
|
+
},
|
|
318
|
+
{
|
|
319
|
+
"type": "const",
|
|
320
|
+
"value": {
|
|
321
|
+
"type": "reference",
|
|
322
|
+
"value": "routing-a"
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
]
|
|
266
326
|
}
|
|
267
327
|
},
|
|
268
328
|
"translations": [
|
|
269
329
|
{
|
|
330
|
+
"ownerId": "routing-followup-a",
|
|
331
|
+
"role": "title",
|
|
270
332
|
"locale": "en",
|
|
271
|
-
"
|
|
272
|
-
"plainText": "Follow-up for option A"
|
|
273
|
-
},
|
|
274
|
-
{
|
|
275
|
-
"locale": "en",
|
|
276
|
-
"contentKey": "options.yes.label",
|
|
277
|
-
"plainText": "Yes"
|
|
278
|
-
},
|
|
279
|
-
{
|
|
280
|
-
"locale": "en",
|
|
281
|
-
"contentKey": "options.no.label",
|
|
282
|
-
"plainText": "No"
|
|
333
|
+
"plainText": "Details for option A"
|
|
283
334
|
}
|
|
284
335
|
]
|
|
285
336
|
},
|
|
286
337
|
{
|
|
287
338
|
"kind": "create-item",
|
|
288
339
|
"target": {
|
|
289
|
-
"parentItemId": "<
|
|
340
|
+
"parentItemId": "<root-group-id>"
|
|
290
341
|
},
|
|
291
342
|
"item": {
|
|
292
|
-
"id": "
|
|
293
|
-
"itemType": "
|
|
343
|
+
"id": "routing-followup-b",
|
|
344
|
+
"itemType": "content",
|
|
294
345
|
"config": {
|
|
295
|
-
"
|
|
296
|
-
|
|
297
|
-
"shuffleOptions": false,
|
|
298
|
-
"options": [
|
|
299
|
-
{
|
|
300
|
-
"id": "yes",
|
|
301
|
-
"code": "yes"
|
|
302
|
-
},
|
|
303
|
-
{
|
|
304
|
-
"id": "no",
|
|
305
|
-
"code": "no"
|
|
306
|
-
}
|
|
307
|
-
],
|
|
308
|
-
"variableName": "follow_up_b"
|
|
309
|
-
},
|
|
310
|
-
"displayConditions": {
|
|
311
|
-
"root": {
|
|
312
|
-
"type": "function",
|
|
313
|
-
"functionName": "eq",
|
|
314
|
-
"arguments": [
|
|
315
|
-
{
|
|
316
|
-
"type": "responseVariable",
|
|
317
|
-
"variableRef": {
|
|
318
|
-
"slotId": "routing_choice",
|
|
319
|
-
"method": "get"
|
|
320
|
-
}
|
|
321
|
-
},
|
|
346
|
+
"body": {
|
|
347
|
+
"blocks": [
|
|
322
348
|
{
|
|
323
|
-
"
|
|
324
|
-
"
|
|
325
|
-
|
|
326
|
-
"
|
|
327
|
-
|
|
349
|
+
"kind": "layout",
|
|
350
|
+
"id": "routing-followup-b-layout",
|
|
351
|
+
"layout": {
|
|
352
|
+
"mode": "automatic",
|
|
353
|
+
"maxColumns": 1
|
|
354
|
+
},
|
|
355
|
+
"elements": [
|
|
356
|
+
{
|
|
357
|
+
"kind": "element",
|
|
358
|
+
"id": "routing-followup-b-text",
|
|
359
|
+
"elementType": "text",
|
|
360
|
+
"config": {
|
|
361
|
+
"slotId": "routing-followup-b-slot",
|
|
362
|
+
"variableName": "followup_b",
|
|
363
|
+
"presentation": "long"
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
]
|
|
328
367
|
}
|
|
329
368
|
]
|
|
330
369
|
}
|
|
370
|
+
},
|
|
371
|
+
"visibility": {
|
|
372
|
+
"type": "function",
|
|
373
|
+
"functionName": "eq",
|
|
374
|
+
"arguments": [
|
|
375
|
+
{
|
|
376
|
+
"type": "responseVariable",
|
|
377
|
+
"variableRef": {
|
|
378
|
+
"slotId": "routing-slot",
|
|
379
|
+
"method": "get"
|
|
380
|
+
}
|
|
381
|
+
},
|
|
382
|
+
{
|
|
383
|
+
"type": "const",
|
|
384
|
+
"value": {
|
|
385
|
+
"type": "reference",
|
|
386
|
+
"value": "routing-b"
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
]
|
|
331
390
|
}
|
|
332
391
|
},
|
|
333
392
|
"translations": [
|
|
334
393
|
{
|
|
394
|
+
"ownerId": "routing-followup-b",
|
|
395
|
+
"role": "title",
|
|
335
396
|
"locale": "en",
|
|
336
|
-
"
|
|
337
|
-
"plainText": "Follow-up for option B"
|
|
338
|
-
},
|
|
339
|
-
{
|
|
340
|
-
"locale": "en",
|
|
341
|
-
"contentKey": "options.yes.label",
|
|
342
|
-
"plainText": "Yes"
|
|
343
|
-
},
|
|
344
|
-
{
|
|
345
|
-
"locale": "en",
|
|
346
|
-
"contentKey": "options.no.label",
|
|
347
|
-
"plainText": "No"
|
|
397
|
+
"plainText": "Details for option B"
|
|
348
398
|
}
|
|
349
399
|
]
|
|
350
400
|
}
|
|
351
401
|
]
|
|
352
402
|
```
|
|
353
403
|
|
|
354
|
-
|
|
355
|
-
translations change. The validator makes response slots from earlier creates available to later
|
|
356
|
-
creates in this one operations array.
|
|
357
|
-
|
|
358
|
-
## survey_expression Mutations
|
|
404
|
+
The validator makes response slots from earlier creates available to later creates in this one operations array. This example creates separate conditional questions. For content directly below a radio/checkbox option, use an option-inline follow-up instead; it already has an activation gate.
|
|
359
405
|
|
|
360
|
-
|
|
361
|
-
server validates every entry against these canonical shapes before changing the request-scoped
|
|
362
|
-
draft.
|
|
406
|
+
## Disabled state and applicability
|
|
363
407
|
|
|
364
|
-
|
|
408
|
+
`ownerState` with `state: "disabled"` is the stored form of `isDisabled(owner)`. It reads the configured and inherited disabling of an inspected structural owner. It always returns boolean. It does not report visibility, answer presence or whether a choice cap permits a change. Answer and state dependencies share one cycle-checked graph. A parent reading its own child's disabled state is cyclic because the child inherits from that parent.
|
|
365
409
|
|
|
366
|
-
|
|
367
|
-
{
|
|
368
|
-
"kind": "set-item-display-condition",
|
|
369
|
-
"itemId": "followup_yes",
|
|
370
|
-
"expression": {
|
|
371
|
-
"type": "function",
|
|
372
|
-
"functionName": "eq",
|
|
373
|
-
"arguments": [
|
|
374
|
-
{
|
|
375
|
-
"type": "responseVariable",
|
|
376
|
-
"variableRef": {
|
|
377
|
-
"slotId": "q1",
|
|
378
|
-
"method": "get"
|
|
379
|
-
}
|
|
380
|
-
},
|
|
381
|
-
{
|
|
382
|
-
"type": "const",
|
|
383
|
-
"value": {
|
|
384
|
-
"type": "reference",
|
|
385
|
-
"value": "yes"
|
|
386
|
-
}
|
|
387
|
-
}
|
|
388
|
-
]
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
|
-
```
|
|
410
|
+
Active disabled answers are retained, readable in expressions and submitted. Participant writes are rejected while the whole input or an ancestor is disabled; initialization has its separate engine-owned path. Validation cannot block on targets the participant cannot change. Disabled checkbox options are locked; single-choice replacement can leave a disabled selection for an enabled destination. Hidden answers remain unavailable instead. Use visibility for “not applicable” and disabled for locking, not as a way of removing answers from data.
|
|
392
411
|
|
|
393
|
-
|
|
394
|
-
`set-component-display-condition` with `itemId`, `componentId`, and a boolean `expression`.
|
|
395
|
-
For choice options the component id is usually the option id. For form fields or field groups, inspect item details/raw JSON first.
|
|
412
|
+
“Selected and enabled” is an authoring shortcut expanded into `and(selectionTest, not(ownerState(...)))`. Use eq for single choice, list_contains for checkbox selection. It is not a new persisted function. Disabled ancestors also make this false, including intentionally read-only prefilled items. Do not use the shortcut where the condition should still honor such answers. Mutual selected-and-enabled disabling may create a cycle; ordinary selection-based exclusivity avoids adding that state loop.
|
|
396
413
|
|
|
397
|
-
|
|
398
|
-
`set-component-disabled-condition` with `itemId`, `componentId`, and a boolean `expression`.
|
|
414
|
+
## Creation and expression mutations
|
|
399
415
|
|
|
400
|
-
|
|
401
|
-
`set-validation-expression` with `itemId`, `validationKey`, and a boolean `expression`.
|
|
402
|
-
Add a matching validation message translation when respondents need visible feedback.
|
|
416
|
+
Create source owners before their dependents. New owners may carry `visibility`, `disabled`, prefills and validation expressions in their creation payloads. For existing owners, use `survey_expression` with these mutations:
|
|
403
417
|
|
|
404
|
-
|
|
405
|
-
`
|
|
406
|
-
|
|
418
|
+
- `set-condition`: `ownerId`, `property` (`visibility` or `disabled`), boolean `expression`.
|
|
419
|
+
- `clear-condition`: the same owner and property; absent visibility means visible and absent disabling means enabled, subject to ancestors.
|
|
420
|
+
- `set-config-expression`: `elementId`, inspected config-relative JSON Pointer `path`, and `expression`. The exact field must be declared as an expression by the installed element schema, including custom definitions.
|
|
421
|
+
- `clear-config-expression`: the same element and path; schema-required fields cannot be cleared.
|
|
422
|
+
- `set-validation-rule`: `itemId` and complete `rule` (`id`, nonempty `targets` slot IDs, boolean `expression`, optional boolean `when`, optional `phase: page|submit`). Its localized message belongs to that rule ID's `message` role.
|
|
423
|
+
- `remove-validation-rule`: `itemId`, `ruleId`.
|
|
424
|
+
- `set-prefill`: `elementId`, `slotId`, complete `prefill`.
|
|
425
|
+
- `clear-prefill`: `elementId`, `slotId`, `prefillId`.
|
|
426
|
+
- `set-template-value`: `templateKey`, complete `templateValue`.
|
|
427
|
+
- `clear-template-value`: `templateKey`.
|
|
407
428
|
|
|
408
|
-
|
|
409
|
-
`set-template-value` with `templateKey` and `templateValue`.
|
|
410
|
-
The template expression should match `returnType`; `date2string` also needs `dateFormat`.
|
|
429
|
+
Inspect exact owner IDs and expression locations. Conditions live directly on their annotated owner; prefills live at `element.prefills[slotId]`; validation rules live in `contentItem.config.validationRules`. Never reconstruct a location from a display label or old component path. Rules target slots owned by their item and cannot block when no target is active and changeable.
|
|
411
430
|
|
|
412
|
-
|
|
413
|
-
`clear-item-display-condition`, `clear-component-display-condition`,
|
|
414
|
-
`clear-component-disabled-condition`, `clear-validation-expression`,
|
|
415
|
-
`clear-prefill`, and `clear-template-value`.
|
|
416
|
-
|
|
417
|
-
## Storage Locations
|
|
418
|
-
|
|
419
|
-
Item display condition:
|
|
420
|
-
`/surveyItems/<itemIndex>/displayConditions/root`
|
|
421
|
-
|
|
422
|
-
Component display condition:
|
|
423
|
-
`/surveyItems/<itemIndex>/displayConditions/components/<componentId>`
|
|
424
|
-
|
|
425
|
-
Component disabled condition:
|
|
426
|
-
`/surveyItems/<itemIndex>/disabledConditions/components/<componentId>`
|
|
427
|
-
|
|
428
|
-
Item validation expression:
|
|
429
|
-
`/surveyItems/<itemIndex>/validations/<validationKey>`
|
|
430
|
-
|
|
431
|
-
Prefills:
|
|
432
|
-
`/surveyItems/<itemIndex>/prefills`
|
|
433
|
-
|
|
434
|
-
Template values:
|
|
435
|
-
`/templateValues/<templateValueKey>`
|
|
431
|
+
Page rules that read another item's answers can prevent reaching those answers on a later page. Inspect the shared `cross-item-page-rule` advisory; use submit-phase validation or an explicit unanswered-dependency condition when appropriate. Do not silently change an existing rule's phase.
|
|
436
432
|
|
|
437
433
|
## Prefills
|
|
438
434
|
|
|
439
|
-
|
|
435
|
+
Prefills initialize **once** when creating a new session, including hidden inputs, disabled inputs and closed follow-ups. They do not reapply while answering, after clearing a field, or on resume. A resumed session restores its versioned snapshot without new prefill lookups. Hiding/disabling retains initialized and participant-entered answers. Never use repeated prefilling to enforce exclusivity.
|
|
436
|
+
|
|
437
|
+
A prefill has `id`, optional boolean `when`, optional `apply: "ifEmpty"`, and `source`. Its target is the surrounding element's slot key, not an itemResponse/field/embeddedField descriptor.
|
|
440
438
|
|
|
441
439
|
```json
|
|
442
440
|
{
|
|
443
|
-
"
|
|
444
|
-
"
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
"type": "
|
|
449
|
-
"value": {
|
|
450
|
-
"type": "boolean",
|
|
451
|
-
"value": true
|
|
452
|
-
}
|
|
453
|
-
},
|
|
454
|
-
"apply": "ifEmpty",
|
|
455
|
-
"source": {
|
|
456
|
-
"type": "static",
|
|
457
|
-
"value": {
|
|
458
|
-
"type": "string",
|
|
459
|
-
"value": "x"
|
|
460
|
-
}
|
|
441
|
+
"kind": "set-prefill",
|
|
442
|
+
"elementId": "name-input",
|
|
443
|
+
"slotId": "name-slot",
|
|
444
|
+
"prefill": {
|
|
445
|
+
"id": "name-initial",
|
|
446
|
+
"source": { "type": "static", "value": { "type": "string", "value": "Example" } }
|
|
461
447
|
}
|
|
462
448
|
}
|
|
463
449
|
```
|
|
464
450
|
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
- `{ "type": "itemResponse" }`
|
|
468
|
-
- `{ "type": "field", "fieldId": "<fieldId>" }`
|
|
469
|
-
- `{ "type": "embeddedField", "optionId": "<optionId>", "fieldId": "<fieldId>" }`
|
|
470
|
-
|
|
471
|
-
Sources:
|
|
451
|
+
Sources are static typed value, expression, templateValue key, or previousResponse with `ref: {surveyKey?, slotId}` and optional `ifUnsupported: "skip"`. Inspect host capabilities before depending on previous responses. Values must match the target slot's domain; scores/computed slots are not prefill targets. Prefill dependencies also participate in cycle checking.
|
|
472
452
|
|
|
473
|
-
|
|
474
|
-
- `expression`: JsonExpression.
|
|
475
|
-
- `templateValue`: `{ "key": "<templateValueKey>" }`.
|
|
476
|
-
- `previousResponse`: `{ "ref": { "surveyKey"?, "itemId", "target"? }, "ifUnsupported": "skip" }`.
|
|
453
|
+
Do not assume a host provides previous responses. Survey Mode currently does not; it rejects publication with a required unsupported source. Use `ifUnsupported: "skip"` only when omitting that initial value is intentional. Invalid derived prefill values are skipped with a located diagnostic and later candidates may apply; do not treat that as permission to author incompatible values.
|
|
477
454
|
|
|
478
455
|
## Template Values
|
|
479
456
|
|
|
@@ -493,7 +470,7 @@ Template value shape:
|
|
|
493
470
|
}
|
|
494
471
|
```
|
|
495
472
|
|
|
496
|
-
Date formatting template values use `type: "
|
|
473
|
+
Date formatting template values use `type: "formatDate"`, `returnType: "string"`, and `dateFormat`.
|
|
497
474
|
|
|
498
475
|
## Bounded context and atomic batches
|
|
499
476
|
|