@object-ui/core 17.6.0 → 18.0.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/CHANGELOG.md +7260 -0
- package/README.md +228 -14
- package/dist/actions/ActionEngine.d.ts +4 -2
- package/dist/actions/ActionEngine.js +13 -8
- package/dist/actions/ActionRunner.d.ts +473 -69
- package/dist/actions/ActionRunner.js +792 -125
- package/dist/actions/TransactionManager.d.ts +7 -2
- package/dist/actions/UndoManager.d.ts +8 -13
- package/dist/actions/actionKeys.d.ts +9 -7
- package/dist/actions/actionKeys.js +67 -14
- package/dist/actions/actionResponse.js +2 -2
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.js +2 -0
- package/dist/actions/navigationTarget.d.ts +41 -0
- package/dist/actions/navigationTarget.js +20 -0
- package/dist/actions/recordDelete.d.ts +154 -0
- package/dist/actions/recordDelete.js +110 -0
- package/dist/adapters/ApiDataSource.d.ts +8 -4
- package/dist/adapters/ApiDataSource.js +19 -7
- package/dist/adapters/ValueDataSource.d.ts +6 -1
- package/dist/adapters/ValueDataSource.js +1090 -98
- package/dist/adapters/batchTransaction.d.ts +1 -1
- package/dist/adapters/batchTransaction.js +1 -1
- package/dist/adapters/resolveDataSource.d.ts +9 -6
- package/dist/adapters/resolveDataSource.js +9 -12
- package/dist/builder/schema-builder.d.ts +38 -81
- package/dist/builder/schema-builder.js +33 -152
- package/dist/data-scope/ViewDataProvider.d.ts +8 -25
- package/dist/data-scope/ViewDataProvider.js +27 -54
- package/dist/data-scope/element-data-source.d.ts +261 -7
- package/dist/data-scope/element-data-source.js +342 -52
- package/dist/data-scope/index.d.ts +9 -4
- package/dist/data-scope/index.js +9 -4
- package/dist/evaluator/ExpressionEvaluator.d.ts +86 -0
- package/dist/evaluator/ExpressionEvaluator.js +184 -12
- package/dist/evaluator/FormulaFunctions.d.ts +0 -10
- package/dist/evaluator/FormulaFunctions.js +166 -27
- package/dist/evaluator/deadlineSettled.d.ts +40 -0
- package/dist/evaluator/deadlineSettled.js +45 -0
- package/dist/evaluator/declaredPredicate.d.ts +93 -9
- package/dist/evaluator/declaredPredicate.js +117 -16
- package/dist/evaluator/fieldRules.d.ts +88 -4
- package/dist/evaluator/fieldRules.js +208 -31
- package/dist/evaluator/index.d.ts +2 -0
- package/dist/evaluator/index.js +2 -0
- package/dist/evaluator/listConditional.d.ts +103 -34
- package/dist/evaluator/listConditional.js +127 -50
- package/dist/evaluator/optionRules.d.ts +77 -6
- package/dist/evaluator/optionRules.js +87 -10
- package/dist/evaluator/predicateInput.d.ts +15 -4
- package/dist/evaluator/predicateInput.js +35 -2
- package/dist/evaluator/rowPredicateCanon.d.ts +7 -18
- package/dist/evaluator/rowPredicateCanon.js +65 -115
- package/dist/evaluator/subjectPermissions.d.ts +105 -0
- package/dist/evaluator/subjectPermissions.js +86 -0
- package/dist/evaluator/unevaluablePredicate.d.ts +57 -0
- package/dist/evaluator/unevaluablePredicate.js +70 -0
- package/dist/index.d.ts +15 -0
- package/dist/index.js +83 -2
- package/dist/protocols/index.d.ts +0 -1
- package/dist/protocols/index.js +9 -1
- package/dist/registry/Registry.d.ts +382 -34
- package/dist/registry/Registry.js +247 -12
- package/dist/registry/WidgetRegistry.js +7 -3
- package/dist/registry/html-tier-intrinsics.d.ts +90 -0
- package/dist/registry/html-tier-intrinsics.js +110 -0
- package/dist/registry/public-blocks.d.ts +8 -0
- package/dist/registry/public-blocks.js +57 -0
- package/dist/theme/ThemeEngine.js +1 -1
- package/dist/utils/affordanceGrants.d.ts +371 -0
- package/dist/utils/affordanceGrants.js +252 -0
- package/dist/utils/chart-category-key.d.ts +82 -0
- package/dist/utils/chart-category-key.js +84 -0
- package/dist/utils/chart-measure-key.d.ts +64 -0
- package/dist/utils/chart-measure-key.js +65 -0
- package/dist/utils/chart-presentation.d.ts +95 -112
- package/dist/utils/chart-presentation.js +169 -104
- package/dist/utils/chart-series.d.ts +165 -5
- package/dist/utils/chart-series.js +123 -18
- package/dist/utils/column-sortability.d.ts +157 -0
- package/dist/utils/column-sortability.js +217 -0
- package/dist/utils/dashboard-filters.d.ts +38 -6
- package/dist/utils/dashboard-filters.js +107 -61
- package/dist/utils/dataset-format.d.ts +211 -30
- package/dist/utils/dataset-format.js +389 -46
- package/dist/utils/date-display.d.ts +346 -0
- package/dist/utils/date-display.js +644 -0
- package/dist/utils/date-macros.js +7 -0
- package/dist/utils/drill-down.d.ts +78 -0
- package/dist/utils/drill-down.js +93 -0
- package/dist/utils/emptiness.d.ts +96 -0
- package/dist/utils/emptiness.js +101 -0
- package/dist/utils/expand-fields.d.ts +81 -9
- package/dist/utils/expand-fields.js +81 -9
- package/dist/utils/extract-records.d.ts +65 -5
- package/dist/utils/extract-records.js +65 -8
- package/dist/utils/filter-converter.d.ts +158 -6
- package/dist/utils/filter-converter.js +1098 -24
- package/dist/utils/filter-tokens.d.ts +49 -5
- package/dist/utils/filter-tokens.js +105 -33
- package/dist/utils/grouping-fields.d.ts +61 -0
- package/dist/utils/grouping-fields.js +84 -0
- package/dist/utils/managedBy.d.ts +3 -3
- package/dist/utils/managedBy.js +5 -5
- package/dist/utils/native-date-value.d.ts +48 -0
- package/dist/utils/native-date-value.js +167 -0
- package/dist/utils/non-grid-row-ceiling.d.ts +143 -0
- package/dist/utils/non-grid-row-ceiling.js +141 -0
- package/dist/utils/normalize-list-view.d.ts +135 -11
- package/dist/utils/normalize-list-view.js +243 -64
- package/dist/utils/number-display.d.ts +63 -14
- package/dist/utils/number-display.js +34 -12
- package/dist/utils/object-aggregate-query.d.ts +113 -0
- package/dist/utils/object-aggregate-query.js +50 -0
- package/dist/utils/parent-scope.d.ts +123 -0
- package/dist/utils/parent-scope.js +140 -0
- package/dist/utils/predicate-fields.d.ts +45 -12
- package/dist/utils/predicate-fields.js +141 -12
- package/dist/utils/record-color.d.ts +75 -0
- package/dist/utils/record-color.js +65 -0
- package/dist/utils/record-source.d.ts +298 -0
- package/dist/utils/record-source.js +331 -0
- package/dist/utils/record-title.d.ts +148 -8
- package/dist/utils/record-title.js +220 -26
- package/dist/utils/reference-keys.d.ts +21 -22
- package/dist/utils/reference-keys.js +532 -29
- package/dist/utils/sort-query.d.ts +115 -15
- package/dist/utils/sort-query.js +240 -13
- package/dist/utils/text-comparand.d.ts +92 -0
- package/dist/utils/text-comparand.js +99 -0
- package/dist/utils/without-denied-fields.d.ts +49 -0
- package/dist/utils/without-denied-fields.js +52 -0
- package/dist/validation/index.d.ts +8 -4
- package/dist/validation/index.js +8 -4
- package/dist/validation/schema-validator.d.ts +1 -1
- package/dist/validation/schema-validator.js +225 -83
- package/dist/validation/server-owned-value.d.ts +5 -1
- package/dist/validation/server-owned-value.js +5 -1
- package/dist/validation/validators/object-validation-engine.d.ts +1 -1
- package/dist/validation/validators/object-validation-engine.js +14 -3
- package/package.json +8 -9
- package/dist/data-scope/DataScopeManager.d.ts +0 -127
- package/dist/data-scope/DataScopeManager.js +0 -229
- package/dist/protocols/ResponsiveProtocol.d.ts +0 -73
- package/dist/protocols/ResponsiveProtocol.js +0 -158
- package/dist/validation/validation-engine.d.ts +0 -88
- package/dist/validation/validation-engine.js +0 -434
|
@@ -5,53 +5,6 @@
|
|
|
5
5
|
* This source code is licensed under the MIT license found in the
|
|
6
6
|
* LICENSE file in the root directory of this source tree.
|
|
7
7
|
*/
|
|
8
|
-
/**
|
|
9
|
-
* `@object-ui/core` — ElementDataSource resolution (objectstack#5576).
|
|
10
|
-
*
|
|
11
|
-
* `PageComponentSchema.dataSource` (the spec's `ElementDataSourceSchema`) is the
|
|
12
|
-
* per-element data binding a page component uses to query a different object
|
|
13
|
-
* than the page's own context:
|
|
14
|
-
*
|
|
15
|
-
* ```json
|
|
16
|
-
* { "object": "account", "view": "hot", "filter": { … }, "sort": [ … ], "limit": 20 }
|
|
17
|
-
* ```
|
|
18
|
-
*
|
|
19
|
-
* This module owns the two pure halves of consuming it — telling the METADATA
|
|
20
|
-
* apart from a runtime data-source adapter, and composing a named saved view
|
|
21
|
-
* with the binding's own keys. Both are needed in two places (the render path in
|
|
22
|
-
* `@object-ui/plugin-list`, and `ViewDataProvider.resolveElementDataSource`), so
|
|
23
|
-
* they live here rather than being written twice.
|
|
24
|
-
*
|
|
25
|
-
* ## Composition semantics
|
|
26
|
-
*
|
|
27
|
-
* The spec's own `describe()` text settles the one case that could go either
|
|
28
|
-
* way. `filter` is documented as "**Additional** filter criteria" — additional
|
|
29
|
-
* to what the named view already restricts — so a view filter and a binding
|
|
30
|
-
* filter COMBINE under `and`; the binding can only narrow the view, never widen
|
|
31
|
-
* it. That is also the safe direction for AI-authored metadata: a typo in a
|
|
32
|
-
* per-element filter cannot silently expose rows the saved view excluded.
|
|
33
|
-
*
|
|
34
|
-
* Nothing else in the binding is described as additional, and the remaining keys
|
|
35
|
-
* are single-valued (one ordering, one cap), so for those the rule is **the view
|
|
36
|
-
* provides the baseline and an explicit key overrides it**:
|
|
37
|
-
*
|
|
38
|
-
* | key | source | rule |
|
|
39
|
-
* |------------|-----------------------------------------|-----------------------------|
|
|
40
|
-
* | `object` | binding (required) | binding wins |
|
|
41
|
-
* | `columns` | view only — the binding has no such key | view |
|
|
42
|
-
* | `filter` | view + binding | AND-combined ("additional") |
|
|
43
|
-
* | `sort` | view or binding | binding overrides view |
|
|
44
|
-
* | `limit` | view (`pagination.pageSize`) or binding | binding overrides view |
|
|
45
|
-
* | `viewType` | view only | view |
|
|
46
|
-
*
|
|
47
|
-
* A lone `filter` — only the view has one, or only the binding does — is passed
|
|
48
|
-
* through in the shape it was stored in; only the two-source case is lowered to
|
|
49
|
-
* an ObjectQL AST, because that is what combining requires.
|
|
50
|
-
*
|
|
51
|
-
* `viewType` rides along because `list-view` IS the multi-kind view container
|
|
52
|
-
* (its registry `inputs` enumerate grid/kanban/gallery/…): naming a saved kanban
|
|
53
|
-
* view and rendering a grid would be a silently wrong answer.
|
|
54
|
-
*/
|
|
55
8
|
import { mergeFilterNodes } from '../utils/filter-converter.js';
|
|
56
9
|
import { resolveViewId } from '../utils/resolve-view-id.js';
|
|
57
10
|
const isPlainObject = (v) => !!v && typeof v === 'object' && !Array.isArray(v);
|
|
@@ -128,8 +81,42 @@ export function resolveSavedView(views, requested, object) {
|
|
|
128
81
|
const id = resolveViewId(requested, Object.keys(views), object);
|
|
129
82
|
return id === undefined ? undefined : views[id];
|
|
130
83
|
}
|
|
131
|
-
/**
|
|
132
|
-
|
|
84
|
+
/**
|
|
85
|
+
* What the contract admits as a row cap.
|
|
86
|
+
*
|
|
87
|
+
* A deliberate LOCAL RESTATEMENT of the predicate the repaired read points
|
|
88
|
+
* spell as `isUsableRowLimit` / `isUsablePageSize`. It is ⛔ not imported and
|
|
89
|
+
* ⛔ not extracted to a shared helper: this family now spells the same rule at
|
|
90
|
+
* each site that enforces it, and `isUsableRowLimit` / `isUsablePageSize` is
|
|
91
|
+
* what enumerates them. Hoisting it into one module would be a cross-package
|
|
92
|
+
* move nobody has chartered, and it would take the rule out of the file whose
|
|
93
|
+
* reader needs to see it. The cost — one more copy that could drift — is
|
|
94
|
+
* written here rather than hidden.
|
|
95
|
+
*
|
|
96
|
+
* The destination is declared positive at both ends: the spec's element data
|
|
97
|
+
* source declares `limit` a positive integer, and a saved view's pagination
|
|
98
|
+
* declares `pageSize` a positive integer with a default. So `0` is not a
|
|
99
|
+
* spelling whose meaning this layer may choose — it is a value the contract
|
|
100
|
+
* already refuses.
|
|
101
|
+
*/
|
|
102
|
+
function isUsableRowLimit(value) {
|
|
103
|
+
return typeof value === 'number' && Number.isInteger(value) && value > 0;
|
|
104
|
+
}
|
|
105
|
+
/**
|
|
106
|
+
* The row cap a saved view CARRIES, before the contract is applied to it —
|
|
107
|
+
* `pagination.pageSize`, or a flat `limit`.
|
|
108
|
+
*
|
|
109
|
+
* Split out from {@link savedViewLimit} so the resolver and the diagnostic read
|
|
110
|
+
* the same carrier by construction. Two readers would be free to drift, and the
|
|
111
|
+
* drift would be invisible: a value one of them reports and the other keeps, or
|
|
112
|
+
* the reverse.
|
|
113
|
+
*
|
|
114
|
+
* ⚠️ Selection is still by `typeof === 'number'`, unchanged: a non-numeric
|
|
115
|
+
* `pagination.pageSize` falls through to the flat `limit` exactly as it did
|
|
116
|
+
* before. Only the POSITIVITY question is new, and it is asked once, by
|
|
117
|
+
* {@link isUsableRowLimit}, on whichever carrier won.
|
|
118
|
+
*/
|
|
119
|
+
function savedViewRawLimit(view) {
|
|
133
120
|
if (!view)
|
|
134
121
|
return undefined;
|
|
135
122
|
const pagination = view.pagination;
|
|
@@ -138,6 +125,167 @@ function savedViewLimit(view) {
|
|
|
138
125
|
}
|
|
139
126
|
return typeof view.limit === 'number' ? view.limit : undefined;
|
|
140
127
|
}
|
|
128
|
+
/**
|
|
129
|
+
* Read a saved view's row cap — `pagination.pageSize`, or a flat `limit` —
|
|
130
|
+
* and hand back only a cap the contract admits.
|
|
131
|
+
*
|
|
132
|
+
* ## Why DROP, and not clamp or refuse
|
|
133
|
+
*
|
|
134
|
+
* Before this guard, `typeof … === 'number'` admitted `0`, negatives and
|
|
135
|
+
* fractions, and they lowered unchecked into the composed `limit`. Measured on
|
|
136
|
+
* both consumers of that key rather than inferred, and the two answers differ:
|
|
137
|
+
*
|
|
138
|
+
* - through a RENDERER, the refused value reached a block that has its own
|
|
139
|
+
* guard, so the block dropped it and drew its own default — the named view's
|
|
140
|
+
* cap went missing and the read went WIDER than the view asked for;
|
|
141
|
+
* - through `ViewDataProvider.resolveElementDataSource`, which forwards this
|
|
142
|
+
* key to `DataFetcher.fetchRecords` with NO guard of its own, `0`, `-10` and
|
|
143
|
+
* `25.5` reached the fetcher verbatim.
|
|
144
|
+
*
|
|
145
|
+
* ⛔ CLAMP is refused: this layer has no default to clamp to. Every consuming
|
|
146
|
+
* block owns its own default and `ViewDataProvider` owns none, so a number
|
|
147
|
+
* invented here would override a default the author never asked it to, and
|
|
148
|
+
* quietly substituting a number the author never wrote is the quieter half of
|
|
149
|
+
* this same defect.
|
|
150
|
+
*
|
|
151
|
+
* ⛔ THROWING is refused: this function is pure and sits under every block that
|
|
152
|
+
* can be bound to a view, so a throw would take out the page over one
|
|
153
|
+
* declaration — worse than the defect.
|
|
154
|
+
*
|
|
155
|
+
* ⇒ DROP. An absent `limit` is the honest statement that the view supplied no
|
|
156
|
+
* usable cap, and it is the one thing every consumer already handles.
|
|
157
|
+
*
|
|
158
|
+
* The loud half is {@link elementDataSourceRefusedLimitMessage}; see its doc for
|
|
159
|
+
* why the message is built here and reported by the caller.
|
|
160
|
+
*/
|
|
161
|
+
function savedViewLimit(view) {
|
|
162
|
+
const raw = savedViewRawLimit(view);
|
|
163
|
+
return isUsableRowLimit(raw) ? raw : undefined;
|
|
164
|
+
}
|
|
165
|
+
/**
|
|
166
|
+
* Read the binding's own row cap, and hand back only a cap the contract admits.
|
|
167
|
+
*
|
|
168
|
+
* The other operand of the `limit` chain gets the same positivity check as
|
|
169
|
+
* {@link savedViewLimit}, through the same predicate. Maintainer ruling on
|
|
170
|
+
* objectui#10016 (option A): a binding `limit` the contract refuses (`0`, a
|
|
171
|
+
* negative, a fraction, a value that is not a number at all) is NOT AUTHORED.
|
|
172
|
+
* It yields exactly as an absent one does, to the saved view's usable cap and,
|
|
173
|
+
* when that is absent too, to the consumer's own default.
|
|
174
|
+
*
|
|
175
|
+
* This is objectui#10009's precedent applied as a rule rather than re-decided:
|
|
176
|
+
* there, one layer up, a value the contract refuses was ruled not authored and
|
|
177
|
+
* the other source won. Here the same question is asked of the two operands of
|
|
178
|
+
* one resolver, and it gets the same answer. The repo therefore holds ONE
|
|
179
|
+
* precedence rule for "whose row cap is used", not one per pair of operands.
|
|
180
|
+
*
|
|
181
|
+
* The two answers the ruling refused, and why:
|
|
182
|
+
*
|
|
183
|
+
* - ⛔ dropping the binding's cap AND skipping the view's: a bad value on the
|
|
184
|
+
* binding would then discard the view's legitimate cap, which is the least
|
|
185
|
+
* explicable outcome for an author;
|
|
186
|
+
* - ⛔ refusing loudly and rendering nothing: a blank region at render time
|
|
187
|
+
* makes an author's slip expensive without making it any harder to write.
|
|
188
|
+
* The loud refusal belongs on the WRITE surface, not here.
|
|
189
|
+
*
|
|
190
|
+
* `null` stays what `??` always made it: absent.
|
|
191
|
+
*/
|
|
192
|
+
function bindingLimit(config) {
|
|
193
|
+
return isUsableRowLimit(config.limit) ? config.limit : undefined;
|
|
194
|
+
}
|
|
195
|
+
/**
|
|
196
|
+
* The binding operand's half of {@link elementDataSourceRefusedLimitMessage}.
|
|
197
|
+
* Module-private: callers reach it through that one exported builder, so there
|
|
198
|
+
* is still exactly one channel for a refused row cap, whichever operand it was.
|
|
199
|
+
*
|
|
200
|
+
* Unlike the view's message it needs no condition on the other operand. A
|
|
201
|
+
* usable binding cap is used whatever the view carries, so a refused one is
|
|
202
|
+
* ALWAYS a cap the consumer did not get, and saying so is always true.
|
|
203
|
+
*/
|
|
204
|
+
function refusedBindingLimitMessage(binding, viewName, object) {
|
|
205
|
+
const raw = binding?.limit;
|
|
206
|
+
if (raw === undefined || raw === null)
|
|
207
|
+
return null;
|
|
208
|
+
if (isUsableRowLimit(raw))
|
|
209
|
+
return null;
|
|
210
|
+
const where = viewName
|
|
211
|
+
? `dataSource binding on ${object} (view "${viewName}")`
|
|
212
|
+
: `dataSource binding on ${object}`;
|
|
213
|
+
// `String('20')` would print a string exactly like the number it is not.
|
|
214
|
+
const shown = typeof raw === 'number' ? String(raw) : String(JSON.stringify(raw));
|
|
215
|
+
return (`[ObjectUI] ElementDataSource: the ${where} declares \`limit: ${shown}\`, `
|
|
216
|
+
+ 'which is not a positive integer. A row cap must be a positive integer '
|
|
217
|
+
+ '(the spec declares this binding’s `limit` positive), so the binding’s cap '
|
|
218
|
+
+ 'was treated as not authored and ignored, exactly as if the binding declared '
|
|
219
|
+
+ 'no `limit`: the cap comes from the next source that declares a usable one, '
|
|
220
|
+
+ 'or else from the consumer’s own default.');
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* The diagnostic half of {@link savedViewLimit} and {@link bindingLimit}.
|
|
224
|
+
* `null` means "nothing to say".
|
|
225
|
+
*
|
|
226
|
+
* ## Which operand
|
|
227
|
+
*
|
|
228
|
+
* `operand` picks the refusal to describe; it defaults to `'view'`, the one
|
|
229
|
+
* this builder described before objectui#10016. Each operand gets its own
|
|
230
|
+
* sentence, and each names its operand, so the two refusals stay
|
|
231
|
+
* distinguishable when both fire. They do fire together when the binding AND
|
|
232
|
+
* the view each carry a refused cap: two declarations, one message each.
|
|
233
|
+
*
|
|
234
|
+
* `binding` is the binding as authored. The view's sentence needs it too: it
|
|
235
|
+
* says the consumer falls back to its own default, and that is only true when
|
|
236
|
+
* the binding supplied no usable cap. A usable binding cap is used whatever the
|
|
237
|
+
* view carries, so a refused view cap under one changed nothing and is not
|
|
238
|
+
* reported. That condition lives HERE, once, rather than at each caller,
|
|
239
|
+
* because every caller needs it and two copies could drift.
|
|
240
|
+
*
|
|
241
|
+
* ## Why a BUILDER here, and not a warning from the composer
|
|
242
|
+
*
|
|
243
|
+
* This is the shape {@link elementDataSourceViewNotFoundMessage} already
|
|
244
|
+
* established in this module, for the reason its doc gives: built here so every
|
|
245
|
+
* caller reports the same defect the same way. It is followed rather than
|
|
246
|
+
* re-decided because the alternative is ruled out mechanically —
|
|
247
|
+
* {@link composeElementDataSource} is PURE and the render path calls it from a
|
|
248
|
+
* `useMemo`, so a warning emitted inside it would fire during render and fire
|
|
249
|
+
* again on every re-render. The repaired relay one layer up emits from an
|
|
250
|
+
* effect for exactly that reason; a pure function has no effect to emit from,
|
|
251
|
+
* so it hands the caller the words instead.
|
|
252
|
+
*
|
|
253
|
+
* ## Why the message has to exist at all
|
|
254
|
+
*
|
|
255
|
+
* Dropping alone would be a SILENT change on the renderer path: today the
|
|
256
|
+
* refused value travels as far as a block whose own guard reports it once, and
|
|
257
|
+
* after this repair that block receives nothing and correctly says nothing —
|
|
258
|
+
* an absent key is not a mistake. So the repair would remove the only place the
|
|
259
|
+
* author was being told. The layer that makes the decision is the layer that
|
|
260
|
+
* reports it.
|
|
261
|
+
*
|
|
262
|
+
* ⛔ NOT a second guard: the predicate lives once, in {@link isUsableRowLimit},
|
|
263
|
+
* and the view's carrier is read once, by {@link savedViewRawLimit}; this reads
|
|
264
|
+
* both.
|
|
265
|
+
*
|
|
266
|
+
* ⚠️ It speaks only about a cap THIS layer dropped. A non-numeric
|
|
267
|
+
* `pagination.pageSize` never became a limit here, before or after, so there is
|
|
268
|
+
* nothing for this layer to report about it. A non-numeric binding `limit` is
|
|
269
|
+
* different: `??` used to pass it through, so this layer now drops it and says
|
|
270
|
+
* so.
|
|
271
|
+
*/
|
|
272
|
+
export function elementDataSourceRefusedLimitMessage(view, viewName, object, binding, operand = 'view') {
|
|
273
|
+
if (operand === 'binding')
|
|
274
|
+
return refusedBindingLimitMessage(binding, viewName, object);
|
|
275
|
+
if (isUsableRowLimit(binding?.limit))
|
|
276
|
+
return null;
|
|
277
|
+
const raw = savedViewRawLimit(view);
|
|
278
|
+
if (raw === undefined)
|
|
279
|
+
return null;
|
|
280
|
+
if (isUsableRowLimit(raw))
|
|
281
|
+
return null;
|
|
282
|
+
const where = viewName ? `saved view "${viewName}" on ${object}` : `saved view on ${object}`;
|
|
283
|
+
return (`[ObjectUI] ElementDataSource: ${where} declares a row cap of ${String(raw)}, `
|
|
284
|
+
+ 'which is not a positive integer. A row cap must be a positive integer '
|
|
285
|
+
+ '(the spec declares this binding’s `limit` positive, and refuses a zero '
|
|
286
|
+
+ 'or negative `pagination.pageSize`), so the view’s cap was ignored and no '
|
|
287
|
+
+ 'cap was lowered from it — the consuming block uses its own default.');
|
|
288
|
+
}
|
|
141
289
|
/**
|
|
142
290
|
* Read a saved view's render kind. `type` is the spec's key (and what
|
|
143
291
|
* `ObjectView` reads); `viewType` is objectui's legacy spelling, folded by
|
|
@@ -165,7 +313,7 @@ function savedViewColumns(view) {
|
|
|
165
313
|
*
|
|
166
314
|
* Pure — the caller resolves the view (see {@link resolveSavedView}) and owns
|
|
167
315
|
* the "named a view that does not exist" decision. Passing `undefined` /`null`
|
|
168
|
-
* for `view` composes a binding with no view, which is exactly the pre
|
|
316
|
+
* for `view` composes a binding with no view, which is exactly the pre-objectstack-ai/objectstack#5576
|
|
169
317
|
* behaviour for the other four keys.
|
|
170
318
|
*
|
|
171
319
|
* See the module doc for the per-key rule table; `filter` is the only key that
|
|
@@ -194,7 +342,10 @@ export function composeElementDataSource(config, view) {
|
|
|
194
342
|
const sort = config.sort ?? view?.sort;
|
|
195
343
|
if (sort !== undefined)
|
|
196
344
|
composed.sort = sort;
|
|
197
|
-
|
|
345
|
+
// One rule for both operands (objectui#10016): a refused cap is not
|
|
346
|
+
// authored, so a refused binding `limit` yields to the view's cap exactly as
|
|
347
|
+
// an absent one does.
|
|
348
|
+
const limit = bindingLimit(config) ?? savedViewLimit(view);
|
|
198
349
|
if (limit !== undefined)
|
|
199
350
|
composed.limit = limit;
|
|
200
351
|
const viewType = savedViewType(view);
|
|
@@ -207,10 +358,149 @@ export function composeElementDataSource(config, view) {
|
|
|
207
358
|
* have. Built here so the render path and `ViewDataProvider` report the same
|
|
208
359
|
* defect the same way, and so the known-view list (the thing that actually gets
|
|
209
360
|
* an author unstuck) is never omitted by one caller.
|
|
361
|
+
*
|
|
362
|
+
* ## Why the empty case may not say "this object has no saved views"
|
|
363
|
+
*
|
|
364
|
+
* An EMPTY `knownViews` reaches this function from two different worlds, and
|
|
365
|
+
* this function cannot tell them apart:
|
|
366
|
+
*
|
|
367
|
+
* 1. the saved views were read and there are none;
|
|
368
|
+
* 2. the read never successfully happened.
|
|
369
|
+
*
|
|
370
|
+
* World 2 is not hypothetical and not a bug to be fixed upstream: the shipped
|
|
371
|
+
* `ObjectStackAdapter.listViews` contract degrades EVERY failure — refused,
|
|
372
|
+
* offline, malformed — to `[]` on the RESOLVED path (deliberate, and objectui#8151
|
|
373
|
+
* keeps it), so a broken read arrives at `useElementDataSource` as a successful
|
|
374
|
+
* empty answer. The hook's own discrimination catches a REJECTION, which is a
|
|
375
|
+
* shape that contract never produces, so nothing separates the two worlds by the
|
|
376
|
+
* time the count lands here.
|
|
377
|
+
*
|
|
378
|
+
* Framework decision objectstack#13906 decision 1 option A — *a thing that could
|
|
379
|
+
* not be READ is not a thing that is ABSENT* — therefore binds this branch: it
|
|
380
|
+
* may only assert what is true in BOTH worlds. It names the possibilities and
|
|
381
|
+
* commits to neither, because committing is exactly the claim nobody established.
|
|
382
|
+
*
|
|
383
|
+
* ⛔ Do not "restore" the shorter sentence by inferring failure from emptiness in
|
|
384
|
+
* either direction — emptiness is what both worlds produce, so it can never tell
|
|
385
|
+
* them apart. Saying more than this needs the failure FACT plumbed in from the
|
|
386
|
+
* adapter (objectui#8151's surface), not a better guess here.
|
|
210
387
|
*/
|
|
211
388
|
export function elementDataSourceViewNotFoundMessage(object, view, knownViews) {
|
|
212
389
|
const known = knownViews.length
|
|
213
390
|
? `Known views: ${[...knownViews].sort().join(', ')}.`
|
|
214
|
-
: '
|
|
391
|
+
: 'No saved views are known for this object. It may have none, or they could not be read.';
|
|
215
392
|
return `dataSource.view "${view}" was not found on object "${object}". ${known}`;
|
|
216
393
|
}
|
|
394
|
+
/* ------------------------------------------------------------------ *
|
|
395
|
+
* The DECLARATION half — one copy, next to the semantics (objectui#6678)
|
|
396
|
+
* ------------------------------------------------------------------ */
|
|
397
|
+
/**
|
|
398
|
+
* The spec key this module resolves, spelled once.
|
|
399
|
+
*
|
|
400
|
+
* Every consumer that needs the NAME (the registry injection, its gates, the
|
|
401
|
+
* pins) reads it from here rather than repeating the literal, so "which key is
|
|
402
|
+
* this?" has exactly one answer in the tree.
|
|
403
|
+
*/
|
|
404
|
+
export const ELEMENT_DATA_SOURCE_KEY = 'dataSource';
|
|
405
|
+
/**
|
|
406
|
+
* The authoring-surface declaration of {@link ELEMENT_DATA_SOURCE_KEY} — the one
|
|
407
|
+
* copy, emitted into every registration that wraps the runtime gate.
|
|
408
|
+
*
|
|
409
|
+
* ## Why it lives here and is injected rather than written per block
|
|
410
|
+
*
|
|
411
|
+
* `PageComponentSchema.dataSource` is READ by `ElementDataSourceGate` in
|
|
412
|
+
* `@object-ui/react` on behalf of every object-bound block that wraps itself in
|
|
413
|
+
* it — nine of them at the time of writing. It was declared by NONE: `validateTree`
|
|
414
|
+
* skips `BASE_PROPS` and otherwise looks a prop up in the component's `inputs`,
|
|
415
|
+
* and `dataSource` was in neither. So the html tier reported the one spelling
|
|
416
|
+
* that resolves a saved view — the only one that works — with the identical
|
|
417
|
+
* `unknown-prop` warning it gives the spellings that do nothing, on the tier
|
|
418
|
+
* meant to accept AI-authored pages, where the diagnostic IS the contract
|
|
419
|
+
* (objectui#6678, the reporter of objectui#6598 gave up on exactly this).
|
|
420
|
+
*
|
|
421
|
+
* The maintainer ruling of 2026-08-29 took option B **in the injection form**:
|
|
422
|
+
* emitted mechanically at the wrapping seam, so a block declares the key from
|
|
423
|
+
* the same place that reads it. Nine hand-kept copies is the shape that ruling
|
|
424
|
+
* refused — they drift, and a tenth block would simply forget. Adding the key to
|
|
425
|
+
* `sdui-parser`'s `BASE_PROPS` (option A) was refused too: that set mirrors
|
|
426
|
+
* `BaseSchema`, and silencing `dataSource` on blocks that do NOT read it
|
|
427
|
+
* (`flex`, `card`) would make the diagnostic lie in the other direction.
|
|
428
|
+
*
|
|
429
|
+
* ## Why `object`, and not a bare `'object'` kind
|
|
430
|
+
*
|
|
431
|
+
* The `binding: 'object'` marker is what tells a consumer this input names an
|
|
432
|
+
* OBJECT — `validateTree` records it as a binding site, and the designer offers
|
|
433
|
+
* an object picker rather than a free-text blob. The `type` stays the coarse
|
|
434
|
+
* `'object'` kind because the value is a record; the two words are unrelated and
|
|
435
|
+
* both are correct here.
|
|
436
|
+
*
|
|
437
|
+
* ## Typed as the framework's injected input (`9e37d9b39`)
|
|
438
|
+
*
|
|
439
|
+
* `binding` is not a `ComponentInput` member. The maintainer ruling of
|
|
440
|
+
* 2026-09-07 answered the card's product question — may an ordinary
|
|
441
|
+
* registration declare a binding input? — with no, so the ONE writer of the
|
|
442
|
+
* key is this constant, typed by `InjectedComponentInput` from
|
|
443
|
+
* `@object-ui/types`: a `ComponentInput` plus the marker. The hand-written
|
|
444
|
+
* inline type literal that used to sit here was the tell that the key had no
|
|
445
|
+
* authored home, and the splice in `Registry.register` reached the `inputs`
|
|
446
|
+
* array through an `as ComponentMeta` cast. Both are gone: the shape is now
|
|
447
|
+
* checked here and at the splice, and a registration that writes `binding`
|
|
448
|
+
* itself is an excess-property `tsc` error.
|
|
449
|
+
*/
|
|
450
|
+
export const ELEMENT_DATA_SOURCE_INPUT = {
|
|
451
|
+
name: ELEMENT_DATA_SOURCE_KEY,
|
|
452
|
+
type: 'object',
|
|
453
|
+
binding: 'object',
|
|
454
|
+
description: 'Per-element data binding: { object, view, filter, sort, limit }. Overrides the ' +
|
|
455
|
+
'page-level object context for this block; `view` names a saved view of `object`, ' +
|
|
456
|
+
'and `filter` is ANDed with the view’s own rather than replacing it.',
|
|
457
|
+
};
|
|
458
|
+
/**
|
|
459
|
+
* The renderers that wrap the runtime gate.
|
|
460
|
+
*
|
|
461
|
+
* A `WeakSet` rather than a property on the component: marking must not mutate a
|
|
462
|
+
* `React.forwardRef` exotic object or show up when a test snapshots a
|
|
463
|
+
* registration, and an unregistered renderer must stay collectable.
|
|
464
|
+
*/
|
|
465
|
+
const elementDataSourceBlocks = new WeakSet();
|
|
466
|
+
/**
|
|
467
|
+
* Declare that `renderer` wraps `ElementDataSourceGate`, so its registrations
|
|
468
|
+
* publish {@link ELEMENT_DATA_SOURCE_INPUT}.
|
|
469
|
+
*
|
|
470
|
+
* This is the SEAM, and it is deliberately the only way in: `Registry.register`
|
|
471
|
+
* injects the declaration for exactly the renderers marked here, so the key is
|
|
472
|
+
* published by whatever consumes the gate and by nothing else — which is what
|
|
473
|
+
* keeps the `flex` / `card` direction of the ruling true.
|
|
474
|
+
* `scripts/check-element-data-source-declaration.mjs` fails any source that
|
|
475
|
+
* consumes the gate without passing through it, so a new block cannot forget.
|
|
476
|
+
*
|
|
477
|
+
* ## Two import paths, ONE name and ONE function
|
|
478
|
+
*
|
|
479
|
+
* `@object-ui/react` re-exports this beside `ElementDataSourceGate` so the seam is
|
|
480
|
+
* findable next to the thing it is about. That export is for DISCOVERABILITY:
|
|
481
|
+
* every CALL SITE imports from here, and
|
|
482
|
+
* `scripts/check-element-data-source-declaration.mjs` enforces it.
|
|
483
|
+
*
|
|
484
|
+
* The rule is measured, not stylistic. A registration runs at MODULE SCOPE, and
|
|
485
|
+
* `element:record_picker`'s registration in `@object-ui/components` is the
|
|
486
|
+
* worked example. 101 suites in this repo partially
|
|
487
|
+
* mock `@object-ui/react` by hand-listing the exports they return, and a
|
|
488
|
+
* module-scope read of a name those lists do not carry throws at COLLECTION
|
|
489
|
+
* time — the importing test file fails before it runs a single assertion.
|
|
490
|
+
* Measured: 17 files, all four CI shards, zero failed assertions among them.
|
|
491
|
+
* Nothing mocks `@object-ui/core`, and `@object-ui/components` already imports
|
|
492
|
+
* `ComponentRegistry` from it at module scope, so this path adds no coupling
|
|
493
|
+
* that was not already there.
|
|
494
|
+
*/
|
|
495
|
+
export function elementDataSourceBlock(renderer) {
|
|
496
|
+
if (renderer && (typeof renderer === 'object' || typeof renderer === 'function')) {
|
|
497
|
+
elementDataSourceBlocks.add(renderer);
|
|
498
|
+
}
|
|
499
|
+
return renderer;
|
|
500
|
+
}
|
|
501
|
+
/** Whether `renderer` was marked by {@link elementDataSourceBlock}. */
|
|
502
|
+
export function isElementDataSourceBlock(renderer) {
|
|
503
|
+
return (!!renderer
|
|
504
|
+
&& (typeof renderer === 'object' || typeof renderer === 'function')
|
|
505
|
+
&& elementDataSourceBlocks.has(renderer));
|
|
506
|
+
}
|
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @object-ui/core - DataScope Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Resolution of the data a view or a page element reads: the spec's
|
|
5
|
+
* `ViewData` union (`ViewDataProvider`) and the per-element
|
|
6
|
+
* `ElementDataSource` binding.
|
|
7
|
+
*
|
|
8
|
+
* Row-level security is not evaluated here. The platform declares it once, as
|
|
9
|
+
* the CEL predicate of a `@objectstack/spec` row-level security policy, and
|
|
10
|
+
* enforces it on the server; objectui#7750 retired the client-side row-level
|
|
11
|
+
* filter evaluator this module used to export.
|
|
6
12
|
*
|
|
7
13
|
* @module data-scope
|
|
8
14
|
* @packageDocumentation
|
|
9
15
|
*/
|
|
10
|
-
export { DataScopeManager, defaultDataScopeManager, type RowLevelFilter, type DataScopeConfig, } from './DataScopeManager.js';
|
|
11
16
|
export { ViewDataProvider, type ViewDataConfig, type DataFetcher, type ResolvedData, } from './ViewDataProvider.js';
|
|
12
|
-
export { collectSavedViews, composeElementDataSource, elementDataSourceViewNotFoundMessage, isElementDataSourceConfig, resolveSavedView, type ComposedElementDataSource, type ElementDataSourceConfig, type ElementDataSourceSort, type ElementSavedView, } from './element-data-source.js';
|
|
17
|
+
export { collectSavedViews, composeElementDataSource, ELEMENT_DATA_SOURCE_INPUT, ELEMENT_DATA_SOURCE_KEY, elementDataSourceBlock, elementDataSourceRefusedLimitMessage, elementDataSourceViewNotFoundMessage, isElementDataSourceBlock, isElementDataSourceConfig, resolveSavedView, type ComposedElementDataSource, type ElementDataSourceConfig, type ElementDataSourceSort, type ElementSavedView, } from './element-data-source.js';
|
package/dist/data-scope/index.js
CHANGED
|
@@ -1,12 +1,17 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @object-ui/core - DataScope Module
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Resolution of the data a view or a page element reads: the spec's
|
|
5
|
+
* `ViewData` union (`ViewDataProvider`) and the per-element
|
|
6
|
+
* `ElementDataSource` binding.
|
|
7
|
+
*
|
|
8
|
+
* Row-level security is not evaluated here. The platform declares it once, as
|
|
9
|
+
* the CEL predicate of a `@objectstack/spec` row-level security policy, and
|
|
10
|
+
* enforces it on the server; objectui#7750 retired the client-side row-level
|
|
11
|
+
* filter evaluator this module used to export.
|
|
6
12
|
*
|
|
7
13
|
* @module data-scope
|
|
8
14
|
* @packageDocumentation
|
|
9
15
|
*/
|
|
10
|
-
export { DataScopeManager, defaultDataScopeManager, } from './DataScopeManager.js';
|
|
11
16
|
export { ViewDataProvider, } from './ViewDataProvider.js';
|
|
12
|
-
export { collectSavedViews, composeElementDataSource, elementDataSourceViewNotFoundMessage, isElementDataSourceConfig, resolveSavedView, } from './element-data-source.js';
|
|
17
|
+
export { collectSavedViews, composeElementDataSource, ELEMENT_DATA_SOURCE_INPUT, ELEMENT_DATA_SOURCE_KEY, elementDataSourceBlock, elementDataSourceRefusedLimitMessage, elementDataSourceViewNotFoundMessage, isElementDataSourceBlock, isElementDataSourceConfig, resolveSavedView, } from './element-data-source.js';
|
|
@@ -35,6 +35,47 @@ export interface EvaluationOptions {
|
|
|
35
35
|
* @default true
|
|
36
36
|
*/
|
|
37
37
|
sanitize?: boolean;
|
|
38
|
+
/**
|
|
39
|
+
* Fault passback: called with the failure reason when this evaluation could
|
|
40
|
+
* not be performed, at the moment the evaluator ALREADY knows it faulted.
|
|
41
|
+
*
|
|
42
|
+
* ## Why a passback and not a second evaluation (objectui#6038)
|
|
43
|
+
*
|
|
44
|
+
* The only fault-detection channel this class used to offer a fail-soft
|
|
45
|
+
* caller was `throwOnError`, and on the CEL branch `evaluateCelCondition`
|
|
46
|
+
* implements that by evaluating TWICE (once with each fallback — a value
|
|
47
|
+
* that tracks the fallback both times is a fault). A caller that wants to
|
|
48
|
+
* *observe* a fault while keeping the fail-soft verdict therefore had to pay
|
|
49
|
+
* for a second engine call per predicate per node per render. That price is
|
|
50
|
+
* exactly why the node gate in `SchemaRenderer` bought its diagnostic with a
|
|
51
|
+
* `__DEV__` gate and shipped production silent.
|
|
52
|
+
*
|
|
53
|
+
* This option costs nothing: every fault site below is already inside a
|
|
54
|
+
* `catch`, or already holds the engine's own failure reason. The verdict is
|
|
55
|
+
* untouched on every path — `onFault` is invoked for its side effect and its
|
|
56
|
+
* return value is ignored.
|
|
57
|
+
*
|
|
58
|
+
* ## Supplying it TRANSFERS reporting to the caller
|
|
59
|
+
*
|
|
60
|
+
* The built-in `console.warn`s on these paths are suppressed while it is
|
|
61
|
+
* set, so one fault stays one line — the caller's, which can name the node
|
|
62
|
+
* the predicate belongs to. This mirrors, one layer up, the contract
|
|
63
|
+
* `FieldPredicateDiagnostic` (`fieldRules.ts`) already documents for the
|
|
64
|
+
* canonical CEL engine: `warn: false` plus an `onFault` passback, so
|
|
65
|
+
* silencing the generic line never discards the description of *why* the
|
|
66
|
+
* predicate failed. On the CEL branch this option is forwarded to exactly
|
|
67
|
+
* that seam rather than reimplementing it.
|
|
68
|
+
*
|
|
69
|
+
* Independent of {@link throwOnError}, which converts a fault into a throw
|
|
70
|
+
* and is the fail-CLOSED contract; this one keeps the historical fail-soft
|
|
71
|
+
* answer and merely says so out loud. `throwOnError` still wins where both
|
|
72
|
+
* are set: the throw happens first and is the caller's own signal.
|
|
73
|
+
*
|
|
74
|
+
* Must not throw — it is invoked outside the evaluation guard, so an
|
|
75
|
+
* exception here propagates to the caller rather than being reported as an
|
|
76
|
+
* evaluation fault.
|
|
77
|
+
*/
|
|
78
|
+
onFault?: (reason: string) => void;
|
|
38
79
|
}
|
|
39
80
|
/**
|
|
40
81
|
* Expression evaluator for dynamic UI expressions
|
|
@@ -96,6 +137,51 @@ export declare class ExpressionEvaluator {
|
|
|
96
137
|
* syntax) throws; a genuine `false` never throws.
|
|
97
138
|
*/
|
|
98
139
|
private evaluateCelCondition;
|
|
140
|
+
/**
|
|
141
|
+
* Answer a BLANK gate predicate — the ONE diagnosed guard of
|
|
142
|
+
* {@link evaluateCondition}, on both of its routes (objectui#8069 put it on
|
|
143
|
+
* the `{ dialect: 'cel' }` route; objectui#11262 routes the legacy path's
|
|
144
|
+
* blank here too, so the two are one report rather than two).
|
|
145
|
+
*
|
|
146
|
+
* The verdict is `true` — no predicate → visible/enabled, exactly as before
|
|
147
|
+
* (objectui#3850 / #3960's verdict) — in EVERY mode, `throwOnError` included,
|
|
148
|
+
* since the author wrote nothing that could fault. What it is not is SILENT
|
|
149
|
+
* (ADR-0137 D4: a blank gate predicate is "diagnosed, never a silent
|
|
150
|
+
* `true`"). The report is `evalFieldPredicate`'s own `[blank]` one — the
|
|
151
|
+
* channel every other predicate fault already uses — so a caller that passed
|
|
152
|
+
* `onFault` receives it there (and prints its own, node-named line), and
|
|
153
|
+
* every other caller gets the deduped built-in warning. No engine call is
|
|
154
|
+
* made: a blank predicate never reaches the engine.
|
|
155
|
+
*
|
|
156
|
+
* The locator names a CEL gate on both routes: a blank has no syntax to put
|
|
157
|
+
* it in either dialect, and a bare-string predicate is CEL by the spec's
|
|
158
|
+
* contract. One locator is also what keeps `''` and `{ dialect: 'cel',
|
|
159
|
+
* source: '' }` on one dedupe key.
|
|
160
|
+
*/
|
|
161
|
+
private answerBlankGate;
|
|
162
|
+
/**
|
|
163
|
+
* Answer a gate that is DECLARED but cannot be evaluated (objectui#11358) —
|
|
164
|
+
* see `isUnevaluablePredicate` (`./unevaluablePredicate.ts`) for the shapes.
|
|
165
|
+
*
|
|
166
|
+
* It is a fault, not a blank: {@link answerBlankGate} answers `true` in every
|
|
167
|
+
* mode because a blank says nothing, while this value says "there is a gate"
|
|
168
|
+
* and the client cannot read it. So the modes split exactly as they do for a
|
|
169
|
+
* predicate that faults with text in it:
|
|
170
|
+
*
|
|
171
|
+
* - `throwOnError` → THROW. The caller opted into fail-closed semantics,
|
|
172
|
+
* and its catch both hides / disables and reports, naming the control —
|
|
173
|
+
* the same contract `evaluateCelCondition` keeps (no warning AND a throw
|
|
174
|
+
* for one fault, objectstack-ai/objectstack#5149).
|
|
175
|
+
* - otherwise → reported once through `evalFieldPredicate`'s own report
|
|
176
|
+
* (the `[unevaluable]` reason, beside `[blank]`), or handed to the
|
|
177
|
+
* caller's `onFault`, and answered with the fail-soft `true`. On a
|
|
178
|
+
* `disabled` / `hidden` leg that `true` is the CLOSED side (greyed out /
|
|
179
|
+
* hidden), on `visible` / `enabled` / `condition` the open one — each
|
|
180
|
+
* key's existing fault direction, unchanged.
|
|
181
|
+
*
|
|
182
|
+
* No engine call is made: there is no `source` to hand it.
|
|
183
|
+
*/
|
|
184
|
+
private answerUnevaluableGate;
|
|
99
185
|
/**
|
|
100
186
|
* Update the context with new data
|
|
101
187
|
*/
|