@yahoo/uds-create-config 2.45.0 → 3.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/README.md +129 -0
- package/dist/ai-lanes.d.ts +23 -0
- package/dist/ai-lanes.js +34 -0
- package/dist/authoring/define-component.d.ts +85 -0
- package/dist/configs/CanvasConfig.d.ts +3237 -0
- package/dist/configs/CanvasConfig.js +332 -0
- package/dist/configs/build-options.d.ts +10 -0
- package/dist/configs/build-options.js +68 -0
- package/dist/configs/platform.d.ts +15 -0
- package/dist/configs/platform.js +17 -0
- package/dist/configs/react-native-system.d.ts +3026 -0
- package/dist/configs/react-native-system.js +64 -0
- package/dist/configs/system.d.ts +2771 -0
- package/dist/configs/system.js +74 -0
- package/dist/css/properties.generated.d.ts +14 -0
- package/dist/css/properties.generated.js +6260 -0
- package/dist/css/value-type.d.ts +48 -0
- package/dist/css/value-type.js +131 -0
- package/dist/css/values.d.ts +33 -0
- package/dist/css/values.js +116 -0
- package/dist/entities/native/NativeModifier.d.ts +25 -0
- package/dist/entities/native/NativeModifier.js +41 -0
- package/dist/entities/native/NativeSettings.d.ts +44 -0
- package/dist/entities/native/NativeSettings.js +39 -0
- package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
- package/dist/entities/native/NativeStyleProperty.js +28 -0
- package/dist/entities/native/NativeToken.d.ts +31 -0
- package/dist/entities/native/NativeToken.js +49 -0
- package/dist/entities/system/CanvasRole.d.ts +34 -0
- package/dist/entities/system/CanvasRole.js +45 -0
- package/dist/entities/system/Component.d.ts +1287 -0
- package/dist/entities/system/Component.js +1840 -0
- package/dist/entities/system/Composite.d.ts +12 -0
- package/dist/entities/system/Composite.js +26 -0
- package/dist/entities/system/Device.d.ts +11 -0
- package/dist/entities/system/Device.js +18 -0
- package/dist/entities/system/File.d.ts +72 -0
- package/dist/entities/system/File.js +136 -0
- package/dist/entities/system/Font.d.ts +48 -0
- package/dist/entities/system/Font.js +56 -0
- package/dist/entities/system/GlobalStyle.d.ts +26 -0
- package/dist/entities/system/GlobalStyle.js +54 -0
- package/dist/entities/system/Guidance.d.ts +85 -0
- package/dist/entities/system/Guidance.js +59 -0
- package/dist/entities/system/GuidanceStyle.d.ts +14 -0
- package/dist/entities/system/GuidanceStyle.js +8 -0
- package/dist/entities/system/Icon.d.ts +46 -0
- package/dist/entities/system/Icon.js +46 -0
- package/dist/entities/system/LinkedSystem.d.ts +504 -0
- package/dist/entities/system/LinkedSystem.js +814 -0
- package/dist/entities/system/Modifier.d.ts +92 -0
- package/dist/entities/system/Modifier.js +120 -0
- package/dist/entities/system/Motion.d.ts +28 -0
- package/dist/entities/system/Motion.js +48 -0
- package/dist/entities/system/Operation.d.ts +100 -0
- package/dist/entities/system/Operation.js +236 -0
- package/dist/entities/system/Package.d.ts +42 -0
- package/dist/entities/system/Package.js +75 -0
- package/dist/entities/system/Settings.d.ts +94 -0
- package/dist/entities/system/Settings.js +166 -0
- package/dist/entities/system/StyleProperty.d.ts +135 -0
- package/dist/entities/system/StyleProperty.js +438 -0
- package/dist/entities/system/Token.d.ts +67 -0
- package/dist/entities/system/Token.js +129 -0
- package/dist/entities/system/Tool.d.ts +134 -0
- package/dist/entities/system/Tool.js +124 -0
- package/dist/entities/system/color.d.ts +64 -0
- package/dist/entities/system/color.js +123 -0
- package/dist/entities/system/component-module.d.ts +63 -0
- package/dist/entities/system/component-module.js +258 -0
- package/dist/entities/system/copy-plan.d.ts +98 -0
- package/dist/entities/system/copy-plan.js +451 -0
- package/dist/entities/system/defineComponent.d.ts +428 -0
- package/dist/entities/system/defineComponent.js +337 -0
- package/dist/entities/system/element.d.ts +101 -0
- package/dist/entities/system/element.js +171 -0
- package/dist/entities/system/icon-library.d.ts +64 -0
- package/dist/entities/system/icon-library.js +112 -0
- package/dist/entities/system/icon-metadata.d.ts +72 -0
- package/dist/entities/system/icon-metadata.js +111 -0
- package/dist/entities/system/link-declaration.d.ts +27 -0
- package/dist/entities/system/link-declaration.js +64 -0
- package/dist/entities/system/link-plan.d.ts +160 -0
- package/dist/entities/system/link-plan.js +770 -0
- package/dist/entities/system/runtime-modules.d.ts +25 -0
- package/dist/entities/system/runtime-modules.js +38 -0
- package/dist/entities/system/style-bag.d.ts +20 -0
- package/dist/entities/system/style-bag.js +246 -0
- package/dist/entities/system/token-index.d.ts +89 -0
- package/dist/entities/system/token-index.js +112 -0
- package/dist/framework/Config.d.ts +2472 -0
- package/dist/framework/Config.js +5023 -0
- package/dist/framework/Entity.d.ts +127 -0
- package/dist/framework/Entity.js +125 -0
- package/dist/framework/authoring.d.ts +24 -0
- package/dist/framework/authoring.js +7 -0
- package/dist/framework/change-hooks.d.ts +119 -0
- package/dist/framework/change-hooks.js +131 -0
- package/dist/framework/changes.d.ts +88 -0
- package/dist/framework/changes.js +246 -0
- package/dist/framework/class-names.d.ts +260 -0
- package/dist/framework/class-names.js +630 -0
- package/dist/framework/coalesce.d.ts +25 -0
- package/dist/framework/coalesce.js +60 -0
- package/dist/framework/config-op.d.ts +76 -0
- package/dist/framework/config-op.js +43 -0
- package/dist/framework/config-operation-kind.d.ts +14 -0
- package/dist/framework/config-operation-kind.js +14 -0
- package/dist/framework/config-ops.d.ts +34 -0
- package/dist/framework/config-ops.js +187 -0
- package/dist/framework/defineConfig.d.ts +196 -0
- package/dist/framework/defineConfig.js +100 -0
- package/dist/framework/defineDerivedEntity.d.ts +74 -0
- package/dist/framework/defineDerivedEntity.js +83 -0
- package/dist/framework/defineEntity.d.ts +318 -0
- package/dist/framework/defineEntity.js +183 -0
- package/dist/framework/defineSubEntity.d.ts +148 -0
- package/dist/framework/defineSubEntity.js +121 -0
- package/dist/framework/derived-mutations.d.ts +20 -0
- package/dist/framework/derived-mutations.js +38 -0
- package/dist/framework/entity-search.d.ts +29 -0
- package/dist/framework/entity-search.js +117 -0
- package/dist/framework/inline-sources.d.ts +49 -0
- package/dist/framework/inline-sources.js +388 -0
- package/dist/framework/layer-styles.d.ts +25 -0
- package/dist/framework/layer-styles.js +49 -0
- package/dist/framework/memo.d.ts +48 -0
- package/dist/framework/memo.js +84 -0
- package/dist/framework/overlay.d.ts +49 -0
- package/dist/framework/overlay.js +17 -0
- package/dist/framework/plan.d.ts +49 -0
- package/dist/framework/plan.js +73 -0
- package/dist/framework/projections.d.ts +480 -0
- package/dist/framework/projections.js +974 -0
- package/dist/framework/prop-surface.d.ts +132 -0
- package/dist/framework/prop-surface.js +278 -0
- package/dist/framework/ref-graph.d.ts +71 -0
- package/dist/framework/ref-graph.js +158 -0
- package/dist/framework/ref-integrity.d.ts +55 -0
- package/dist/framework/ref-integrity.js +171 -0
- package/dist/framework/registered.d.ts +95 -0
- package/dist/framework/registry-dir.d.ts +42 -0
- package/dist/framework/registry-dir.js +48 -0
- package/dist/framework/registry.d.ts +300 -0
- package/dist/framework/registry.js +104 -0
- package/dist/framework/rejection.d.ts +58 -0
- package/dist/framework/rejection.js +111 -0
- package/dist/framework/rename-inference.d.ts +26 -0
- package/dist/framework/rename-inference.js +50 -0
- package/dist/framework/render-spec.d.ts +296 -0
- package/dist/framework/render-spec.js +809 -0
- package/dist/framework/schema-version.d.ts +140 -0
- package/dist/framework/schema-version.js +214 -0
- package/dist/framework/schemas.d.ts +109 -0
- package/dist/framework/schemas.js +615 -0
- package/dist/framework/session.d.ts +196 -0
- package/dist/framework/session.js +367 -0
- package/dist/framework/signature.d.ts +15 -0
- package/dist/framework/signature.js +83 -0
- package/dist/framework/snapshot.d.ts +115 -0
- package/dist/framework/snapshot.js +277 -0
- package/dist/framework/source-integrity.d.ts +226 -0
- package/dist/framework/source-integrity.js +478 -0
- package/dist/framework/sources.d.ts +211 -0
- package/dist/framework/sources.js +89 -0
- package/dist/framework/utils/compiled-schema.d.ts +23 -0
- package/dist/framework/utils/compiled-schema.js +46 -0
- package/dist/framework/utils/content-key.d.ts +15 -0
- package/dist/framework/utils/content-key.js +33 -0
- package/dist/framework/utils/enumerated.d.ts +13 -0
- package/dist/framework/utils/enumerated.js +19 -0
- package/dist/framework/utils/field-path.d.ts +95 -0
- package/dist/framework/utils/field-path.js +136 -0
- package/dist/framework/utils/field-schema.d.ts +55 -0
- package/dist/framework/utils/field-schema.js +183 -0
- package/dist/framework/utils/group.d.ts +37 -0
- package/dist/framework/utils/group.js +13 -0
- package/dist/framework/utils/package-path.d.ts +37 -0
- package/dist/framework/utils/package-path.js +61 -0
- package/dist/framework/utils/refs.d.ts +194 -0
- package/dist/framework/utils/refs.js +403 -0
- package/dist/framework/validate-spec.d.ts +27 -0
- package/dist/framework/validate-spec.js +45 -0
- package/dist/framework/value-domain.d.ts +26 -0
- package/dist/framework/value-domain.js +202 -0
- package/dist/framework/views-facade.d.ts +15 -0
- package/dist/framework/views-facade.js +19 -0
- package/dist/index.d.ts +90 -42
- package/dist/index.js +86 -37
- package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
- package/dist/migrations/2.0.0/raw-css.js +72 -0
- package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
- package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
- package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
- package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
- package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
- package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
- package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
- package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
- package/dist/migrations/index.d.ts +2 -0
- package/dist/migrations/index.js +2 -0
- package/dist/react-native/style-keys.generated.d.ts +10 -0
- package/dist/react-native/style-keys.generated.js +167 -0
- package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
- package/dist/renderer/RendererErrorBoundary.js +59 -10
- package/dist/renderer/UdsRenderer.d.ts +11 -10
- package/dist/renderer/UdsRenderer.js +1 -1
- package/dist/renderer/assetEntries.d.ts +37 -0
- package/dist/renderer/assetEntries.js +39 -0
- package/dist/renderer/assetRenderable.d.ts +14 -6
- package/dist/renderer/assetRenderable.js +8 -2
- package/dist/renderer/componentEntry.d.ts +58 -0
- package/dist/renderer/componentEntry.js +71 -0
- package/dist/renderer/icon-library.d.ts +20 -0
- package/dist/renderer/index.d.ts +7 -7
- package/dist/renderer/index.js +5 -5
- package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
- package/dist/renderer/primitives/SlotRenderer.js +1 -1
- package/dist/renderer/runtimeComponent.d.ts +33 -0
- package/dist/renderer/runtimeComponent.js +113 -0
- package/dist/renderer/spec-content.d.ts +43 -0
- package/dist/renderer/spec-content.js +95 -0
- package/dist/renderer/wrapRegistry.d.ts +22 -37
- package/dist/renderer/wrapRegistry.js +10 -20
- package/dist/renderer/wrappers/event-bridge.js +6 -5
- package/dist/renderer/wrappers/hex-normalize.js +6 -5
- package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
- package/dist/renderer/wrappers/html-aliases.js +36 -19
- package/dist/renderer/wrappers/inline-styles.js +7 -6
- package/dist/spec/asset-jsx.d.ts +18 -5
- package/dist/spec/asset-jsx.js +27 -16
- package/dist/spec/collapse-text-labels.d.ts +5 -15
- package/dist/spec/collapse-text-labels.js +26 -19
- package/dist/spec/empty-node-slots.d.ts +56 -34
- package/dist/spec/empty-node-slots.js +87 -47
- package/dist/spec/index.d.ts +21 -10
- package/dist/spec/index.js +21 -10
- package/dist/spec/jsxToSpec.d.ts +14 -9
- package/dist/spec/jsxToSpec.js +20 -3
- package/dist/spec/preview-elements.d.ts +63 -0
- package/dist/spec/preview-elements.js +89 -0
- package/dist/spec/rewrite-refs.d.ts +58 -0
- package/dist/spec/rewrite-refs.js +250 -0
- package/dist/spec/specToJsx.js +18 -29
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +39 -52
- package/dist/AssetGroup.d.ts +0 -77
- package/dist/AssetGroup.js +0 -125
- package/dist/Component.d.ts +0 -333
- package/dist/Component.js +0 -1061
- package/dist/ComponentGroup.d.ts +0 -22
- package/dist/ComponentGroup.js +0 -51
- package/dist/CompositeStyle.d.ts +0 -30
- package/dist/CompositeStyle.js +0 -59
- package/dist/Config.d.ts +0 -528
- package/dist/Config.js +0 -1712
- package/dist/Mode.d.ts +0 -41
- package/dist/Mode.js +0 -81
- package/dist/Modifier.d.ts +0 -51
- package/dist/Modifier.js +0 -97
- package/dist/MotionDef.d.ts +0 -81
- package/dist/MotionDef.js +0 -212
- package/dist/Props.d.ts +0 -332
- package/dist/Props.js +0 -35
- package/dist/Provider.d.ts +0 -20
- package/dist/Provider.js +0 -14
- package/dist/StyleProp.d.ts +0 -145
- package/dist/StyleProp.js +0 -239
- package/dist/Token.d.ts +0 -76
- package/dist/Token.js +0 -133
- package/dist/TokenGroup.d.ts +0 -33
- package/dist/TokenGroup.js +0 -69
- package/dist/asset-kind.d.ts +0 -55
- package/dist/asset-kind.js +0 -29
- package/dist/asset-value.d.ts +0 -23
- package/dist/asset-value.js +0 -40
- package/dist/brands.d.ts +0 -30
- package/dist/brands.js +0 -20
- package/dist/captureCallerPath.d.ts +0 -48
- package/dist/captureCallerPath.js +0 -95
- package/dist/colorExpressions.d.ts +0 -131
- package/dist/colorExpressions.js +0 -148
- package/dist/component-referrers.d.ts +0 -30
- package/dist/component-referrers.js +0 -40
- package/dist/config-diagnostics.d.ts +0 -21
- package/dist/config-diagnostics.js +0 -12
- package/dist/defineAssetGroup.d.ts +0 -200
- package/dist/defineAssetGroup.js +0 -323
- package/dist/defineProvider.d.ts +0 -29
- package/dist/defineProvider.js +0 -60
- package/dist/element-marker.d.ts +0 -63
- package/dist/element-marker.js +0 -113
- package/dist/entity-utils.d.ts +0 -56
- package/dist/entity-utils.js +0 -105
- package/dist/extension.d.ts +0 -55
- package/dist/extension.js +0 -214
- package/dist/factories.d.ts +0 -863
- package/dist/factories.js +0 -475
- package/dist/font-face.d.ts +0 -25
- package/dist/font-face.js +0 -72
- package/dist/foreign-component-name.d.ts +0 -21
- package/dist/foreign-component-name.js +0 -42
- package/dist/interpolate.d.ts +0 -20
- package/dist/interpolate.js +0 -10
- package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
- package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
- package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
- package/dist/jsx/jsx-dev-runtime.js +0 -11
- package/dist/jsx/jsx-runtime.d.ts +0 -48
- package/dist/jsx/jsx-runtime.js +0 -305
- package/dist/linked-system-pins.d.ts +0 -30
- package/dist/linked-system-pins.js +0 -45
- package/dist/linkedNodePrefixes.d.ts +0 -73
- package/dist/linkedNodePrefixes.js +0 -99
- package/dist/markers.d.ts +0 -235
- package/dist/markers.js +0 -70
- package/dist/motion-constants.d.ts +0 -37
- package/dist/motion-constants.js +0 -61
- package/dist/native/NativeConfig.d.ts +0 -56
- package/dist/native/NativeConfig.js +0 -162
- package/dist/native/assets.d.ts +0 -20
- package/dist/native/assets.js +0 -17
- package/dist/native/components.d.ts +0 -139
- package/dist/native/components.js +0 -67
- package/dist/native/index.d.ts +0 -18
- package/dist/native/index.js +0 -17
- package/dist/native/modes.d.ts +0 -10
- package/dist/native/modes.js +0 -11
- package/dist/native/types.d.ts +0 -95
- package/dist/native/types.js +0 -0
- package/dist/native/validation.d.ts +0 -8
- package/dist/native/validation.js +0 -885
- package/dist/native/values.d.ts +0 -7
- package/dist/native/values.js +0 -15
- package/dist/native.d.ts +0 -12
- package/dist/native.js +0 -10
- package/dist/refs.d.ts +0 -204
- package/dist/refs.js +0 -129
- package/dist/registry-aliases.d.ts +0 -33
- package/dist/registry-aliases.js +0 -35
- package/dist/registry-dir.d.ts +0 -22
- package/dist/registry-dir.js +0 -10
- package/dist/renderer/makeRegistry.d.ts +0 -34
- package/dist/renderer/makeRegistry.js +0 -52
- package/dist/renderer/makeUdsRenderer.d.ts +0 -13
- package/dist/renderer/makeUdsRenderer.js +0 -51
- package/dist/renderer/wrappers/component-slots.d.ts +0 -41
- package/dist/renderer/wrappers/component-slots.js +0 -66
- package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
- package/dist/renderer/wrappers/slot-resolution.js +0 -68
- package/dist/renderer/wrappers/void-elements.d.ts +0 -37
- package/dist/renderer/wrappers/void-elements.js +0 -40
- package/dist/spec/layer-props.d.ts +0 -52
- package/dist/spec/layer-props.js +0 -149
- package/dist/spec/preview-controls.d.ts +0 -44
- package/dist/spec/preview-controls.js +0 -139
- package/dist/spec/slot-refs.d.ts +0 -39
- package/dist/spec/slot-refs.js +0 -56
- package/dist/token-override-rows.d.ts +0 -68
- package/dist/token-override-rows.js +0 -233
- package/dist/tokenValueType.d.ts +0 -34
- package/dist/tokenValueType.js +0 -138
- package/dist/types/css-properties.d.ts +0 -233
- package/dist/types/css-properties.js +0 -14
- package/dist/types/css-property-keywords.d.ts +0 -156
- package/dist/types/css-property-keywords.js +0 -616
- package/dist/types/css-values.d.ts +0 -63
- package/dist/types/css-values.js +0 -16
- package/dist/types.d.ts +0 -1138
- package/dist/types.js +0 -12
- package/dist/units.d.ts +0 -14
- package/dist/units.js +0 -16
- package/dist/utils/index.d.ts +0 -4
- package/dist/utils/index.js +0 -4
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
//#region src/framework/utils/field-path.ts
|
|
2
|
+
/**
|
|
3
|
+
* A write's ADDRESS, carried in the delta's KEY.
|
|
4
|
+
*
|
|
5
|
+
* `update` / `sub-update` take a partial whose keys are FIELD PATHS. One rule covers every depth:
|
|
6
|
+
* **the value replaces whatever the key addresses**, and `null` removes it.
|
|
7
|
+
*
|
|
8
|
+
* { layers: {…} } → replaces the whole `layers` field
|
|
9
|
+
* { 'layers.root.bg': 'hover' } → replaces one leaf, touching nothing else
|
|
10
|
+
* { 'layers.root.bg': null } → removes that leaf
|
|
11
|
+
* { 'layers.root': null } → removes the whole bag
|
|
12
|
+
*
|
|
13
|
+
* So depth is something the CALLER states rather than something the verb implies — Firestore's
|
|
14
|
+
* `update()` rule, and the reason there is no second "deep" verb. A deep write and a whole-field
|
|
15
|
+
* write differ only in how many segments the key has.
|
|
16
|
+
*
|
|
17
|
+
* The nested-object delta this replaces could not tell those two apart. Merged recursively,
|
|
18
|
+
* `{ value: { warning: {} } }` is both "add a value called `warning`" and "empty the one that is
|
|
19
|
+
* already there", and the merge had to GUESS — it pruned, so adding a variant value applied cleanly
|
|
20
|
+
* and stored nothing: a silent no-op with no rejection to explain it. Under an address there is
|
|
21
|
+
* nothing to guess, because setting and removing are different calls rather than different-looking
|
|
22
|
+
* data.
|
|
23
|
+
*
|
|
24
|
+
* The one thing an address cannot spell is a member key that itself contains a dot (`spacing.2`,
|
|
25
|
+
* which nothing names today — paths separate with `/`). Such a key is reachable by `sub-upsert`,
|
|
26
|
+
* which addresses it whole.
|
|
27
|
+
*/
|
|
28
|
+
/** A JSON object — not an array, not a class instance. */
|
|
29
|
+
function isPlainObject(value) {
|
|
30
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* The segments a delta key addresses.
|
|
34
|
+
*
|
|
35
|
+
* A key is a PATH when it contains a `.` AND its first segment names a field of the thing being
|
|
36
|
+
* written — decidable off the target's own schema, so it is a rule rather than a guess. A key that
|
|
37
|
+
* fails either test addresses one field, dot and all, which is what keeps a literal dotted key
|
|
38
|
+
* writable at the depth it lives at.
|
|
39
|
+
*/
|
|
40
|
+
function pathSegments(key, isField) {
|
|
41
|
+
const dot = key.indexOf(".");
|
|
42
|
+
if (dot === -1) return [key];
|
|
43
|
+
return isField(key.slice(0, dot)) ? key.split(".") : [key];
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* A partial over one section of an item, as the item-level delta that writes it: every key prefixed by
|
|
47
|
+
* the section's field, so `{ prefix: 'acme' }` on `css` becomes `{ 'css.prefix': 'acme' }`. A value that
|
|
48
|
+
* is not a record writes the section whole.
|
|
49
|
+
*/
|
|
50
|
+
function sectionDelta(field, data) {
|
|
51
|
+
if (!isPlainObject(data)) return { [field]: data };
|
|
52
|
+
return Object.fromEntries(Object.entries(data).map(([key, value]) => [`${field}.${key}`, value]));
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* `body` with `value` at `segments` — assigned, or REMOVED when `value` is `null`. Neither input is
|
|
56
|
+
* mutated.
|
|
57
|
+
*
|
|
58
|
+
* Two rules about containers along the way, and both follow from "the value replaces what the key
|
|
59
|
+
* addresses":
|
|
60
|
+
*
|
|
61
|
+
* - An intermediate that is missing, or is a scalar, becomes a container. The caller addressed
|
|
62
|
+
* something inside it, which is a caller saying one belongs there.
|
|
63
|
+
* - A removal that EMPTIES a container takes the container with it, except at the first segment —
|
|
64
|
+
* those are the target's own declared fields, and a rule whose `layers` bag has been cleared is
|
|
65
|
+
* still a rule with an empty bag, not a rule missing a required field. Removing the field itself
|
|
66
|
+
* is what `null` AT that segment says. A SET never prunes: an empty object a caller wrote is a
|
|
67
|
+
* value.
|
|
68
|
+
*/
|
|
69
|
+
function setAtPath(body, segments, value, depth = 0) {
|
|
70
|
+
const [head, ...rest] = segments;
|
|
71
|
+
if (head === void 0) return body;
|
|
72
|
+
const next = { ...body };
|
|
73
|
+
if (rest.length === 0) {
|
|
74
|
+
if (value === null) delete next[head];
|
|
75
|
+
else next[head] = value;
|
|
76
|
+
return next;
|
|
77
|
+
}
|
|
78
|
+
const written = setAtPath(isPlainObject(next[head]) ? next[head] : {}, rest, value, depth + 1);
|
|
79
|
+
if (depth > 0 && value === null && Object.keys(written).length === 0) delete next[head];
|
|
80
|
+
else next[head] = written;
|
|
81
|
+
return next;
|
|
82
|
+
}
|
|
83
|
+
/**
|
|
84
|
+
* A path-keyed delta applied to a body, entry by entry in the order the caller wrote them.
|
|
85
|
+
*
|
|
86
|
+
* Order matters and is the caller's: two entries may address the same subtree, and the second is
|
|
87
|
+
* meant to win. That is also what makes one batch safe where a read-merge-write pair was not.
|
|
88
|
+
*/
|
|
89
|
+
function applyPathDelta(current, delta, isField) {
|
|
90
|
+
let out = current;
|
|
91
|
+
for (const [key, value] of Object.entries(delta)) out = setAtPath(out, pathSegments(key, isField), value);
|
|
92
|
+
return out;
|
|
93
|
+
}
|
|
94
|
+
/**
|
|
95
|
+
* The inverse of {@link applyPathDelta}: the path-keyed delta that turns `existing` into `desired`,
|
|
96
|
+
* over `fields` — one entry per changed member (`null` removes), nothing restated. This is what
|
|
97
|
+
* makes a reconciling writer produce patches that SAY what the gesture did: a prop edit reads back
|
|
98
|
+
* as `props.bg`, not as a whole-body replace.
|
|
99
|
+
*
|
|
100
|
+
* Descent stops exactly where addressing stops, so applying the delta always reproduces `desired`:
|
|
101
|
+
* both sides must be plain records (an array, a ref, a scalar replaces at its own address), every
|
|
102
|
+
* member key must be dot-free (a dotted key can't be addressed — the record writes whole), and a
|
|
103
|
+
* NESTED record emptied of members writes whole, since {@link setAtPath} prunes a container a
|
|
104
|
+
* removal empties. A declared field is never pruned there, so at the field level the same
|
|
105
|
+
* emptying stays addressed.
|
|
106
|
+
*
|
|
107
|
+
* `same` is the caller's structural equality — bodies hold refs, and whether two spellings of one
|
|
108
|
+
* are equal is the caller's to say.
|
|
109
|
+
*/
|
|
110
|
+
function pathDelta({ existing, desired, fields, same }) {
|
|
111
|
+
const delta = {};
|
|
112
|
+
const isRef = (value) => typeof value?.__ref === "string";
|
|
113
|
+
const walk = (address, before, after, depth) => {
|
|
114
|
+
if (same(before, after)) return;
|
|
115
|
+
const keys = isPlainObject(before) && isPlainObject(after) ? [...new Set([...Object.keys(before), ...Object.keys(after)])] : void 0;
|
|
116
|
+
if (!(keys !== void 0 && keys.length > 0 && (depth === 0 || Object.keys(after).length > 0) && !isRef(before) && !isRef(after) && keys.every((key) => !key.includes(".")))) {
|
|
117
|
+
delta[address] = after === void 0 ? null : after;
|
|
118
|
+
return;
|
|
119
|
+
}
|
|
120
|
+
for (const key of keys) walk(`${address}.${key}`, before[key], after[key], depth + 1);
|
|
121
|
+
};
|
|
122
|
+
for (const field of fields) walk(field, existing[field], desired[field], 0);
|
|
123
|
+
return delta;
|
|
124
|
+
}
|
|
125
|
+
/** A field predicate over a known list of names — an entity's `fieldKeys`, straight off the kind. */
|
|
126
|
+
function namedFields(names) {
|
|
127
|
+
const declared = new Set(names);
|
|
128
|
+
return (name) => declared.has(name);
|
|
129
|
+
}
|
|
130
|
+
/** The FIELDS a delta touched — every key's first segment. What a write reports as changed, so work
|
|
131
|
+
* scoped to written fields (member coercion) covers the same set the delta reached. */
|
|
132
|
+
function touchedFields(delta, isField) {
|
|
133
|
+
return new Set(Object.keys(delta).map((key) => pathSegments(key, isField)[0]));
|
|
134
|
+
}
|
|
135
|
+
//#endregion
|
|
136
|
+
export { applyPathDelta, isPlainObject, namedFields, pathDelta, pathSegments, sectionDelta, setAtPath, touchedFields };
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/utils/field-schema.d.ts
|
|
4
|
+
/** A kind's fields: a flat object, or a union discriminated on one field for kinds whose
|
|
5
|
+
* shape varies (each member a `z.object`). */
|
|
6
|
+
type FieldsSchema = z.ZodObject<z.ZodRawShape> | z.ZodDiscriminatedUnion<readonly z.ZodObject<z.ZodRawShape>[]>;
|
|
7
|
+
/** Distribute over a union first, then drop each member's index signature so an empty
|
|
8
|
+
* `z.object({})` (which infers to `Record<string, never>`) intersects cleanly with the
|
|
9
|
+
* metadata below. Real declared keys are kept; only the catch-all index is removed. */
|
|
10
|
+
type RemoveIndex<T> = T extends unknown ? { [K in keyof T as string extends K ? never : number extends K ? never : symbol extends K ? never : K]: T[K] } : never;
|
|
11
|
+
/** The typed author/create body for a schema — the schema's input shape (so a field with
|
|
12
|
+
* a zod `.default()` is optional to author; it's coerced in) plus the universal metadata
|
|
13
|
+
* every entity may carry. Over a discriminated union this stays a union, so authoring one
|
|
14
|
+
* member's fields never bleeds into another's. */
|
|
15
|
+
type CreateInput<S extends FieldsSchema> = RemoveIndex<z.input<S>> & {
|
|
16
|
+
label?: string;
|
|
17
|
+
description?: string;
|
|
18
|
+
copiedFrom?: string;
|
|
19
|
+
hidden?: boolean;
|
|
20
|
+
deprecated?: boolean;
|
|
21
|
+
guidance?: string;
|
|
22
|
+
};
|
|
23
|
+
/** The create validator — the field schema plus metadata (the storage shape; a value
|
|
24
|
+
* storage accepts is creatable — no artificial narrowing at the entity layer). A union
|
|
25
|
+
* extends each member so the discriminant still selects one strict shape. `safeExtend`, so a
|
|
26
|
+
* check a kind declares across its fields (a preview prop naming a prop the body doesn't
|
|
27
|
+
* declare) survives: `extend` drops an object's checks. */
|
|
28
|
+
declare function deriveCreateSchema(schema: FieldsSchema): z.ZodTypeAny;
|
|
29
|
+
/**
|
|
30
|
+
* The update validator — a partial whose keys are field paths ({@link applyPathDelta}).
|
|
31
|
+
*
|
|
32
|
+
* Loose, and that is load-bearing rather than lax: `layers.root.bg` is not a declared field, so a
|
|
33
|
+
* schema that stripped unknown keys (zod's default) would drop every deep write on the floor and
|
|
34
|
+
* report success. What the key names is checked when the delta is applied — the path's head must be a
|
|
35
|
+
* field — and the result of applying it is then validated against the create schema, which is where
|
|
36
|
+
* value types, cross-field checks and coercions all live. So this schema's job is to describe the
|
|
37
|
+
* fields a caller may name and to type the whole-field case; it is deliberately not the gate.
|
|
38
|
+
*/
|
|
39
|
+
declare function deriveUpdateSchema(schema: FieldsSchema): z.ZodTypeAny;
|
|
40
|
+
/**
|
|
41
|
+
* Whether a name is a field of the thing being written — what {@link pathSegments} asks to decide
|
|
42
|
+
* whether a dotted delta key is an address or one literal key.
|
|
43
|
+
*
|
|
44
|
+
* Liberal by construction: a union contributes every member's keys, and a record contributes all
|
|
45
|
+
* names, because a record's keys are its fields (a component's `layers` bag is addressed by layer
|
|
46
|
+
* name). Metadata counts too, so `label` is namable wherever it is storable. A name this says no to
|
|
47
|
+
* is written as one key, dot and all, which is the safe answer — the create schema then judges it.
|
|
48
|
+
*/
|
|
49
|
+
declare function declaredField(schema: z.ZodTypeAny | undefined): (name: string) => boolean;
|
|
50
|
+
/** The declared field names, in order — hydration and `toJSON` walk these. A union yields
|
|
51
|
+
* the union of every member's keys (discriminant first), so hydration copies whichever
|
|
52
|
+
* fields the stored member actually carries. */
|
|
53
|
+
declare function fieldKeys(schema: FieldsSchema): string[];
|
|
54
|
+
//#endregion
|
|
55
|
+
export { CreateInput, FieldsSchema, declaredField, deriveCreateSchema, deriveUpdateSchema, fieldKeys };
|
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/framework/utils/field-schema.ts
|
|
3
|
+
/**
|
|
4
|
+
* An entity declares its fields as a plain `z.object({ ... })` — optionality, value types,
|
|
5
|
+
* and validation come straight from zod (`z.string().optional()`), no custom dsl. Everything
|
|
6
|
+
* downstream (typed bodies, create/update validators, hydration) derives from that one
|
|
7
|
+
* schema.
|
|
8
|
+
*
|
|
9
|
+
* A kind whose shape genuinely varies by a discriminant (Motion: `runtime: 'css'` needs
|
|
10
|
+
* `keyframes`, `runtime: 'js'` carries interaction state instead) may instead declare a
|
|
11
|
+
* `z.discriminatedUnion` — so the coupling is a type, not a runtime hope. The three
|
|
12
|
+
* derivations below handle both: an object extends/partials its shape directly; a union
|
|
13
|
+
* extends/partials each member and re-composes, keeping the discriminant intact.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* Universal editable metadata — every entity's create body may carry it, on an item and on a group
|
|
17
|
+
* node alike.
|
|
18
|
+
*
|
|
19
|
+
* `copiedFrom` is where a copied entity was taken from, as `<path>@<slug>`: the source's spelling of
|
|
20
|
+
* the path and the pin it came through. A plain string rather than a ref, because a copy stands on its
|
|
21
|
+
* own — it must not become a dependency on the pin, and dropping the pin must not delete it. Written by
|
|
22
|
+
* `linked-system/copy`; absent on an entity authored here.
|
|
23
|
+
*
|
|
24
|
+
* `hidden` and `deprecated` are the two ways to retire an entity short of deleting it. Both keep it
|
|
25
|
+
* registered, resolving and emitting, and take it out of every surface that offers values to pick
|
|
26
|
+
* from. `deprecated` additionally flags every existing use, so it can be worked through. Set on a
|
|
27
|
+
* group node, either applies to every member; `Config.hidden` and `Config.deprecated` read both.
|
|
28
|
+
*
|
|
29
|
+
* `guidance` is how to use the entity, as prose for a model composing with the system, in the
|
|
30
|
+
* imperative voice of a guidance rule. `description` says what the thing is for a surface that lists
|
|
31
|
+
* it. The guidance document collects these per kind and the prompt prints them there.
|
|
32
|
+
*/
|
|
33
|
+
const METADATA = {
|
|
34
|
+
label: z.string().optional(),
|
|
35
|
+
description: z.string().optional(),
|
|
36
|
+
copiedFrom: z.string().optional(),
|
|
37
|
+
hidden: z.boolean().optional(),
|
|
38
|
+
deprecated: z.boolean().optional(),
|
|
39
|
+
guidance: z.string().optional()
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* The metadata names a body may carry on top of its kind's own fields — read off {@link metadata}
|
|
43
|
+
* rather than re-listed, so the two cannot disagree.
|
|
44
|
+
*
|
|
45
|
+
* What a caller wants it for is deciding whether a delta key names something: `fieldKeys` covers the
|
|
46
|
+
* declared fields and stops, so a gate built on that alone refuses `label` on every kind. `Entity`
|
|
47
|
+
* hydrates these two separately for the same reason.
|
|
48
|
+
*/
|
|
49
|
+
const METADATA_KEYS = Object.keys(METADATA);
|
|
50
|
+
/** Re-compose a discriminated union from transformed members. Each member keeps its literal
|
|
51
|
+
* discriminant at runtime, but mapping over the erased `ZodObject<ZodRawShape>` members
|
|
52
|
+
* hides that literal from `discriminatedUnion`'s tuple constraint — so the one bridging cast
|
|
53
|
+
* lives here rather than at every call site. */
|
|
54
|
+
function composeDiscriminated(discriminator, members) {
|
|
55
|
+
return z.discriminatedUnion(discriminator, members);
|
|
56
|
+
}
|
|
57
|
+
/** Make every field of a shape a partial-patch field: an optional field also accepts
|
|
58
|
+
* `null` (the universal "clear this field" affordance — `apply` drops null keys), a
|
|
59
|
+
* required field just becomes optional. Keys in `keep` pass through untouched — used to
|
|
60
|
+
* hold a union's discriminant literal required so the patch still identifies its member. */
|
|
61
|
+
function partializeShape(shape, keep) {
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const [key, field] of Object.entries(shape)) {
|
|
64
|
+
if (keep.has(key)) {
|
|
65
|
+
out[key] = field;
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
const f = field;
|
|
69
|
+
out[key] = (f instanceof z.ZodOptional ? f.unwrap() : f).nullable().optional();
|
|
70
|
+
}
|
|
71
|
+
return out;
|
|
72
|
+
}
|
|
73
|
+
/** The create validator — the field schema plus metadata (the storage shape; a value
|
|
74
|
+
* storage accepts is creatable — no artificial narrowing at the entity layer). A union
|
|
75
|
+
* extends each member so the discriminant still selects one strict shape. `safeExtend`, so a
|
|
76
|
+
* check a kind declares across its fields (a preview prop naming a prop the body doesn't
|
|
77
|
+
* declare) survives: `extend` drops an object's checks. */
|
|
78
|
+
function deriveCreateSchema(schema) {
|
|
79
|
+
if (schema instanceof z.ZodDiscriminatedUnion) return composeDiscriminated(schema.def.discriminator, schema.def.options.map((member) => member.safeExtend(METADATA)));
|
|
80
|
+
return schema.safeExtend(METADATA);
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* The delta shape — one entry per field a partial may name, each optional and `null`-accepting.
|
|
84
|
+
*
|
|
85
|
+
* A union flattens into one shape rather than staying discriminated, and that is the point: a delta
|
|
86
|
+
* addresses a field, not a member, so requiring the discriminant would mean restating `type` to
|
|
87
|
+
* change a Motion's duration. A key two members declare differently widens to `unknown` — the delta
|
|
88
|
+
* doesn't say which member it is aimed at, and the narrower of two types would refuse a legitimate
|
|
89
|
+
* write. What the delta is actually checked against is the create schema, applied to the result.
|
|
90
|
+
*
|
|
91
|
+
* `undefined` when there is no shape to partial: a member may be a scalar (a component layer is its
|
|
92
|
+
* element), and there is nothing to name inside it.
|
|
93
|
+
*/
|
|
94
|
+
function deltaShape(schema) {
|
|
95
|
+
if (schema instanceof z.ZodOptional || schema instanceof z.ZodNullable || schema instanceof z.ZodDefault) return deltaShape(unwrapOnce(schema));
|
|
96
|
+
if (schema instanceof z.ZodPipe) return deltaShape(schema.def.in);
|
|
97
|
+
if (schema instanceof z.ZodObject) return partializeShape(schema.shape, /* @__PURE__ */ new Set());
|
|
98
|
+
if (schema instanceof z.ZodUnion || schema instanceof z.ZodDiscriminatedUnion) {
|
|
99
|
+
const out = {};
|
|
100
|
+
const shared = z.unknown().nullable().optional();
|
|
101
|
+
for (const member of schema.options) {
|
|
102
|
+
const fields = deltaShape(member);
|
|
103
|
+
if (!fields) return void 0;
|
|
104
|
+
for (const [key, field] of Object.entries(fields)) out[key] = key in out ? shared : field;
|
|
105
|
+
}
|
|
106
|
+
return out;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
/** One layer of optional/nullable/default off a schema. */
|
|
110
|
+
function unwrapOnce(schema) {
|
|
111
|
+
if (schema instanceof z.ZodDefault) return schema.def.innerType;
|
|
112
|
+
return schema.unwrap();
|
|
113
|
+
}
|
|
114
|
+
/**
|
|
115
|
+
* The update validator — a partial whose keys are field paths ({@link applyPathDelta}).
|
|
116
|
+
*
|
|
117
|
+
* Loose, and that is load-bearing rather than lax: `layers.root.bg` is not a declared field, so a
|
|
118
|
+
* schema that stripped unknown keys (zod's default) would drop every deep write on the floor and
|
|
119
|
+
* report success. What the key names is checked when the delta is applied — the path's head must be a
|
|
120
|
+
* field — and the result of applying it is then validated against the create schema, which is where
|
|
121
|
+
* value types, cross-field checks and coercions all live. So this schema's job is to describe the
|
|
122
|
+
* fields a caller may name and to type the whole-field case; it is deliberately not the gate.
|
|
123
|
+
*/
|
|
124
|
+
function deriveUpdateSchema(schema) {
|
|
125
|
+
const metadata = partializeShape(METADATA, /* @__PURE__ */ new Set());
|
|
126
|
+
return z.looseObject({
|
|
127
|
+
...deltaShape(schema),
|
|
128
|
+
...metadata
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
/** The update (partial) validator for a sub-entity member — {@link deriveUpdateSchema} without the
|
|
132
|
+
* Entity metadata (a layer/prop member isn't an entity, carries no label/description). A member with
|
|
133
|
+
* no shape to name into — a component layer is its element — keeps its own schema: there is no path
|
|
134
|
+
* to write, so an update replaces it. */
|
|
135
|
+
function deriveMemberUpdateSchema(schema) {
|
|
136
|
+
if (schema instanceof z.ZodNullable) return deriveMemberUpdateSchema(schema.unwrap()).nullable();
|
|
137
|
+
const shape = deltaShape(schema);
|
|
138
|
+
return shape ? z.looseObject(shape) : schema;
|
|
139
|
+
}
|
|
140
|
+
/**
|
|
141
|
+
* Whether a name is a field of the thing being written — what {@link pathSegments} asks to decide
|
|
142
|
+
* whether a dotted delta key is an address or one literal key.
|
|
143
|
+
*
|
|
144
|
+
* Liberal by construction: a union contributes every member's keys, and a record contributes all
|
|
145
|
+
* names, because a record's keys are its fields (a component's `layers` bag is addressed by layer
|
|
146
|
+
* name). Metadata counts too, so `label` is namable wherever it is storable. A name this says no to
|
|
147
|
+
* is written as one key, dot and all, which is the safe answer — the create schema then judges it.
|
|
148
|
+
*/
|
|
149
|
+
function declaredField(schema) {
|
|
150
|
+
const names = new Set(Object.keys(METADATA));
|
|
151
|
+
let anyName = false;
|
|
152
|
+
const collect = (from) => {
|
|
153
|
+
if (!from) return;
|
|
154
|
+
if (from instanceof z.ZodOptional || from instanceof z.ZodNullable || from instanceof z.ZodDefault) {
|
|
155
|
+
collect(unwrapOnce(from));
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (from instanceof z.ZodRecord) {
|
|
159
|
+
anyName = true;
|
|
160
|
+
return;
|
|
161
|
+
}
|
|
162
|
+
if (from instanceof z.ZodObject) {
|
|
163
|
+
for (const key of Object.keys(from.shape)) names.add(key);
|
|
164
|
+
return;
|
|
165
|
+
}
|
|
166
|
+
if (from instanceof z.ZodUnion || from instanceof z.ZodDiscriminatedUnion) for (const member of from.options) collect(member);
|
|
167
|
+
};
|
|
168
|
+
collect(schema);
|
|
169
|
+
return (name) => anyName || names.has(name);
|
|
170
|
+
}
|
|
171
|
+
/** The declared field names, in order — hydration and `toJSON` walk these. A union yields
|
|
172
|
+
* the union of every member's keys (discriminant first), so hydration copies whichever
|
|
173
|
+
* fields the stored member actually carries. */
|
|
174
|
+
function fieldKeys(schema) {
|
|
175
|
+
if (schema instanceof z.ZodDiscriminatedUnion) {
|
|
176
|
+
const keys = [];
|
|
177
|
+
for (const member of schema.def.options) for (const key of Object.keys(member.shape)) if (!keys.includes(key)) keys.push(key);
|
|
178
|
+
return keys;
|
|
179
|
+
}
|
|
180
|
+
return Object.keys(schema.shape);
|
|
181
|
+
}
|
|
182
|
+
//#endregion
|
|
183
|
+
export { METADATA_KEYS, declaredField, deriveCreateSchema, deriveMemberUpdateSchema, deriveUpdateSchema, fieldKeys };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Ref } from "./refs.js";
|
|
2
|
+
import { CreateInput, FieldsSchema } from "./field-schema.js";
|
|
3
|
+
import { Authored } from "../authoring.js";
|
|
4
|
+
|
|
5
|
+
//#region src/framework/utils/group.d.ts
|
|
6
|
+
declare const GROUP: unique symbol;
|
|
7
|
+
/**
|
|
8
|
+
* One authored entry for a kind: an item body, a group node, a bare shorthand for the primary field,
|
|
9
|
+
* or a NESTED record whose keys extend the path.
|
|
10
|
+
*
|
|
11
|
+
* Recursive because nesting is. A path is a slash-joined name and a config may spell it either way —
|
|
12
|
+
* `'color/text/primary'` or `color: { text: { primary } }` — so a record of these is admissible at
|
|
13
|
+
* every level, exactly as `register` flattens them.
|
|
14
|
+
*/
|
|
15
|
+
type AuthoredEntry<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<F> | GroupBody<F, G> | Authored | string | number | Ref | NestedEntries<F, G>;
|
|
16
|
+
/**
|
|
17
|
+
* A record of entries under a shared prefix.
|
|
18
|
+
*
|
|
19
|
+
* Its values are entries in their own right, but never a BARE SHORTHAND. That mirrors the flattener,
|
|
20
|
+
* which treats a record as a prefix only when every value is an object — so a string sitting in one
|
|
21
|
+
* is a malformed item either way, and this is what makes the type say so rather than silently
|
|
22
|
+
* reading `{ valuee: '#fff' }` as a nested token named `valuee`.
|
|
23
|
+
*/
|
|
24
|
+
type NestedEntries<F extends FieldsSchema, G extends FieldsSchema> = {
|
|
25
|
+
readonly [key: string]: CreateInput<F> | GroupBody<F, G> | Authored | Ref | NestedEntries<F, G>;
|
|
26
|
+
};
|
|
27
|
+
/** A group node — its own fields, plus the members that live under its path. */
|
|
28
|
+
type GroupBody<F extends FieldsSchema, G extends FieldsSchema> = CreateInput<G> & {
|
|
29
|
+
/** The group's members, keyed by the segment that extends its path. Stating the prefix once is
|
|
30
|
+
* the point: `color: Token.group({ items: { brand } })` rather than `'color/brand'` per entry. */
|
|
31
|
+
readonly items?: Readonly<Record<string, AuthoredEntry<F, G>>>;
|
|
32
|
+
readonly [GROUP]?: true;
|
|
33
|
+
};
|
|
34
|
+
declare function brandGroup<F extends FieldsSchema, G extends FieldsSchema>(meta: GroupBody<F, G>): GroupBody<F, G>;
|
|
35
|
+
declare function isGroupBody(value: unknown): boolean;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { AuthoredEntry, GROUP, GroupBody, brandGroup, isGroupBody };
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
//#region src/framework/utils/group.ts
|
|
2
|
+
const GROUP = Symbol("entity-kit/group");
|
|
3
|
+
function brandGroup(meta) {
|
|
4
|
+
return {
|
|
5
|
+
...meta,
|
|
6
|
+
[GROUP]: true
|
|
7
|
+
};
|
|
8
|
+
}
|
|
9
|
+
function isGroupBody(value) {
|
|
10
|
+
return typeof value === "object" && value !== null && value[GROUP] === true;
|
|
11
|
+
}
|
|
12
|
+
//#endregion
|
|
13
|
+
export { GROUP, brandGroup, isGroupBody };
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
//#region src/framework/utils/package-path.d.ts
|
|
2
|
+
/**
|
|
3
|
+
* A package specifier → the path its `Package` entities live at.
|
|
4
|
+
*
|
|
5
|
+
* **There is no slug. The path IS the module** — `package:@ariakit/react#TooltipAnchor` — the same
|
|
6
|
+
* choice `File` makes for its src, and for the same reason: a name derived from another name is a
|
|
7
|
+
* second copy that can drift, and a derived name has to stay stable against a set that grows.
|
|
8
|
+
*
|
|
9
|
+
* It used to be a slug (`package:ariakit/TooltipAnchor`), computed over the whole import SET so that
|
|
10
|
+
* two specifiers sharing a scope could both qualify away from it. That made a key depend on what else
|
|
11
|
+
* happened to be imported: `@phosphor-icons/core` arriving beside `@phosphor-icons/react` renamed the
|
|
12
|
+
* latter's group and stranded every stored ref that named it. Declaring the groups froze the answer,
|
|
13
|
+
* at the cost of making every consumer restate imports it had already written. A module is a name npm
|
|
14
|
+
* has already made unique, so using it needs neither a set nor a declaration.
|
|
15
|
+
*
|
|
16
|
+
* Lives in the config package because BOTH sides derive from it: the layers schema serializes a
|
|
17
|
+
* native marker to `package:<module>/<name>` at parse, and codegen's collectors key registry entries
|
|
18
|
+
* and `Package` groups the same way at build. One rule — and now one that cannot be computed two
|
|
19
|
+
* ways, because it consults nothing but the specifier in hand.
|
|
20
|
+
*/
|
|
21
|
+
declare const EXPORT_MEMBER = "exports";
|
|
22
|
+
declare function packageName(specifier: string): string;
|
|
23
|
+
/**
|
|
24
|
+
* The stored ref for one export — `package:react-native#Pressable`.
|
|
25
|
+
*
|
|
26
|
+
* The MODULE is the entity and the export is a MEMBER of it, separated by the grammar's own member
|
|
27
|
+
* marker rather than by a `/` and a convention about which segment is which. A `/` cannot do it: an
|
|
28
|
+
* npm specifier contains them (`@ariakit/react`, `motion/react`), so "the last segment is the export"
|
|
29
|
+
* is a guess that `motion/react` and `@phosphor-icons/core` both break — the first is a module that
|
|
30
|
+
* parses as an export called `react`, the second a module that parsed as an export called `core`.
|
|
31
|
+
*
|
|
32
|
+
* The module goes in VERBATIM. `motion/react` and `motion` are different modules even though they are
|
|
33
|
+
* one npm package, and only the exact one regenerates the import the author wrote.
|
|
34
|
+
*/
|
|
35
|
+
declare function packageKey(specifier: string, name: string): string;
|
|
36
|
+
//#endregion
|
|
37
|
+
export { EXPORT_MEMBER, packageKey, packageName };
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
//#region src/framework/utils/package-path.ts
|
|
2
|
+
/**
|
|
3
|
+
* A package specifier → the path its `Package` entities live at.
|
|
4
|
+
*
|
|
5
|
+
* **There is no slug. The path IS the module** — `package:@ariakit/react#TooltipAnchor` — the same
|
|
6
|
+
* choice `File` makes for its src, and for the same reason: a name derived from another name is a
|
|
7
|
+
* second copy that can drift, and a derived name has to stay stable against a set that grows.
|
|
8
|
+
*
|
|
9
|
+
* It used to be a slug (`package:ariakit/TooltipAnchor`), computed over the whole import SET so that
|
|
10
|
+
* two specifiers sharing a scope could both qualify away from it. That made a key depend on what else
|
|
11
|
+
* happened to be imported: `@phosphor-icons/core` arriving beside `@phosphor-icons/react` renamed the
|
|
12
|
+
* latter's group and stranded every stored ref that named it. Declaring the groups froze the answer,
|
|
13
|
+
* at the cost of making every consumer restate imports it had already written. A module is a name npm
|
|
14
|
+
* has already made unique, so using it needs neither a set nor a declaration.
|
|
15
|
+
*
|
|
16
|
+
* Lives in the config package because BOTH sides derive from it: the layers schema serializes a
|
|
17
|
+
* native marker to `package:<module>/<name>` at parse, and codegen's collectors key registry entries
|
|
18
|
+
* and `Package` groups the same way at build. One rule — and now one that cannot be computed two
|
|
19
|
+
* ways, because it consults nothing but the specifier in hand.
|
|
20
|
+
*/
|
|
21
|
+
/**
|
|
22
|
+
* A specifier stripped to the npm package it installs — `@scope/pkg/sub` → `@scope/pkg`.
|
|
23
|
+
*
|
|
24
|
+
* The unit a GROUP is keyed by, because it is the unit a consumer installs: two specifiers reaching
|
|
25
|
+
* into one package are one dependency. The SUBPATH is not lost — it is the key of the `File.imports`
|
|
26
|
+
* entry that reached it. So the two kinds divide the fact: `File` records what the source WROTE,
|
|
27
|
+
* `Package` records what a consumer INSTALLS.
|
|
28
|
+
*
|
|
29
|
+
* This is also what answers "where does the module end and the export begin" in a stored path — a
|
|
30
|
+
* leading `@` means the first two segments, otherwise the first one, which is npm's own rule. An
|
|
31
|
+
* export name cannot contain a `/`, so there is nothing left ambiguous.
|
|
32
|
+
*/
|
|
33
|
+
/** The grammar's member marker, and the FIELD `Package` stores its exports in. Both spelled here so a
|
|
34
|
+
* key and a `memberRef` cannot disagree about the one string that separates a ref's two halves.
|
|
35
|
+
*
|
|
36
|
+
* It is the field name rather than the sub-entity's own name because that is what resolution reads:
|
|
37
|
+
* `ref-integrity`'s `resolves` looks the collection up as `owner[member.slice(0, slash)]`, the same
|
|
38
|
+
* way `component:Input#props/disabled` names the `props` field. */
|
|
39
|
+
const MEMBER = "#";
|
|
40
|
+
const EXPORT_MEMBER = "exports";
|
|
41
|
+
function packageName(specifier) {
|
|
42
|
+
const segments = specifier.split("/");
|
|
43
|
+
return specifier.startsWith("@") ? segments.slice(0, 2).join("/") : segments[0] ?? specifier;
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* The stored ref for one export — `package:react-native#Pressable`.
|
|
47
|
+
*
|
|
48
|
+
* The MODULE is the entity and the export is a MEMBER of it, separated by the grammar's own member
|
|
49
|
+
* marker rather than by a `/` and a convention about which segment is which. A `/` cannot do it: an
|
|
50
|
+
* npm specifier contains them (`@ariakit/react`, `motion/react`), so "the last segment is the export"
|
|
51
|
+
* is a guess that `motion/react` and `@phosphor-icons/core` both break — the first is a module that
|
|
52
|
+
* parses as an export called `react`, the second a module that parsed as an export called `core`.
|
|
53
|
+
*
|
|
54
|
+
* The module goes in VERBATIM. `motion/react` and `motion` are different modules even though they are
|
|
55
|
+
* one npm package, and only the exact one regenerates the import the author wrote.
|
|
56
|
+
*/
|
|
57
|
+
function packageKey(specifier, name) {
|
|
58
|
+
return `package:${specifier}${MEMBER}${name}`;
|
|
59
|
+
}
|
|
60
|
+
//#endregion
|
|
61
|
+
export { EXPORT_MEMBER, packageKey, packageName };
|