@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,7 +5,81 @@
|
|
|
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 { ELEMENT_DATA_SOURCE_INPUT, isElementDataSourceBlock, } from '../data-scope/element-data-source.js';
|
|
8
9
|
import { PUBLIC_BLOCKS } from './public-blocks.js';
|
|
10
|
+
import { HTML_TIER_INTRINSICS } from './html-tier-intrinsics.js';
|
|
11
|
+
/**
|
|
12
|
+
* The full type a pending lazy stub DECLARES for a bare key.
|
|
13
|
+
*
|
|
14
|
+
* `registerLazy` computes `namespace:type` and stores the stub under both that
|
|
15
|
+
* key and the bare one; nothing on the entry itself records which bare key it
|
|
16
|
+
* claims, so the claim has to be recomputed from the entry's own meta. Spelled
|
|
17
|
+
* once here because both doors' collision guards need it and a second copy
|
|
18
|
+
* would be a second thing to keep in step with `registerLazy`'s own line.
|
|
19
|
+
*/
|
|
20
|
+
function lazyStubFullType(type, entry) {
|
|
21
|
+
return entry.meta?.namespace ? `${entry.meta.namespace}:${type}` : type;
|
|
22
|
+
}
|
|
23
|
+
/**
|
|
24
|
+
* Emit the spec's `dataSource` input for a registration whose renderer wraps
|
|
25
|
+
* `ElementDataSourceGate` (objectui#6678).
|
|
26
|
+
*
|
|
27
|
+
* ## The one place, and why it is this one
|
|
28
|
+
*
|
|
29
|
+
* The maintainer ruling of 2026-08-29 adopted option B **in the injection
|
|
30
|
+
* form**: the declaration is emitted mechanically at the wrapping seam so every
|
|
31
|
+
* gate-wrapping registration declares the key from the same place that reads it
|
|
32
|
+
* — one mechanism rather than nine hand-kept copies across nine packages, which
|
|
33
|
+
* drift and which a tenth block would simply forget. `register()` is where every
|
|
34
|
+
* one of those registrations passes through, so it is where the emission lands;
|
|
35
|
+
* the DECLARATION itself is `ELEMENT_DATA_SOURCE_INPUT`, which lives beside the
|
|
36
|
+
* binding's own semantics in `data-scope/element-data-source.ts`.
|
|
37
|
+
*
|
|
38
|
+
* ## What it must NOT do, which is half the ruling
|
|
39
|
+
*
|
|
40
|
+
* Widening this to every registration is option A wearing a different hat: it
|
|
41
|
+
* would silence `dataSource` on `flex` and `card`, which do not read it, and the
|
|
42
|
+
* diagnostic would lie in the other direction instead of the one it lied in
|
|
43
|
+
* before. So the condition is the marker and nothing else — no heuristic over
|
|
44
|
+
* `objectName`, no "looks object-bound".
|
|
45
|
+
*
|
|
46
|
+
* ## Idempotent, and it never overwrites
|
|
47
|
+
*
|
|
48
|
+
* A registration that declares `dataSource` ITSELF keeps its own entry: the
|
|
49
|
+
* emission fills a gap, it does not own the key. (Nothing declares it today —
|
|
50
|
+
* that is the defect — but a block whose binding needs a narrower description
|
|
51
|
+
* later must be able to say so without fighting this function.) Re-registering
|
|
52
|
+
* the same component, which the registry allows and tests do constantly, is
|
|
53
|
+
* likewise a no-op rather than a growing `inputs` array.
|
|
54
|
+
*
|
|
55
|
+
* ## Typed end to end — the cast is gone (`9e37d9b39`)
|
|
56
|
+
*
|
|
57
|
+
* The spliced element is an `InjectedComponentInput` (`@object-ui/types`): a
|
|
58
|
+
* `ComponentInput` plus the framework-set `binding` marker, so it is a plain
|
|
59
|
+
* subtype of the array's element type and the return value type-checks as a
|
|
60
|
+
* `ComponentMeta` with no assertion. This used to read `as ComponentMeta`,
|
|
61
|
+
* because `ELEMENT_DATA_SOURCE_INPUT` carried a hand-written inline type and
|
|
62
|
+
* `binding` had no declared home — and a cast at the one place the key is
|
|
63
|
+
* written is exactly what would have hidden any later drift between the
|
|
64
|
+
* constant and the type. The absence is held by `eslint.config.js`, which
|
|
65
|
+
* scopes `@typescript-eslint/consistent-type-assertions` with
|
|
66
|
+
* `assertionStyle: 'never'` to THIS FILE (objectui#8316) — an AST rule,
|
|
67
|
+
* because `tsc --noEmit` stays at exit 0 with the cast re-added and the
|
|
68
|
+
* source-text pin that used to stand here was green for `<ComponentMeta>{…}`,
|
|
69
|
+
* the same assertion in the other spelling.
|
|
70
|
+
* `packages/types/src/__tests__/injected-component-input-6950.test.ts` still
|
|
71
|
+
* pins the positive half, that the local below is ANNOTATED. Keep it typed: if
|
|
72
|
+
* the shape ever stops fitting, that line is where the compiler should say so.
|
|
73
|
+
*/
|
|
74
|
+
export function withElementDataSourceInput(component, meta) {
|
|
75
|
+
if (!isElementDataSourceBlock(component))
|
|
76
|
+
return meta;
|
|
77
|
+
const inputs = meta?.inputs ?? [];
|
|
78
|
+
if (inputs.some((input) => input?.name === ELEMENT_DATA_SOURCE_INPUT.name))
|
|
79
|
+
return meta;
|
|
80
|
+
const injected = { ...ELEMENT_DATA_SOURCE_INPUT };
|
|
81
|
+
return { ...(meta ?? {}), inputs: [...inputs, injected] };
|
|
82
|
+
}
|
|
9
83
|
export class Registry {
|
|
10
84
|
constructor() {
|
|
11
85
|
Object.defineProperty(this, "components", {
|
|
@@ -65,6 +139,9 @@ export class Registry {
|
|
|
65
139
|
*/
|
|
66
140
|
register(type, component, meta) {
|
|
67
141
|
const fullType = meta?.namespace ? `${meta.namespace}:${type}` : type;
|
|
142
|
+
// The `dataSource` declaration is EMITTED here, not written by the blocks
|
|
143
|
+
// (objectui#6678). See `withElementDataSourceInput`.
|
|
144
|
+
const resolvedMeta = withElementDataSourceInput(component, meta);
|
|
68
145
|
// Warn if registering without namespace (deprecated pattern)
|
|
69
146
|
if (!meta?.namespace) {
|
|
70
147
|
console.warn(`Registering component "${type}" without a namespace is deprecated. ` +
|
|
@@ -74,7 +151,7 @@ export class Registry {
|
|
|
74
151
|
` registry.register('${type}', MyComponent);\n\n` +
|
|
75
152
|
` // After:\n` +
|
|
76
153
|
` registry.register('${type}', MyComponent, { namespace: 'my-plugin' });\n\n` +
|
|
77
|
-
` See: https://
|
|
154
|
+
` See: https://www.objectui.org/docs/guide/plugin-development#namespaced-registration`);
|
|
78
155
|
}
|
|
79
156
|
if (this.components.has(fullType)) {
|
|
80
157
|
// console.warn(`Component type "${fullType}" is already registered. Overwriting.`);
|
|
@@ -82,7 +159,7 @@ export class Registry {
|
|
|
82
159
|
this.components.set(fullType, {
|
|
83
160
|
type: fullType,
|
|
84
161
|
component,
|
|
85
|
-
...
|
|
162
|
+
...resolvedMeta
|
|
86
163
|
});
|
|
87
164
|
// Also register without namespace for backward compatibility
|
|
88
165
|
// This allows "button" to work even when registered as "ui:button"
|
|
@@ -101,24 +178,94 @@ export class Registry {
|
|
|
101
178
|
`If this is intentional keep going; otherwise register "${fullType}" with ` +
|
|
102
179
|
`{ skipFallback: true } so it doesn't claim the bare "${type}" key.`);
|
|
103
180
|
}
|
|
181
|
+
else if (!existing) {
|
|
182
|
+
// The CROSS-TABLE half of the same guard (objectui#9821), and the half
|
|
183
|
+
// the contest objectui#9533 measured actually went through. The check
|
|
184
|
+
// above reads `components` only, so a bare key held by a pending STUB
|
|
185
|
+
// is invisible to it: the console declared bare `dashboard` for
|
|
186
|
+
// `plugin-dashboard:dashboard` at boot, this door took the same bare key
|
|
187
|
+
// for `view:dashboard` when the chunk landed, and because `components`
|
|
188
|
+
// still held nothing under `dashboard` at that moment, NOTHING warned.
|
|
189
|
+
// Measured, not reasoned: replaying that card's three real claimants
|
|
190
|
+
// against a real registry emitted zero warnings in BOTH orders.
|
|
191
|
+
//
|
|
192
|
+
// ⚠️ The guard has to fire HERE and not only in `registerLazy`, because
|
|
193
|
+
// a contest that is only reported in one registration order is reported
|
|
194
|
+
// in the order this repository does not boot in. The `report-` and
|
|
195
|
+
// `timeline-bare-key-ownership` pins replay both orders for exactly
|
|
196
|
+
// that reason.
|
|
197
|
+
//
|
|
198
|
+
// ⭐ The remedy this warning names CHANGED with objectui#9839, and it
|
|
199
|
+
// changed because the behaviour behind it did. It used to send the
|
|
200
|
+
// author away from `skipFallback: true` — correctly at the time, since
|
|
201
|
+
// this door cleared the bare stub outside the fallback branch, so the
|
|
202
|
+
// opt-out left the bare key resolving to nothing at all. The delete is
|
|
203
|
+
// now inside the branch, so declining the bare key leaves it with its
|
|
204
|
+
// owner and the opt-out settles this contest exactly as it does on the
|
|
205
|
+
// lazy door. Both doors therefore prescribe the same thing now, which
|
|
206
|
+
// `each door prescribes the remedy that is true for it` pins.
|
|
207
|
+
const stub = this.lazyEntries.get(type);
|
|
208
|
+
const stubType = stub ? lazyStubFullType(type, stub) : undefined;
|
|
209
|
+
if (stubType && stubType !== fullType) {
|
|
210
|
+
console.warn(`Component "${type}" bare-name fallback is being overwritten by "${fullType}", ` +
|
|
211
|
+
`which a pending lazy stub already claims for "${stubType}". Which one an ` +
|
|
212
|
+
`authored "${type}" node resolves to depends on whether that chunk has loaded. ` +
|
|
213
|
+
`If this is intentional keep going; otherwise register "${fullType}" with ` +
|
|
214
|
+
`{ skipFallback: true } so it doesn't claim the bare "${type}" key — that ` +
|
|
215
|
+
`opt-out settles it, because the bare "${type}" key is then left with ` +
|
|
216
|
+
`"${stubType}".`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
104
219
|
this.components.set(type, {
|
|
105
220
|
type: fullType, // Keep reference to namespaced type
|
|
106
221
|
component,
|
|
107
|
-
...
|
|
222
|
+
...resolvedMeta
|
|
108
223
|
});
|
|
224
|
+
// The bare key now resolves to THIS registration, so the bare stub is
|
|
225
|
+
// ours to clear. It is cleared here — inside the branch, under the same
|
|
226
|
+
// predicate that took the key — and deliberately not below (objectui#9839).
|
|
227
|
+
this.lazyEntries.delete(type);
|
|
109
228
|
}
|
|
110
|
-
// A real component is now available — clear
|
|
111
|
-
// don't keep holding the loader
|
|
229
|
+
// A real component is now available — clear the stub for the key this
|
|
230
|
+
// registration actually claimed, so we don't keep holding the loader
|
|
231
|
+
// reference, and notify subscribers.
|
|
232
|
+
//
|
|
233
|
+
// ⭐ `fullType` only. With no namespace `fullType === type`, so a bare
|
|
234
|
+
// registration still clears the bare stub — it claimed the bare key. What
|
|
235
|
+
// this line must NOT do is clear a bare stub the registration DECLINED:
|
|
236
|
+
// `skipFallback: true` skips the branch above, so `components` is never
|
|
237
|
+
// written under the bare key, and deleting the stub here took the bare key
|
|
238
|
+
// away from its owner and gave it to nobody — the stub was gone and this
|
|
239
|
+
// registration had refused to replace it (objectui#9839). A registration
|
|
240
|
+
// that opts out of the bare key opts out of clearing it too.
|
|
112
241
|
this.lazyEntries.delete(fullType);
|
|
113
|
-
this.lazyEntries.delete(type);
|
|
114
242
|
this.notify();
|
|
115
243
|
}
|
|
116
244
|
/**
|
|
117
245
|
* Remove a previously registered component. Mirrors {@link register} by
|
|
118
246
|
* clearing both the namespaced key and the bare-name fallback (when the
|
|
119
|
-
* fallback still points at this registration), plus any matching lazy stub
|
|
247
|
+
* fallback still points at this registration), plus any matching lazy stub —
|
|
248
|
+
* where "matching" means the same thing on both tables: a stub that still
|
|
249
|
+
* belongs to THIS registration (objectui#9839).
|
|
120
250
|
* Notifies subscribers only when something was actually removed.
|
|
121
251
|
*
|
|
252
|
+
* ⭐ Why "matching" cannot mean "a stub under either key". This function
|
|
253
|
+
* already answers that question for the bare `components` key and answers it
|
|
254
|
+
* "ownership" — it will not drop bare `dashboard` when it resolves to
|
|
255
|
+
* `plugin-dashboard:dashboard`. Reading the next line as an unconditional
|
|
256
|
+
* delete makes the SAME call, on the SAME bare key, with the SAME owner,
|
|
257
|
+
* take the opposite decision purely because the owner happens to be sitting
|
|
258
|
+
* in the other table at that instant — and which table it is sitting in is
|
|
259
|
+
* exactly the "has the chunk loaded yet" race that objectui#9533 and
|
|
260
|
+
* objectui#9821 are about. A policy that flips on chunk-load timing is not a
|
|
261
|
+
* policy, so the stub gets the ownership test too.
|
|
262
|
+
*
|
|
263
|
+
* ⚠️ The BARE form (`unregister(type)` with no namespace) is unchanged and
|
|
264
|
+
* is still the unconditional one, on both tables: `fullType === type` there,
|
|
265
|
+
* so the deletes below address the bare key directly. That is the "force"
|
|
266
|
+
* form teardown sites pair with the namespaced call, and taking it away
|
|
267
|
+
* would break them.
|
|
268
|
+
*
|
|
122
269
|
* Mainly used by tests that install a stub renderer and need to restore the
|
|
123
270
|
* prior registry state on teardown, since the registry is a process-level
|
|
124
271
|
* singleton shared across test files.
|
|
@@ -133,7 +280,13 @@ export class Registry {
|
|
|
133
280
|
this.components.delete(type);
|
|
134
281
|
}
|
|
135
282
|
this.lazyEntries.delete(fullType);
|
|
136
|
-
|
|
283
|
+
// The same ownership test, on the other table.
|
|
284
|
+
if (namespace) {
|
|
285
|
+
const bareStub = this.lazyEntries.get(type);
|
|
286
|
+
if (bareStub && lazyStubFullType(type, bareStub) === fullType) {
|
|
287
|
+
this.lazyEntries.delete(type);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
137
290
|
if (removed)
|
|
138
291
|
this.notify();
|
|
139
292
|
return removed;
|
|
@@ -155,6 +308,46 @@ export class Registry {
|
|
|
155
308
|
const entry = { loader, meta };
|
|
156
309
|
this.lazyEntries.set(fullType, entry);
|
|
157
310
|
if (meta?.namespace && !meta?.skipFallback) {
|
|
311
|
+
// Collision guard (objectui#9821). This door took the same bare-name
|
|
312
|
+
// fallback branch as `register` with no check at all, so a stub could
|
|
313
|
+
// take the bare key off another declaration in total silence — and the
|
|
314
|
+
// silence is why the class stayed invisible: two of the three claimants
|
|
315
|
+
// in the contest objectui#9533 filed came in through here.
|
|
316
|
+
//
|
|
317
|
+
// ⭐ The predicate keys on the FULL TYPE and reads BOTH tables, and both
|
|
318
|
+
// halves of that were decided by the census rather than chosen:
|
|
319
|
+
//
|
|
320
|
+
// - BOTH tables, because the contention is cross-table. Copying the
|
|
321
|
+
// guard above verbatim would compare `lazyEntries` against itself,
|
|
322
|
+
// and the one contested bare key on this tree is a stub in this table
|
|
323
|
+
// against a loaded registration in the other one. A same-table check
|
|
324
|
+
// would not have caught the card that produced this one.
|
|
325
|
+
// - FULL TYPE and not loader identity, because the ordinary correct
|
|
326
|
+
// shape here is a stub re-declared with a DIFFERENT loader closure
|
|
327
|
+
// for the SAME full type: two console files drive the same plugin
|
|
328
|
+
// set, and nine of this tree's bare keys are registered twice that
|
|
329
|
+
// way. Keying on the loader would warn on all nine, every boot.
|
|
330
|
+
//
|
|
331
|
+
// Census taken on the declared population of this repository (the same
|
|
332
|
+
// one `check-registry-bare-name-collisions.mjs` reads): of 31 bare keys
|
|
333
|
+
// a stub claims, 30 name exactly one full type across both tables — the
|
|
334
|
+
// stub-then-real lifecycle this must stay silent about — and one is a
|
|
335
|
+
// genuine contest.
|
|
336
|
+
const loaded = this.components.get(type);
|
|
337
|
+
const priorStub = loaded ? undefined : this.lazyEntries.get(type);
|
|
338
|
+
const claimedBy = loaded
|
|
339
|
+
? loaded.type
|
|
340
|
+
: priorStub
|
|
341
|
+
? lazyStubFullType(type, priorStub)
|
|
342
|
+
: undefined;
|
|
343
|
+
if (claimedBy && claimedBy !== fullType) {
|
|
344
|
+
console.warn(`Lazy component "${type}" bare-name fallback is being overwritten by "${fullType}", ` +
|
|
345
|
+
`which ${loaded ? 'a loaded registration' : 'another pending stub'} already claims ` +
|
|
346
|
+
`for "${claimedBy}". If this is intentional keep going; otherwise register ` +
|
|
347
|
+
`"${fullType}" with { skipFallback: true } so it doesn't claim the bare "${type}" ` +
|
|
348
|
+
`key — that opt-out settles it, because the stub then claims only ` +
|
|
349
|
+
`"${fullType}".`);
|
|
350
|
+
}
|
|
158
351
|
this.lazyEntries.set(type, entry);
|
|
159
352
|
}
|
|
160
353
|
// Bump the version but do NOT notify: the set of KNOWN types grew, so
|
|
@@ -329,6 +522,47 @@ export class Registry {
|
|
|
329
522
|
const key = namespace ? `${namespace}:${type}` : type;
|
|
330
523
|
return this.components.get(key) ?? this.lazyEntries.get(key)?.meta;
|
|
331
524
|
}
|
|
525
|
+
/**
|
|
526
|
+
* The deprecation `type` declares FOR `surface` — or `undefined` when it
|
|
527
|
+
* declares none there (objectui#6674).
|
|
528
|
+
*
|
|
529
|
+
* ## The question this makes askable
|
|
530
|
+
*
|
|
531
|
+
* "Is this type deprecated?" — which, before the {@link ComponentDeprecation}
|
|
532
|
+
* declaration existed, nothing could ask. The only two statements of a
|
|
533
|
+
* deprecation were a `console.warn` string literal in a renderer and the word
|
|
534
|
+
* "(Deprecated)" inside a human `label`; no gate, test or type can consult
|
|
535
|
+
* either. Both gates that touch component types ask whether a type RESOLVES,
|
|
536
|
+
* and a deprecated type resolves.
|
|
537
|
+
*
|
|
538
|
+
* ## Why the caller must name a surface
|
|
539
|
+
*
|
|
540
|
+
* Because the honest answer differs by surface, and a reader that dropped the
|
|
541
|
+
* distinction would let every caller re-derive it — which is how the same
|
|
542
|
+
* exemption ends up written N times and wrong in N-1 of them. `span` is
|
|
543
|
+
* deprecated for JSON-authored pages and is vocabulary of the `kind:'html'`
|
|
544
|
+
* tier (objectui#4000). Asking `deprecationFor('span', 'html')` therefore
|
|
545
|
+
* correctly answers `undefined` even when the type declares a `'json'`
|
|
546
|
+
* deprecation, while `deprecationFor('div', 'html')` answers the declaration,
|
|
547
|
+
* because `div` names both surfaces (objectui#10757). A gate over html-tier
|
|
548
|
+
* sources gets the right answer for either without knowing the rulings: the
|
|
549
|
+
* console's html compile reads exactly this to decide what it refuses.
|
|
550
|
+
*
|
|
551
|
+
* Returning the DECLARATION rather than a boolean is deliberate: the caller
|
|
552
|
+
* that has to report the finding also needs `replacement` to say what to
|
|
553
|
+
* author instead, and a boolean would send it back to the console string.
|
|
554
|
+
*
|
|
555
|
+
* Resolution is {@link getMeta}'s, so both spellings of a namespaced
|
|
556
|
+
* registration answer alike (`div` and `ui:div`), a `skipFallback` type
|
|
557
|
+
* answers only under its namespaced key, and a pending `registerLazy` stub
|
|
558
|
+
* answers from the meta it was registered with.
|
|
559
|
+
*/
|
|
560
|
+
deprecationFor(type, surface, namespace) {
|
|
561
|
+
const declared = this.getMeta(type, namespace)?.deprecated;
|
|
562
|
+
if (!declared)
|
|
563
|
+
return undefined;
|
|
564
|
+
return declared.surfaces.includes(surface) ? declared : undefined;
|
|
565
|
+
}
|
|
332
566
|
/**
|
|
333
567
|
* Get all registered component configurations.
|
|
334
568
|
*
|
|
@@ -364,9 +598,18 @@ export class Registry {
|
|
|
364
598
|
return { ...entry.meta, type: canonical, lazy: true };
|
|
365
599
|
}
|
|
366
600
|
/**
|
|
367
|
-
* Get the
|
|
368
|
-
*
|
|
369
|
-
*
|
|
601
|
+
* Get the CONTRACT-surface component configs (ADR-0080) — what the published
|
|
602
|
+
* `sdui.manifest.json` serialises. A subset of the full rendering capability
|
|
603
|
+
* returned by {@link getAllConfigs}, made of two tiers:
|
|
604
|
+
*
|
|
605
|
+
* - the curated PUBLIC tier — `PUBLIC_BLOCKS` plus registrations that opted
|
|
606
|
+
* in with `tier: 'public'` — the JSON-surface AI-authoring vocabulary;
|
|
607
|
+
* - the html tier's registered intrinsic elements — `HTML_TIER_INTRINSICS`,
|
|
608
|
+
* each entry stamped `tier: 'html'` (objectui#10735). A `kind:'html'` page
|
|
609
|
+
* may author these tags and the gate that reads the manifest must accept
|
|
610
|
+
* them; they are NOT part of the curated vocabulary, so a consumer that
|
|
611
|
+
* means that vocabulary alone — the `kind:'react'` JSX scope, the block
|
|
612
|
+
* list, a census of curated blocks — filters on the stamp.
|
|
370
613
|
*
|
|
371
614
|
* Includes blocks that are only lazily registered so far; those come back
|
|
372
615
|
* with `lazy: true` and no `component` (see {@link PublicComponentConfig}).
|
|
@@ -398,6 +641,15 @@ export class Registry {
|
|
|
398
641
|
if (entry.meta?.tier === 'public' && !key.includes(':'))
|
|
399
642
|
add(key, this.getContractConfig(key));
|
|
400
643
|
}
|
|
644
|
+
// … and the html tier's registered intrinsic elements, LAST and STAMPED:
|
|
645
|
+
// the dedupe above means a tag on both rosters comes out curated and
|
|
646
|
+
// unstamped, which is why the two rosters are pinned disjoint. The stamp is
|
|
647
|
+
// a projection, never written back onto the registration (objectui#10735).
|
|
648
|
+
for (const tag of HTML_TIER_INTRINSICS) {
|
|
649
|
+
const cfg = this.getContractConfig(tag);
|
|
650
|
+
if (cfg)
|
|
651
|
+
add(tag, { ...cfg, tier: 'html' });
|
|
652
|
+
}
|
|
401
653
|
return out;
|
|
402
654
|
}
|
|
403
655
|
/**
|
|
@@ -147,15 +147,19 @@ export class WidgetRegistry {
|
|
|
147
147
|
label: manifest.label,
|
|
148
148
|
icon: manifest.icon,
|
|
149
149
|
category: manifest.category,
|
|
150
|
+
// `WidgetInput.label` / `defaultValue` / `advanced` are NOT copied
|
|
151
|
+
// across: they are ADR-0049 retirement tombstones on BOTH faces now
|
|
152
|
+
// (`ComponentInput` by objectui#7493 / objectui#7781,
|
|
153
|
+
// `WidgetInput` by objectui#7911) — the manifest serializer never
|
|
154
|
+
// forwarded them and no consumer of `ComponentMeta.inputs` read them,
|
|
155
|
+
// so this copy was the one non-test write of the three keys and it
|
|
156
|
+
// fed nothing. Restoring a line here would assign from a `never`.
|
|
150
157
|
inputs: manifest.inputs?.map((input) => ({
|
|
151
158
|
name: input.name,
|
|
152
159
|
type: input.type,
|
|
153
|
-
label: input.label,
|
|
154
|
-
defaultValue: input.defaultValue,
|
|
155
160
|
required: input.required,
|
|
156
161
|
enum: input.options,
|
|
157
162
|
description: input.description,
|
|
158
|
-
advanced: input.advanced,
|
|
159
163
|
})),
|
|
160
164
|
defaultProps: manifest.defaultProps,
|
|
161
165
|
isContainer: manifest.isContainer,
|
|
@@ -0,0 +1,90 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* ADR-0081 §2 — the html tier's registered intrinsic-element roster, as the
|
|
10
|
+
* published manifest declares it (objectui#10735, executing the maintainer's
|
|
11
|
+
* ruling A on objectstack#20112).
|
|
12
|
+
*
|
|
13
|
+
* A `kind:'html'` page is author-written HTML expressed as constrained JSX,
|
|
14
|
+
* parsed (never executed) into the SDUI tree. Its everyday tags — headings,
|
|
15
|
+
* paragraphs, links, lists, images, emphasis, the sectioning tags — each
|
|
16
|
+
* resolve to a renderer: `renderers/basic/html-elements.tsx` registers the
|
|
17
|
+
* flow/inline set from its `TAGS` loop, `renderers/layout/semantic.tsx` the
|
|
18
|
+
* seven sectioning tags, and `span` / `table` / `label` are registered by
|
|
19
|
+
* their own modules. The console's html-tier compile whitelists
|
|
20
|
+
* `ComponentRegistry.getKnownTypes()` minus the types whose registration is
|
|
21
|
+
* deprecated on the `'html'` surface (objectui#10757), so those pages render
|
|
22
|
+
* today.
|
|
23
|
+
*
|
|
24
|
+
* The PUBLISHED contract did not say so. `sdui.manifest.json` is
|
|
25
|
+
* `getPublicConfigs()` serialised, and that read was the curated JSON-surface
|
|
26
|
+
* vocabulary (`PUBLIC_BLOCKS`) alone — so the objectstack CLI gate, which reads
|
|
27
|
+
* the manifest as the html tier's tag whitelist, refused every plain HTML tag as
|
|
28
|
+
* `forbidden-tag` / `unknown-component` on pages the renderer accepts. The
|
|
29
|
+
* ruling: the manifest declares the html tier's registered intrinsic set
|
|
30
|
+
* exactly as the registry declares it, with each tag's registered `inputs` and
|
|
31
|
+
* child slot.
|
|
32
|
+
*
|
|
33
|
+
* ## Why a SECOND roster, and a marker, rather than entries in `PUBLIC_BLOCKS`
|
|
34
|
+
*
|
|
35
|
+
* The manifest is one flat `components` map and it feeds two readers with two
|
|
36
|
+
* meanings: the objectstack gate reads its keys as the html tier's whitelist;
|
|
37
|
+
* objectui reads the same set as the curated AI-authoring vocabulary — the
|
|
38
|
+
* `kind:'react'` JSX scope (`renderers/layout/react-page.tsx`), the generated
|
|
39
|
+
* block list, the console's contract census. Listing `h1` or `p` in
|
|
40
|
+
* `PUBLIC_BLOCKS` would have widened that curated vocabulary silently, which
|
|
41
|
+
* the ruling forbids. So the tier is declared here, on its own list, and every
|
|
42
|
+
* entry it contributes to `getPublicConfigs()` is stamped `tier: 'html'`;
|
|
43
|
+
* `manifestFromConfigs` carries the stamp into the manifest as the component's
|
|
44
|
+
* `tier`, and a consumer that means the CURATED vocabulary filters on it. A
|
|
45
|
+
* consumer that ignores the key — the objectstack gate does — sees the tags as
|
|
46
|
+
* legal, which is the ruling's whole intent for that reader.
|
|
47
|
+
*
|
|
48
|
+
* ## What is deliberately NOT here
|
|
49
|
+
*
|
|
50
|
+
* - `div` — deprecated on the JSON surface in favour of `box` (objectui#3965,
|
|
51
|
+
* PR objectui#6878) and kept out of the published contract by the same
|
|
52
|
+
* ruling that admits the rest: the gate keeps refusing `<div>` on an html
|
|
53
|
+
* page. The renderer still registers it, and its declared deprecation names
|
|
54
|
+
* both surfaces, `json` and `html` (objectui#10757): the console's html
|
|
55
|
+
* compile refuses it too, naming `box`, so the renderer and the gate agree.
|
|
56
|
+
* - `kbd` — a `ui` component under an HTML tag name (renders `keys` /
|
|
57
|
+
* `label`), not named by the ruling. Admitting it is additive and cheap on
|
|
58
|
+
* a named need; retracting a declared tag is a narrowing.
|
|
59
|
+
* - `form`, `input`, `textarea`, `select`, `switch`, `progress`, `dialog`,
|
|
60
|
+
* `summary`, `object`, `view` — JSON-surface components (or `field:` /
|
|
61
|
+
* plugin fallbacks) that happen to squat on HTML tag names; the tier
|
|
62
|
+
* excludes form controls by design (html-elements.tsx's own exclusion
|
|
63
|
+
* list) and none of the rest is an element passthrough.
|
|
64
|
+
* - `button`, `text`, `image`, `html` — HTML tag names that are ALREADY
|
|
65
|
+
* curated in `PUBLIC_BLOCKS`; they reach the manifest from there, unmarked.
|
|
66
|
+
*
|
|
67
|
+
* `code` was on that list when the roster landed: the ruling named it
|
|
68
|
+
* "registered elsewhere", but the only bare `code` registration was the
|
|
69
|
+
* `field:code` widget's namespace fallback — a code editor reading `value`, no
|
|
70
|
+
* child slot — so an html author's `<code>inline</code>` drew the editor and lost
|
|
71
|
+
* its text. objectui#10756 registers `code` as a sanitised passthrough in
|
|
72
|
+
* `html-elements.tsx`'s `TAGS` and has the widget stand down from the bare key
|
|
73
|
+
* (`FIELD_TYPES_SKIP_FALLBACK` in `@object-ui/fields`; it stays `field:code`),
|
|
74
|
+
* so the tag is declared here exactly as its siblings are.
|
|
75
|
+
*
|
|
76
|
+
* The console's `html-tier-manifest` test derives the population of
|
|
77
|
+
* HTML-named registrations from `@types/react`'s `IntrinsicElements` and
|
|
78
|
+
* holds every member to one of: this roster, `PUBLIC_BLOCKS`, or its exclusion
|
|
79
|
+
* ledger with a reason — so a registration that newly squats on a tag name
|
|
80
|
+
* lands there by absence.
|
|
81
|
+
*
|
|
82
|
+
* A tag listed here that is not registered is skipped, exactly as an
|
|
83
|
+
* unregistered `PUBLIC_BLOCKS` entry is (aspirational-safe). ⛔ A tag may not be
|
|
84
|
+
* on both rosters: the curated read wins the dedupe, so the html marker would
|
|
85
|
+
* silently not apply; `__tests__/html-tier-intrinsics.test.ts` pins the
|
|
86
|
+
* disjointness.
|
|
87
|
+
*/
|
|
88
|
+
export declare const HTML_TIER_INTRINSICS: readonly string[];
|
|
89
|
+
/** Fast membership set built from {@link HTML_TIER_INTRINSICS}. */
|
|
90
|
+
export declare const HTML_TIER_INTRINSIC_SET: ReadonlySet<string>;
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* ObjectUI
|
|
3
|
+
* Copyright (c) 2024-present ObjectStack Inc.
|
|
4
|
+
*
|
|
5
|
+
* This source code is licensed under the MIT license found in the
|
|
6
|
+
* LICENSE file in the root directory of this source tree.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* ADR-0081 §2 — the html tier's registered intrinsic-element roster, as the
|
|
10
|
+
* published manifest declares it (objectui#10735, executing the maintainer's
|
|
11
|
+
* ruling A on objectstack#20112).
|
|
12
|
+
*
|
|
13
|
+
* A `kind:'html'` page is author-written HTML expressed as constrained JSX,
|
|
14
|
+
* parsed (never executed) into the SDUI tree. Its everyday tags — headings,
|
|
15
|
+
* paragraphs, links, lists, images, emphasis, the sectioning tags — each
|
|
16
|
+
* resolve to a renderer: `renderers/basic/html-elements.tsx` registers the
|
|
17
|
+
* flow/inline set from its `TAGS` loop, `renderers/layout/semantic.tsx` the
|
|
18
|
+
* seven sectioning tags, and `span` / `table` / `label` are registered by
|
|
19
|
+
* their own modules. The console's html-tier compile whitelists
|
|
20
|
+
* `ComponentRegistry.getKnownTypes()` minus the types whose registration is
|
|
21
|
+
* deprecated on the `'html'` surface (objectui#10757), so those pages render
|
|
22
|
+
* today.
|
|
23
|
+
*
|
|
24
|
+
* The PUBLISHED contract did not say so. `sdui.manifest.json` is
|
|
25
|
+
* `getPublicConfigs()` serialised, and that read was the curated JSON-surface
|
|
26
|
+
* vocabulary (`PUBLIC_BLOCKS`) alone — so the objectstack CLI gate, which reads
|
|
27
|
+
* the manifest as the html tier's tag whitelist, refused every plain HTML tag as
|
|
28
|
+
* `forbidden-tag` / `unknown-component` on pages the renderer accepts. The
|
|
29
|
+
* ruling: the manifest declares the html tier's registered intrinsic set
|
|
30
|
+
* exactly as the registry declares it, with each tag's registered `inputs` and
|
|
31
|
+
* child slot.
|
|
32
|
+
*
|
|
33
|
+
* ## Why a SECOND roster, and a marker, rather than entries in `PUBLIC_BLOCKS`
|
|
34
|
+
*
|
|
35
|
+
* The manifest is one flat `components` map and it feeds two readers with two
|
|
36
|
+
* meanings: the objectstack gate reads its keys as the html tier's whitelist;
|
|
37
|
+
* objectui reads the same set as the curated AI-authoring vocabulary — the
|
|
38
|
+
* `kind:'react'` JSX scope (`renderers/layout/react-page.tsx`), the generated
|
|
39
|
+
* block list, the console's contract census. Listing `h1` or `p` in
|
|
40
|
+
* `PUBLIC_BLOCKS` would have widened that curated vocabulary silently, which
|
|
41
|
+
* the ruling forbids. So the tier is declared here, on its own list, and every
|
|
42
|
+
* entry it contributes to `getPublicConfigs()` is stamped `tier: 'html'`;
|
|
43
|
+
* `manifestFromConfigs` carries the stamp into the manifest as the component's
|
|
44
|
+
* `tier`, and a consumer that means the CURATED vocabulary filters on it. A
|
|
45
|
+
* consumer that ignores the key — the objectstack gate does — sees the tags as
|
|
46
|
+
* legal, which is the ruling's whole intent for that reader.
|
|
47
|
+
*
|
|
48
|
+
* ## What is deliberately NOT here
|
|
49
|
+
*
|
|
50
|
+
* - `div` — deprecated on the JSON surface in favour of `box` (objectui#3965,
|
|
51
|
+
* PR objectui#6878) and kept out of the published contract by the same
|
|
52
|
+
* ruling that admits the rest: the gate keeps refusing `<div>` on an html
|
|
53
|
+
* page. The renderer still registers it, and its declared deprecation names
|
|
54
|
+
* both surfaces, `json` and `html` (objectui#10757): the console's html
|
|
55
|
+
* compile refuses it too, naming `box`, so the renderer and the gate agree.
|
|
56
|
+
* - `kbd` — a `ui` component under an HTML tag name (renders `keys` /
|
|
57
|
+
* `label`), not named by the ruling. Admitting it is additive and cheap on
|
|
58
|
+
* a named need; retracting a declared tag is a narrowing.
|
|
59
|
+
* - `form`, `input`, `textarea`, `select`, `switch`, `progress`, `dialog`,
|
|
60
|
+
* `summary`, `object`, `view` — JSON-surface components (or `field:` /
|
|
61
|
+
* plugin fallbacks) that happen to squat on HTML tag names; the tier
|
|
62
|
+
* excludes form controls by design (html-elements.tsx's own exclusion
|
|
63
|
+
* list) and none of the rest is an element passthrough.
|
|
64
|
+
* - `button`, `text`, `image`, `html` — HTML tag names that are ALREADY
|
|
65
|
+
* curated in `PUBLIC_BLOCKS`; they reach the manifest from there, unmarked.
|
|
66
|
+
*
|
|
67
|
+
* `code` was on that list when the roster landed: the ruling named it
|
|
68
|
+
* "registered elsewhere", but the only bare `code` registration was the
|
|
69
|
+
* `field:code` widget's namespace fallback — a code editor reading `value`, no
|
|
70
|
+
* child slot — so an html author's `<code>inline</code>` drew the editor and lost
|
|
71
|
+
* its text. objectui#10756 registers `code` as a sanitised passthrough in
|
|
72
|
+
* `html-elements.tsx`'s `TAGS` and has the widget stand down from the bare key
|
|
73
|
+
* (`FIELD_TYPES_SKIP_FALLBACK` in `@object-ui/fields`; it stays `field:code`),
|
|
74
|
+
* so the tag is declared here exactly as its siblings are.
|
|
75
|
+
*
|
|
76
|
+
* The console's `html-tier-manifest` test derives the population of
|
|
77
|
+
* HTML-named registrations from `@types/react`'s `IntrinsicElements` and
|
|
78
|
+
* holds every member to one of: this roster, `PUBLIC_BLOCKS`, or its exclusion
|
|
79
|
+
* ledger with a reason — so a registration that newly squats on a tag name
|
|
80
|
+
* lands there by absence.
|
|
81
|
+
*
|
|
82
|
+
* A tag listed here that is not registered is skipped, exactly as an
|
|
83
|
+
* unregistered `PUBLIC_BLOCKS` entry is (aspirational-safe). ⛔ A tag may not be
|
|
84
|
+
* on both rosters: the curated read wins the dedupe, so the html marker would
|
|
85
|
+
* silently not apply; `__tests__/html-tier-intrinsics.test.ts` pins the
|
|
86
|
+
* disjointness.
|
|
87
|
+
*/
|
|
88
|
+
export const HTML_TIER_INTRINSICS = [
|
|
89
|
+
// ── `renderers/basic/html-elements.tsx` `TAGS` — the safe flow/inline set ──
|
|
90
|
+
'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
|
|
91
|
+
'p', 'a', 'blockquote', 'pre', 'code',
|
|
92
|
+
'strong', 'em', 'b', 'i', 'u', 'small', 'mark', 'sub', 'sup', 'del', 'ins', 'abbr',
|
|
93
|
+
'ul', 'ol', 'li', 'dl', 'dt', 'dd',
|
|
94
|
+
'figure', 'figcaption', 'img', 'hr', 'br', 'time', 'address', 'cite', 'q',
|
|
95
|
+
// ── registered elsewhere, each with its own module ────────────────────────
|
|
96
|
+
// `renderers/basic/span.tsx` — deprecated on the JSON surface, permanent
|
|
97
|
+
// vocabulary of the html tier (objectui#4000); the declaration travels with
|
|
98
|
+
// the registration, so nothing here restates it.
|
|
99
|
+
'span',
|
|
100
|
+
// `renderers/complex/table.tsx` — the data-driven table (`columns` / `data`),
|
|
101
|
+
// declared exactly as registered: no child slot, so a `<table>` authored with
|
|
102
|
+
// element children draws `not-a-container` rather than rendering them.
|
|
103
|
+
'table',
|
|
104
|
+
// `renderers/form/label.tsx` — reads `text`, declared exactly as registered.
|
|
105
|
+
'label',
|
|
106
|
+
// ── `renderers/layout/semantic.tsx` — the seven sectioning tags ──────────
|
|
107
|
+
'aside', 'main', 'header', 'nav', 'footer', 'section', 'article',
|
|
108
|
+
];
|
|
109
|
+
/** Fast membership set built from {@link HTML_TIER_INTRINSICS}. */
|
|
110
|
+
export const HTML_TIER_INTRINSIC_SET = new Set(HTML_TIER_INTRINSICS);
|
|
@@ -21,6 +21,14 @@
|
|
|
21
21
|
*
|
|
22
22
|
* This is a single, reviewable source of truth for the public surface — prefer
|
|
23
23
|
* editing this list over scattering `tier` flags across registration sites.
|
|
24
|
+
*
|
|
25
|
+
* ⛔ The html tier's intrinsic elements (`h1`, `p`, `a`, the sectioning tags, …)
|
|
26
|
+
* do NOT belong here. They reach the published manifest through the second
|
|
27
|
+
* roster beside this one, `HTML_TIER_INTRINSICS`, stamped `tier: 'html'`, so
|
|
28
|
+
* that the manifest's other reader — the objectstack gate that whitelists a
|
|
29
|
+
* `kind:'html'` page's tags — accepts them without this curated JSON-surface
|
|
30
|
+
* vocabulary growing (objectui#10735). Listing one here would widen the
|
|
31
|
+
* vocabulary silently; `html-tier-intrinsics.test.ts` pins the two disjoint.
|
|
24
32
|
*/
|
|
25
33
|
export declare const PUBLIC_BLOCKS: readonly string[];
|
|
26
34
|
/** Fast membership set built from {@link PUBLIC_BLOCKS}. */
|