@object-ui/core 17.5.0 → 17.7.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 +7404 -0
- package/README.md +127 -26
- package/dist/actions/ActionEngine.d.ts +5 -3
- package/dist/actions/ActionEngine.js +14 -10
- package/dist/actions/ActionRunner.d.ts +363 -30
- package/dist/actions/ActionRunner.js +544 -58
- package/dist/actions/TransactionManager.d.ts +7 -2
- package/dist/actions/actionKeys.d.ts +75 -13
- package/dist/actions/actionKeys.js +131 -16
- package/dist/actions/actionResponse.js +3 -3
- package/dist/actions/index.d.ts +2 -0
- package/dist/actions/index.js +2 -0
- package/dist/actions/recordDelete.d.ts +118 -0
- package/dist/actions/recordDelete.js +112 -0
- package/dist/actions/recordIdParam.d.ts +77 -0
- package/dist/actions/recordIdParam.js +37 -0
- package/dist/actions/serverActionHandler.d.ts +1 -1
- package/dist/actions/serverActionHandler.js +1 -1
- 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/builder/schema-builder.d.ts +38 -81
- package/dist/builder/schema-builder.js +33 -152
- package/dist/data-scope/ViewDataProvider.d.ts +1 -1
- package/dist/data-scope/ViewDataProvider.js +21 -1
- 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 +128 -1
- package/dist/evaluator/ExpressionEvaluator.js +226 -13
- package/dist/evaluator/FormulaFunctions.d.ts +0 -10
- package/dist/evaluator/FormulaFunctions.js +166 -27
- package/dist/evaluator/SafeExpressionParser.js +0 -4
- package/dist/evaluator/declaredPredicate.d.ts +93 -9
- package/dist/evaluator/declaredPredicate.js +118 -17
- package/dist/evaluator/fieldRules.d.ts +107 -4
- package/dist/evaluator/fieldRules.js +231 -35
- package/dist/evaluator/index.d.ts +2 -0
- package/dist/evaluator/index.js +2 -0
- package/dist/evaluator/listConditional.d.ts +125 -9
- package/dist/evaluator/listConditional.js +167 -26
- package/dist/evaluator/optionRules.d.ts +126 -0
- package/dist/evaluator/optionRules.js +141 -4
- package/dist/evaluator/predicateInput.d.ts +15 -4
- package/dist/evaluator/predicateInput.js +35 -2
- package/dist/evaluator/rowPredicateCanon.d.ts +56 -0
- package/dist/evaluator/rowPredicateCanon.js +158 -0
- package/dist/evaluator/subjectPermissions.d.ts +76 -0
- package/dist/evaluator/subjectPermissions.js +44 -0
- package/dist/evaluator/unevaluablePredicate.d.ts +57 -0
- package/dist/evaluator/unevaluablePredicate.js +70 -0
- package/dist/index.d.ts +18 -0
- package/dist/index.js +97 -2
- package/dist/protocols/index.d.ts +0 -1
- package/dist/protocols/index.js +9 -1
- package/dist/registry/Registry.d.ts +397 -48
- package/dist/registry/Registry.js +263 -11
- 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/theme/index.d.ts +1 -1
- package/dist/theme/index.js +1 -1
- package/dist/types/index.d.ts +92 -13
- 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 +188 -0
- package/dist/utils/chart-presentation.js +345 -0
- package/dist/utils/chart-series.d.ts +271 -31
- package/dist/utils/chart-series.js +478 -55
- package/dist/utils/column-identity.d.ts +43 -0
- package/dist/utils/column-identity.js +47 -1
- 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 +407 -52
- package/dist/utils/date-display.d.ts +354 -0
- package/dist/utils/date-display.js +463 -0
- package/dist/utils/date-macros.js +7 -0
- package/dist/utils/debug.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 +171 -11
- package/dist/utils/expand-fields.js +171 -11
- package/dist/utils/extract-records.d.ts +65 -5
- package/dist/utils/extract-records.js +65 -8
- package/dist/utils/filter-converter.d.ts +152 -4
- package/dist/utils/filter-converter.js +1092 -22
- package/dist/utils/filter-tokens.d.ts +49 -5
- package/dist/utils/filter-tokens.js +105 -34
- package/dist/utils/freeze-schema.d.ts +38 -1
- package/dist/utils/freeze-schema.js +10 -0
- package/dist/utils/grouping-fields.d.ts +61 -0
- package/dist/utils/grouping-fields.js +84 -0
- package/dist/utils/humanize-label.d.ts +60 -0
- package/dist/utils/humanize-label.js +62 -0
- package/dist/utils/managedBy.d.ts +30 -5
- 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 +131 -1
- package/dist/utils/normalize-list-view.js +248 -6
- package/dist/utils/number-display.d.ts +70 -17
- 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 +62 -4
- package/dist/utils/predicate-fields.js +169 -4
- 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/retired-field-types.d.ts +90 -0
- package/dist/utils/retired-field-types.js +124 -0
- package/dist/utils/sort-query.d.ts +128 -26
- 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/unmaterialized-fields.d.ts +52 -0
- package/dist/utils/unmaterialized-fields.js +57 -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 +9 -4
- package/dist/validation/index.js +9 -4
- package/dist/validation/schema-validator.d.ts +1 -1
- package/dist/validation/schema-validator.js +305 -82
- package/dist/validation/server-owned-value.d.ts +62 -0
- package/dist/validation/server-owned-value.js +99 -0
- package/dist/validation/validators/object-validation-engine.d.ts +1 -1
- package/dist/validation/validators/object-validation-engine.js +14 -5
- package/package.json +8 -9
- package/dist/__benchmarks__/core.bench.d.ts +0 -8
- package/dist/__benchmarks__/core.bench.js +0 -53
- 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,6 +5,34 @@
|
|
|
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
|
+
* Is the predicate TEXT blank — in EITHER spelling? (objectui#3960)
|
|
10
|
+
*
|
|
11
|
+
* `' '` and `{ dialect: 'cel', source: ' ' }` are the same author mistake
|
|
12
|
+
* written two ways, and {@link toPredicateInput} folds neither: it wraps a
|
|
13
|
+
* whitespace-only string into `'${ }'`, and it only folds an envelope whose
|
|
14
|
+
* `source` is exactly `''`. So blankness cannot be derived from the normalizer's
|
|
15
|
+
* answer and has to be stated once, here, for both spellings — trimming one and
|
|
16
|
+
* not the other is the asymmetry objectui#3960 measured (`disabled` greyed out,
|
|
17
|
+
* `ActionRunner` refused to execute, for a predicate that says nothing).
|
|
18
|
+
*
|
|
19
|
+
* This is not a fourth dialect of "empty": it is the SAME rule core's evaluation
|
|
20
|
+
* entries already apply on the value side — `evaluateCondition` on both of its
|
|
21
|
+
* routes (which ask THIS function: the CEL route since objectui#8069, the
|
|
22
|
+
* legacy path since objectui#11262), `evalRowPredicate` (`listConditional.ts`,
|
|
23
|
+
* whose blank reaches `evalFieldPredicate`, which asks it too) — brought to the
|
|
24
|
+
* one place that answers "is there a condition at all?", so the two halves
|
|
25
|
+
* cannot disagree about the same blank.
|
|
26
|
+
*
|
|
27
|
+
* Exported since objectui#8069 for its second consumer, `evalFieldPredicate`
|
|
28
|
+
* (`evaluator/fieldRules.ts`), which is the entry this docblock's list did NOT
|
|
29
|
+
* name because it did not apply the rule: it trimmed the STRING spelling only,
|
|
30
|
+
* so `{ dialect: 'cel', source: ' ' }` went to the engine and came back as a
|
|
31
|
+
* parse fault while `' '` returned the caller's fallback in silence. Reusing
|
|
32
|
+
* this definition rather than writing a fourth `trim()` is the whole point of
|
|
33
|
+
* the paragraph above.
|
|
34
|
+
*/
|
|
35
|
+
export declare function isBlankPredicateText(value: unknown): boolean;
|
|
8
36
|
/**
|
|
9
37
|
* Is a predicate gate DECLARED on this value — i.e. after normalization, is
|
|
10
38
|
* there still a CONDITION for {@link ExpressionEvaluator.evaluateCondition} to
|
|
@@ -38,18 +66,55 @@
|
|
|
38
66
|
* Neither can be read off the normalizer's answer, so both are named here —
|
|
39
67
|
* see {@link isBlankPredicateText} for why this is the layer that says it.
|
|
40
68
|
* Core's other predicate entries already treat both as blank:
|
|
41
|
-
* `evaluateCondition` (`
|
|
42
|
-
*
|
|
43
|
-
* (`evaluator/listConditional.ts`,
|
|
69
|
+
* `evaluateCondition` (`isBlankPredicateText`, then `true` — diagnosed on
|
|
70
|
+
* the CEL route since objectui#8069 and on the legacy path since
|
|
71
|
+
* objectui#11262) and `evalRowPredicate` (`evaluator/listConditional.ts`,
|
|
72
|
+
* the caller's fallback, through `evalFieldPredicate`'s `[blank]` report
|
|
73
|
+
* since objectui#11262).
|
|
44
74
|
* - `{ dialect, source: '' }` — the empty ENVELOPE. This is not an exotic
|
|
45
75
|
* spelling: `@objectstack/spec`'s `ExpressionInputSchema` normalizes every
|
|
46
76
|
* authored predicate into an envelope, so "author left the predicate empty"
|
|
47
77
|
* compiles to exactly this, which makes it the likeliest empty shape in real
|
|
48
78
|
* metadata (objectui#3850).
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
79
|
+
*
|
|
80
|
+
* The three BLANK shapes above (`''`, whitespace-only text, and an envelope
|
|
81
|
+
* whose `source` is blank) are still folded to "not declared" — that is the
|
|
82
|
+
* verdict — but no longer in silence: each is reported once (objectui#8069,
|
|
83
|
+
* ADR-0137 D4), see {@link reportBlankGate}. `null` / `undefined` (no key) is
|
|
84
|
+
* not blank TEXT and stays silent: nothing was declared there to report.
|
|
85
|
+
*
|
|
86
|
+
* ## What is DECLARED although nothing in it can be evaluated (objectui#11358)
|
|
87
|
+
*
|
|
88
|
+
* A value that is present but is not a predicate the client can evaluate — an
|
|
89
|
+
* envelope with no string `source` (the `ast`-only `{ dialect: 'cel', ast }` an
|
|
90
|
+
* unmirrored authoring door admits), a number (`0`), an object with no `source`
|
|
91
|
+
* (`{}`), an array — IS a declared gate. Triage's ruling on objectui#11358:
|
|
92
|
+
* "declared and faulting", "reported once per predicate", and the action
|
|
93
|
+
* "hides". It used to be the fifth "nothing to evaluate" shape here, answered
|
|
94
|
+
* "not declared" in silence, so a bulk action gated that way ran over every
|
|
95
|
+
* selected record and the toolbars and row menu showed it to everyone.
|
|
96
|
+
*
|
|
97
|
+
* This function's CODE did not change for it: the normalizer did.
|
|
98
|
+
* {@link toPredicateInput} no longer folds such a value into `undefined`; it
|
|
99
|
+
* returns a `cel` envelope with no `source`, so `toPredicateInput(x) !==
|
|
100
|
+
* undefined` — the line below — answers "declared", and the derivation this
|
|
101
|
+
* definition rests on still holds with no second list. The state is told apart
|
|
102
|
+
* in one place, `isUnevaluablePredicate` (`./unevaluablePredicate.ts`).
|
|
103
|
+
*
|
|
104
|
+
* What a reader then DOES with it is the evaluation step's, not this
|
|
105
|
+
* function's: `ExpressionEvaluator.evaluateCondition` and `evalFieldPredicate`
|
|
106
|
+
* treat it as a FAULT, so each reader answers with the fail direction its key
|
|
107
|
+
* already has for a predicate that cannot be evaluated, and reports it there,
|
|
108
|
+
* once — through `evalFieldPredicate`'s report with the `[unevaluable]` reason,
|
|
109
|
+
* or through the caller's own fault report. That is why this function reports
|
|
110
|
+
* nothing for it: a declared gate always goes on to an evaluation, and two
|
|
111
|
+
* reports for one fault is the noise objectstack-ai/objectstack#5149 removed.
|
|
112
|
+
* On every action `visible` leg that direction is CLOSED (objectui#11212), on
|
|
113
|
+
* every `disabled` leg too (objectui#11242), and the hide-polarity `hidden` /
|
|
114
|
+
* `hiddenOn` legs of `SchemaRenderer` answer "hidden". The keys whose fault
|
|
115
|
+
* direction is OPEN keep it — a `condition` still lets the action run, a
|
|
116
|
+
* legacy `enabled` leaves the control enabled, an action param's `visible`
|
|
117
|
+
* still shows the param — now diagnosed rather than silent.
|
|
53
118
|
*
|
|
54
119
|
* A declared-and-`false` gate is DECLARED (`toPredicateInput` returns the
|
|
55
120
|
* boolean unchanged): `disabled: false` / `visible: false` are verdicts, and
|
|
@@ -113,7 +178,26 @@
|
|
|
113
178
|
* an empty predicate made the node VANISH (objectui#3955), and
|
|
114
179
|
* `ActionEngine.getActionsForLocation`'s `visible` filter, which folded some
|
|
115
180
|
* empty spellings by hand and coerced the rest with `Boolean(raw)`, so
|
|
116
|
-
* `visible: 0` hid an action the renderers showed (objectui#3957).
|
|
117
|
-
*
|
|
181
|
+
* `visible: 0` hid an action the renderers showed (objectui#3957).
|
|
182
|
+
*
|
|
183
|
+
* The last one joined with objectui#11322: plugin-grid's `hasVisibilityGate`,
|
|
184
|
+
* on the grid's selection bar, asks it through the renderer-side name
|
|
185
|
+
* `hasDeclaredVisibilityGate`. It decides whether a bulk button whose `visible`
|
|
186
|
+
* admits no record is hidden, and `partitionBulkRows` asks it before handing a
|
|
187
|
+
* bulk def's `visible` to `partitionRowsByPredicate`. It had kept the old
|
|
188
|
+
* `!= null && !== ''` scope after every other member of the family moved here,
|
|
189
|
+
* so a whitespace-only `visible` counted as declared on that bar, failed closed
|
|
190
|
+
* for every record, and hid an action the row menu and toolbars showed.
|
|
191
|
+
*
|
|
192
|
+
* Nothing in the repo now asks "is a gate declared?" anywhere but here for
|
|
193
|
+
* the keys this definition serves. What stays outside is a different family,
|
|
194
|
+
* not a twin: the field-rule `*When` keys (ADR-0137) decide it by rules of
|
|
195
|
+
* their own. Examples are the built-in Edit / Delete row item's
|
|
196
|
+
* `visibleWhen != null` (`isBuiltinRowActionVisible`), and the opening test of
|
|
197
|
+
* the shared partitioner `partitionRowsByPredicate` (`null` / `undefined` /
|
|
198
|
+
* `''`), which is the answer its built-in Delete `visibleWhen` callers get. The
|
|
199
|
+
* action family asks here before it calls that partitioner.
|
|
200
|
+
* ⚠️ Nothing re-derives this paragraph: it was read off a source search when
|
|
201
|
+
* objectui#11322 landed, and no test or gate repeats that search.
|
|
118
202
|
*/
|
|
119
203
|
export declare function hasDeclaredPredicate(value: unknown): boolean;
|
|
@@ -5,7 +5,11 @@
|
|
|
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
|
-
import { toPredicateInput } from './predicateInput';
|
|
8
|
+
import { toPredicateInput } from './predicateInput.js';
|
|
9
|
+
// A cycle with `fieldRules.ts`, which imports `isBlankPredicateText` from here.
|
|
10
|
+
// Benign by construction: each side reads the other only inside a function
|
|
11
|
+
// body, never while its module is being evaluated.
|
|
12
|
+
import { evalFieldPredicate } from './fieldRules.js';
|
|
9
13
|
/**
|
|
10
14
|
* Is the predicate TEXT blank — in EITHER spelling? (objectui#3960)
|
|
11
15
|
*
|
|
@@ -18,13 +22,22 @@ import { toPredicateInput } from './predicateInput';
|
|
|
18
22
|
* `ActionRunner` refused to execute, for a predicate that says nothing).
|
|
19
23
|
*
|
|
20
24
|
* This is not a fourth dialect of "empty": it is the SAME rule core's evaluation
|
|
21
|
-
* entries already apply on the value side — `evaluateCondition`
|
|
22
|
-
*
|
|
23
|
-
*
|
|
24
|
-
*
|
|
25
|
-
*
|
|
25
|
+
* entries already apply on the value side — `evaluateCondition` on both of its
|
|
26
|
+
* routes (which ask THIS function: the CEL route since objectui#8069, the
|
|
27
|
+
* legacy path since objectui#11262), `evalRowPredicate` (`listConditional.ts`,
|
|
28
|
+
* whose blank reaches `evalFieldPredicate`, which asks it too) — brought to the
|
|
29
|
+
* one place that answers "is there a condition at all?", so the two halves
|
|
30
|
+
* cannot disagree about the same blank.
|
|
31
|
+
*
|
|
32
|
+
* Exported since objectui#8069 for its second consumer, `evalFieldPredicate`
|
|
33
|
+
* (`evaluator/fieldRules.ts`), which is the entry this docblock's list did NOT
|
|
34
|
+
* name because it did not apply the rule: it trimmed the STRING spelling only,
|
|
35
|
+
* so `{ dialect: 'cel', source: ' ' }` went to the engine and came back as a
|
|
36
|
+
* parse fault while `' '` returned the caller's fallback in silence. Reusing
|
|
37
|
+
* this definition rather than writing a fourth `trim()` is the whole point of
|
|
38
|
+
* the paragraph above.
|
|
26
39
|
*/
|
|
27
|
-
function isBlankPredicateText(value) {
|
|
40
|
+
export function isBlankPredicateText(value) {
|
|
28
41
|
if (typeof value === 'string')
|
|
29
42
|
return value.trim() === '';
|
|
30
43
|
if (value !== null && typeof value === 'object') {
|
|
@@ -67,18 +80,55 @@ function isBlankPredicateText(value) {
|
|
|
67
80
|
* Neither can be read off the normalizer's answer, so both are named here —
|
|
68
81
|
* see {@link isBlankPredicateText} for why this is the layer that says it.
|
|
69
82
|
* Core's other predicate entries already treat both as blank:
|
|
70
|
-
* `evaluateCondition` (`
|
|
71
|
-
*
|
|
72
|
-
* (`evaluator/listConditional.ts`,
|
|
83
|
+
* `evaluateCondition` (`isBlankPredicateText`, then `true` — diagnosed on
|
|
84
|
+
* the CEL route since objectui#8069 and on the legacy path since
|
|
85
|
+
* objectui#11262) and `evalRowPredicate` (`evaluator/listConditional.ts`,
|
|
86
|
+
* the caller's fallback, through `evalFieldPredicate`'s `[blank]` report
|
|
87
|
+
* since objectui#11262).
|
|
73
88
|
* - `{ dialect, source: '' }` — the empty ENVELOPE. This is not an exotic
|
|
74
89
|
* spelling: `@objectstack/spec`'s `ExpressionInputSchema` normalizes every
|
|
75
90
|
* authored predicate into an envelope, so "author left the predicate empty"
|
|
76
91
|
* compiles to exactly this, which makes it the likeliest empty shape in real
|
|
77
92
|
* metadata (objectui#3850).
|
|
78
|
-
*
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
-
*
|
|
93
|
+
*
|
|
94
|
+
* The three BLANK shapes above (`''`, whitespace-only text, and an envelope
|
|
95
|
+
* whose `source` is blank) are still folded to "not declared" — that is the
|
|
96
|
+
* verdict — but no longer in silence: each is reported once (objectui#8069,
|
|
97
|
+
* ADR-0137 D4), see {@link reportBlankGate}. `null` / `undefined` (no key) is
|
|
98
|
+
* not blank TEXT and stays silent: nothing was declared there to report.
|
|
99
|
+
*
|
|
100
|
+
* ## What is DECLARED although nothing in it can be evaluated (objectui#11358)
|
|
101
|
+
*
|
|
102
|
+
* A value that is present but is not a predicate the client can evaluate — an
|
|
103
|
+
* envelope with no string `source` (the `ast`-only `{ dialect: 'cel', ast }` an
|
|
104
|
+
* unmirrored authoring door admits), a number (`0`), an object with no `source`
|
|
105
|
+
* (`{}`), an array — IS a declared gate. Triage's ruling on objectui#11358:
|
|
106
|
+
* "declared and faulting", "reported once per predicate", and the action
|
|
107
|
+
* "hides". It used to be the fifth "nothing to evaluate" shape here, answered
|
|
108
|
+
* "not declared" in silence, so a bulk action gated that way ran over every
|
|
109
|
+
* selected record and the toolbars and row menu showed it to everyone.
|
|
110
|
+
*
|
|
111
|
+
* This function's CODE did not change for it: the normalizer did.
|
|
112
|
+
* {@link toPredicateInput} no longer folds such a value into `undefined`; it
|
|
113
|
+
* returns a `cel` envelope with no `source`, so `toPredicateInput(x) !==
|
|
114
|
+
* undefined` — the line below — answers "declared", and the derivation this
|
|
115
|
+
* definition rests on still holds with no second list. The state is told apart
|
|
116
|
+
* in one place, `isUnevaluablePredicate` (`./unevaluablePredicate.ts`).
|
|
117
|
+
*
|
|
118
|
+
* What a reader then DOES with it is the evaluation step's, not this
|
|
119
|
+
* function's: `ExpressionEvaluator.evaluateCondition` and `evalFieldPredicate`
|
|
120
|
+
* treat it as a FAULT, so each reader answers with the fail direction its key
|
|
121
|
+
* already has for a predicate that cannot be evaluated, and reports it there,
|
|
122
|
+
* once — through `evalFieldPredicate`'s report with the `[unevaluable]` reason,
|
|
123
|
+
* or through the caller's own fault report. That is why this function reports
|
|
124
|
+
* nothing for it: a declared gate always goes on to an evaluation, and two
|
|
125
|
+
* reports for one fault is the noise objectstack-ai/objectstack#5149 removed.
|
|
126
|
+
* On every action `visible` leg that direction is CLOSED (objectui#11212), on
|
|
127
|
+
* every `disabled` leg too (objectui#11242), and the hide-polarity `hidden` /
|
|
128
|
+
* `hiddenOn` legs of `SchemaRenderer` answer "hidden". The keys whose fault
|
|
129
|
+
* direction is OPEN keep it — a `condition` still lets the action run, a
|
|
130
|
+
* legacy `enabled` leaves the control enabled, an action param's `visible`
|
|
131
|
+
* still shows the param — now diagnosed rather than silent.
|
|
82
132
|
*
|
|
83
133
|
* A declared-and-`false` gate is DECLARED (`toPredicateInput` returns the
|
|
84
134
|
* boolean unchanged): `disabled: false` / `visible: false` are verdicts, and
|
|
@@ -142,11 +192,62 @@ function isBlankPredicateText(value) {
|
|
|
142
192
|
* an empty predicate made the node VANISH (objectui#3955), and
|
|
143
193
|
* `ActionEngine.getActionsForLocation`'s `visible` filter, which folded some
|
|
144
194
|
* empty spellings by hand and coerced the rest with `Boolean(raw)`, so
|
|
145
|
-
* `visible: 0` hid an action the renderers showed (objectui#3957).
|
|
146
|
-
*
|
|
195
|
+
* `visible: 0` hid an action the renderers showed (objectui#3957).
|
|
196
|
+
*
|
|
197
|
+
* The last one joined with objectui#11322: plugin-grid's `hasVisibilityGate`,
|
|
198
|
+
* on the grid's selection bar, asks it through the renderer-side name
|
|
199
|
+
* `hasDeclaredVisibilityGate`. It decides whether a bulk button whose `visible`
|
|
200
|
+
* admits no record is hidden, and `partitionBulkRows` asks it before handing a
|
|
201
|
+
* bulk def's `visible` to `partitionRowsByPredicate`. It had kept the old
|
|
202
|
+
* `!= null && !== ''` scope after every other member of the family moved here,
|
|
203
|
+
* so a whitespace-only `visible` counted as declared on that bar, failed closed
|
|
204
|
+
* for every record, and hid an action the row menu and toolbars showed.
|
|
205
|
+
*
|
|
206
|
+
* Nothing in the repo now asks "is a gate declared?" anywhere but here for
|
|
207
|
+
* the keys this definition serves. What stays outside is a different family,
|
|
208
|
+
* not a twin: the field-rule `*When` keys (ADR-0137) decide it by rules of
|
|
209
|
+
* their own. Examples are the built-in Edit / Delete row item's
|
|
210
|
+
* `visibleWhen != null` (`isBuiltinRowActionVisible`), and the opening test of
|
|
211
|
+
* the shared partitioner `partitionRowsByPredicate` (`null` / `undefined` /
|
|
212
|
+
* `''`), which is the answer its built-in Delete `visibleWhen` callers get. The
|
|
213
|
+
* action family asks here before it calls that partitioner.
|
|
214
|
+
* ⚠️ Nothing re-derives this paragraph: it was read off a source search when
|
|
215
|
+
* objectui#11322 landed, and no test or gate repeats that search.
|
|
147
216
|
*/
|
|
148
217
|
export function hasDeclaredPredicate(value) {
|
|
149
|
-
if (isBlankPredicateText(value))
|
|
218
|
+
if (isBlankPredicateText(value)) {
|
|
219
|
+
reportBlankGate(value);
|
|
150
220
|
return false;
|
|
221
|
+
}
|
|
151
222
|
return toPredicateInput(value) !== undefined;
|
|
152
223
|
}
|
|
224
|
+
/**
|
|
225
|
+
* Say out loud that a DECLARED gate was blank — the one side effect
|
|
226
|
+
* {@link hasDeclaredPredicate} has (objectui#8069).
|
|
227
|
+
*
|
|
228
|
+
* The fold above is objectui#3850 / #3960's ruled verdict and it stands: a
|
|
229
|
+
* blank gate is "no gate". What ADR-0137 D4 removed is the SILENCE of it — "a
|
|
230
|
+
* gate predicate that is blank or faulting is diagnosed, never a silent
|
|
231
|
+
* `true`" — and this fold is where a blank `visible` / `hidden` / `enabled` /
|
|
232
|
+
* `disabled` / `condition` stopped before it could reach any evaluator that
|
|
233
|
+
* might have said so.
|
|
234
|
+
*
|
|
235
|
+
* Reported through `evalFieldPredicate`'s own `[blank]` report — the channel
|
|
236
|
+
* every other predicate fault already uses, with its once-per-(text, locator)
|
|
237
|
+
* dedupe — and not through a warner of its own. It makes no engine call: a
|
|
238
|
+
* blank predicate never reaches the engine. The `false` it is handed is this
|
|
239
|
+
* function's answer ("not declared"); nothing reads it back.
|
|
240
|
+
*
|
|
241
|
+
* ⚠️ The locator is FIXED, because this question is key-neutral and receives
|
|
242
|
+
* nothing that names the node. So the dedupe is per blank SPELLING across the
|
|
243
|
+
* app: `''`, `' '` and a blank envelope each warn once, and a second node
|
|
244
|
+
* with the same blank spelling does not warn again. That is weaker than the
|
|
245
|
+
* field-rule path, which joins the field's locator to a blank's key, and it is
|
|
246
|
+
* the price of diagnosing at the one definition rather than at each of its
|
|
247
|
+
* callers.
|
|
248
|
+
*/
|
|
249
|
+
function reportBlankGate(value) {
|
|
250
|
+
evalFieldPredicate(value, {}, false, undefined, undefined, {
|
|
251
|
+
context: 'a declared gate, read as no gate',
|
|
252
|
+
});
|
|
253
|
+
}
|
|
@@ -44,12 +44,54 @@ export interface FieldPredicateDiagnostic {
|
|
|
44
44
|
/**
|
|
45
45
|
* Evaluate a field-rule CEL predicate against a record.
|
|
46
46
|
*
|
|
47
|
+
* ## `fallback` is a per-CALL-SITE policy, not a default this helper owns
|
|
48
|
+
*
|
|
49
|
+
* The parameter is required and carries no default value, so every call site
|
|
50
|
+
* states a direction of its own — and the directions in this repo do not
|
|
51
|
+
* agree. Five distinct fault policies share this one helper today, which is
|
|
52
|
+
* readable nowhere but here (objectui#8069):
|
|
53
|
+
*
|
|
54
|
+
* 1. **Fixed permissive, paired with an equal "no rule" literal.**
|
|
55
|
+
* {@link resolveFieldRuleState} (`true` / `false` / `false`) and
|
|
56
|
+
* `resolveVisibleOptions` (`evaluator/optionRules.ts`, `true`). A fault
|
|
57
|
+
* produces the permissive verdict, indistinguishable from the verdict for
|
|
58
|
+
* "the author wrote no rule" — see the `…_FAULTED` / `…_ABSENT` note below.
|
|
59
|
+
* 2. **Fixed permissive, unguarded — ONE literal answers absent *and*
|
|
60
|
+
* faulted.** Every visibility call site outside core: the form renderer
|
|
61
|
+
* (`components/renderers/form/form.tsx`), console's `FormPage`, app-shell's
|
|
62
|
+
* `ScreenView`, `plugin-form`'s `WizardForm`. All of them pass `true`, and
|
|
63
|
+
* none has a separate absent branch at all.
|
|
64
|
+
* 3. **Caller-parameterised.** `evalRowPredicate`'s single-eval fast route
|
|
65
|
+
* (`evaluator/listConditional.ts`) forwards `opts.fallback`, so the
|
|
66
|
+
* direction is the mounting surface's to state.
|
|
67
|
+
* 4. **Divergence probe → fault FLAG.** `evalCel`
|
|
68
|
+
* (`evaluator/listConditional.ts`) calls this helper once per direction with
|
|
69
|
+
* `warn: false` + `onFault`: a verdict that tracks the fallback in BOTH runs
|
|
70
|
+
* is a fault, and the caller emits its own labelled warning and returns its
|
|
71
|
+
* own fallback.
|
|
72
|
+
* 5. **Divergence probe → THROW.** `ExpressionEvaluator.evaluateCelCondition`
|
|
73
|
+
* under `throwOnError` runs the same two-call trick and converts the
|
|
74
|
+
* disagreement into `throw new Error('CEL predicate failed to evaluate: …')`.
|
|
75
|
+
*
|
|
76
|
+
* ⚠️ The last two policies exist **because** `fallback` is free to specify: they
|
|
77
|
+
* detect a fault by disagreeing with themselves. Fixing a direction *inside*
|
|
78
|
+
* this helper would remove the mechanism they are built on, which is why
|
|
79
|
+
* ADR-0137 D5 keeps `fallback` free and declares the direction at the
|
|
80
|
+
* field-rule and gate layer instead.
|
|
81
|
+
*
|
|
47
82
|
* @param pred The `visibleWhen` / `readonlyWhen` / `requiredWhen` predicate.
|
|
48
83
|
* @param record The live form values (overlays prior persisted record).
|
|
49
|
-
* @param fallback Value to return when the predicate is
|
|
50
|
-
*
|
|
51
|
-
*
|
|
52
|
-
*
|
|
84
|
+
* @param fallback Value to return when the predicate is ABSENT (`null` /
|
|
85
|
+
* `undefined`), and — separately — the value returned when a
|
|
86
|
+
* present predicate cannot be evaluated. ⚠️ Those are two
|
|
87
|
+
* questions this one parameter answers with one value; a
|
|
88
|
+
* caller that wants different answers must branch before the
|
|
89
|
+
* call, as {@link resolveFieldRuleState} does. The historic
|
|
90
|
+
* advice is to pick the *safe* default (`false` for
|
|
91
|
+
* readonly/required — don't lock/block on error; `true` for
|
|
92
|
+
* visibility — don't hide on error). ADR-0137 kept those
|
|
93
|
+
* directions for RENDER (D3) and put the answer to a broken
|
|
94
|
+
* field rule at SUBMIT (D2) — see {@link FieldRuleFaults}.
|
|
53
95
|
* @param previous The prior persisted record, if any (for `previous.*` refs).
|
|
54
96
|
* @param scope Extra top-level scope variables bound alongside `record` —
|
|
55
97
|
* e.g. `{ parent }` so an inline line-item cell can reference
|
|
@@ -61,6 +103,45 @@ export interface FieldPredicateDiagnostic {
|
|
|
61
103
|
* is unaffected either way.
|
|
62
104
|
*/
|
|
63
105
|
export declare function evalFieldPredicate(pred: FieldRulePredicate | undefined | null, record: Record<string, unknown>, fallback: boolean, previous?: Record<string, unknown>, scope?: Record<string, unknown>, diagnostic?: FieldPredicateDiagnostic): boolean;
|
|
106
|
+
/**
|
|
107
|
+
* Which of {@link resolveFieldRuleState}'s rules could NOT be evaluated, and
|
|
108
|
+
* why — keyed by rule, valued by the reason the one-time warning prints after
|
|
109
|
+
* `Reason:` (`"[kind] message"`). A key is present only for a rule that ran and
|
|
110
|
+
* faulted (objectui#8069).
|
|
111
|
+
*
|
|
112
|
+
* This is the report a SUBMIT path reads — ADR-0137 D2, "at submit time, a
|
|
113
|
+
* field-rule predicate that cannot be evaluated refuses the write and names the
|
|
114
|
+
* field and the rule" — so that the refusal is decided by the very evaluation
|
|
115
|
+
* that drew the verdict, never by a second one with its own record assembly.
|
|
116
|
+
* Which rules a submit path refuses on is that path's ruling, not this
|
|
117
|
+
* function's: under objectui#8069's ruling (Q1 = B, one judge per rule) the
|
|
118
|
+
* client refuses `visibleWhen` only, because no server evaluates it, and leaves
|
|
119
|
+
* `readonlyWhen` / `requiredWhen` to the server's own D2 refusal. The other two
|
|
120
|
+
* keys are reported all the same, so the report does not encode that ruling.
|
|
121
|
+
*
|
|
122
|
+
* A BLANK predicate IS in it, as the `[blank]` reason. ADR-0137 makes a
|
|
123
|
+
* declared-but-blank field rule a third state, not a spelling of "no rule":
|
|
124
|
+
* "A blank predicate takes this path too, wherever one is already stored — D1
|
|
125
|
+
* keeps new ones from being authored, and D2 is what a stored one meets" (D2),
|
|
126
|
+
* and its Alternatives refuse "blank means no rule" for this triad by name. So
|
|
127
|
+
* a stored blank `visibleWhen` is refused at submit like any other fault. The
|
|
128
|
+
* trap that would otherwise make — an authorable value that no submit can ever
|
|
129
|
+
* pass — is closed at AUTHORING: the triad's form wire refuses a blank at parse
|
|
130
|
+
* (`FieldRulePredicateWireSchema` in `@object-ui/types`' `form.zod.ts`, D1).
|
|
131
|
+
* The render verdict of a blank rule is unchanged (D3: the permissive one).
|
|
132
|
+
* A blank GATE is a different thing: `hasDeclaredPredicate` still folds it to
|
|
133
|
+
* "no gate" and only diagnoses it (D4) — it never reaches this function.
|
|
134
|
+
*
|
|
135
|
+
* Deliberately NOT in it: a rule the verdict did not need. `readonlyWhen` under
|
|
136
|
+
* a static `readonly: true`, and `requiredWhen` under `serverOwnedValue` or a
|
|
137
|
+
* static `required: true`, are short-circuited and never run, so they cannot
|
|
138
|
+
* fault.
|
|
139
|
+
*/
|
|
140
|
+
export interface FieldRuleFaults {
|
|
141
|
+
visibleWhen?: string;
|
|
142
|
+
readonlyWhen?: string;
|
|
143
|
+
requiredWhen?: string;
|
|
144
|
+
}
|
|
64
145
|
/**
|
|
65
146
|
* Resolve the effective `{ visible, readonly, required }` state for a field
|
|
66
147
|
* given its conditional rules and the live record. Each `*When` rule, when
|
|
@@ -68,10 +149,30 @@ export declare function evalFieldPredicate(pred: FieldRulePredicate | undefined
|
|
|
68
149
|
* `false` predicate result for required/readonly — but `visibleWhen` is
|
|
69
150
|
* authoritative when present (so a field can be conditionally shown/hidden).
|
|
70
151
|
*
|
|
152
|
+
* ## `statics.serverOwnedValue` — the one thing that outranks BOTH
|
|
153
|
+
*
|
|
154
|
+
* A CREATE form leaves a producer-owned control empty on purpose and omits the
|
|
155
|
+
* key, so the server resolves the declared runtime default (#4069). Required-
|
|
156
|
+
* ness is then not the client's question at all, and this is the single place
|
|
157
|
+
* that answers it: `required` resolves to `false` whatever `statics.required`
|
|
158
|
+
* says and whatever `requiredWhen` evaluates to.
|
|
159
|
+
*
|
|
160
|
+
* Both spellings had to land HERE, not in a gate a layer up. Since
|
|
161
|
+
* objectui#4201 the submit-time check and the required marker read one live
|
|
162
|
+
* verdict — this function's — so a suppression applied anywhere else would
|
|
163
|
+
* show a field without an asterisk and still refuse the submit, which is the
|
|
164
|
+
* exact two-layer disagreement #4201 removed. #4085 is the conditional half:
|
|
165
|
+
* `requiredWhen` resolving TRUE on a create form re-required a control the
|
|
166
|
+
* renderer deliberately left empty, with nothing the user could type to
|
|
167
|
+
* unblock it. See `isServerOwnedValue` in `../validation/server-owned-value.js`
|
|
168
|
+
* for who computes the fact and why the mode is the caller's to state.
|
|
169
|
+
*
|
|
71
170
|
* @param fieldContext Optional locator for failure warnings — e.g.
|
|
72
171
|
* `"field 'amount'"`. The warning then reads
|
|
73
172
|
* `visibleWhen of field 'amount' …`; without it, the rule
|
|
74
173
|
* kind alone is reported.
|
|
174
|
+
* @returns The three verdicts, plus `faults` — see {@link FieldRuleFaults} for
|
|
175
|
+
* what a submit path reads from it and what it leaves out.
|
|
75
176
|
*/
|
|
76
177
|
export declare function resolveFieldRuleState(rules: {
|
|
77
178
|
visibleWhen?: FieldRulePredicate;
|
|
@@ -80,8 +181,10 @@ export declare function resolveFieldRuleState(rules: {
|
|
|
80
181
|
}, record: Record<string, unknown>, statics: {
|
|
81
182
|
required?: boolean;
|
|
82
183
|
readonly?: boolean;
|
|
184
|
+
serverOwnedValue?: boolean;
|
|
83
185
|
}, previous?: Record<string, unknown>, scope?: Record<string, unknown>, fieldContext?: string): {
|
|
84
186
|
visible: boolean;
|
|
85
187
|
readonly: boolean;
|
|
86
188
|
required: boolean;
|
|
189
|
+
faults: FieldRuleFaults;
|
|
87
190
|
};
|