@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,132 @@
|
|
|
1
|
+
import { Config } from "./Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/prop-surface.d.ts
|
|
4
|
+
/** What a prop IS — the config's own prop types, and nothing invented. */
|
|
5
|
+
type SurfacePropKind = 'variant' | 'styleProperty' | 'composite' | 'motion' | 'slot' | 'string' | 'number' | 'boolean';
|
|
6
|
+
interface SurfacePropBase {
|
|
7
|
+
readonly name: string;
|
|
8
|
+
readonly required: boolean;
|
|
9
|
+
}
|
|
10
|
+
interface SurfaceVariantProp extends SurfacePropBase {
|
|
11
|
+
readonly kind: 'variant';
|
|
12
|
+
/** The values it offers, as the leaves a consumer authors. */
|
|
13
|
+
readonly values: string[];
|
|
14
|
+
/** An icon LIBRARY the values delegate to, when the domain is the group itself — a surface
|
|
15
|
+
* offers the glyph picker rather than a select over every member. A FACET ref
|
|
16
|
+
* (`icon:phosphor#variants`) stays a plain list: its leaves are the group node's own field
|
|
17
|
+
* values, a menu-sized set. Mirrors {@link SurfaceSlotProp.acceptsIconLibrary}. */
|
|
18
|
+
readonly iconLibrary?: string;
|
|
19
|
+
}
|
|
20
|
+
interface SurfaceStylePropertyProp extends SurfacePropBase {
|
|
21
|
+
readonly kind: 'styleProperty';
|
|
22
|
+
/** The style property this prop writes through. */
|
|
23
|
+
readonly styleProperty: string;
|
|
24
|
+
}
|
|
25
|
+
interface SurfaceCompositeProp extends SurfacePropBase {
|
|
26
|
+
readonly kind: 'composite';
|
|
27
|
+
readonly compositeName: string;
|
|
28
|
+
}
|
|
29
|
+
interface SurfaceScalarProp extends SurfacePropBase {
|
|
30
|
+
readonly kind: 'string' | 'number' | 'boolean' | 'motion';
|
|
31
|
+
}
|
|
32
|
+
interface SurfaceSlotProp extends SurfacePropBase {
|
|
33
|
+
readonly kind: 'slot';
|
|
34
|
+
/** Declared a TEXT surface — content typed in place rather than dropped into. */
|
|
35
|
+
readonly text: boolean;
|
|
36
|
+
/** The layer this routes into, when it targets one. */
|
|
37
|
+
readonly targetLayer?: string;
|
|
38
|
+
/** The prop on that layer's element it arrives as (`children` unless stated). */
|
|
39
|
+
readonly into?: string;
|
|
40
|
+
/** Components this slot may be filled with (`accepts`), as paths. Empty when unconstrained. */
|
|
41
|
+
readonly accepts: string[];
|
|
42
|
+
/** The icon library this slot accepts, when `accepts` names one — the picker offers its glyphs
|
|
43
|
+
* beside any accepted components. The library is the group the glyphs live in; Studio labels it
|
|
44
|
+
* the slot's icon set. */
|
|
45
|
+
readonly acceptsIconLibrary?: string;
|
|
46
|
+
/** What the prop on the other end of the routing is, when this slot targets a layer. Absent for an
|
|
47
|
+
* open slot (content the render places itself). */
|
|
48
|
+
readonly valueKind?: SurfacePropKind;
|
|
49
|
+
/** That prop's own value domain, for the kinds that have one. */
|
|
50
|
+
readonly valueOptions?: string[];
|
|
51
|
+
/** That prop's composite, when it forwards into one. */
|
|
52
|
+
readonly compositeName?: string;
|
|
53
|
+
}
|
|
54
|
+
type SurfaceProp = SurfaceVariantProp | SurfaceStylePropertyProp | SurfaceCompositeProp | SurfaceScalarProp | SurfaceSlotProp;
|
|
55
|
+
/** A prop declaration, as far as this reads it. An index signature because `propValueDomain` takes a
|
|
56
|
+
* declaration as an open record — it resolves the domain off `type`/`value` generically. */
|
|
57
|
+
interface PropDecl extends Record<string, unknown> {
|
|
58
|
+
type?: string;
|
|
59
|
+
value?: unknown;
|
|
60
|
+
required?: boolean;
|
|
61
|
+
target?: unknown;
|
|
62
|
+
into?: string;
|
|
63
|
+
text?: boolean;
|
|
64
|
+
accepts?: unknown;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The prop a slot routes INTO, resolved through the layer it targets: the layer's element is a
|
|
68
|
+
* component, and `into` names one of that component's props. `undefined` when the slot targets
|
|
69
|
+
* nothing, when the layer renders a bare tag (which declares no props), or when the named prop isn't
|
|
70
|
+
* one that component exposes.
|
|
71
|
+
*/
|
|
72
|
+
/**
|
|
73
|
+
* The prop name a route addresses, whichever spelling `into` is in.
|
|
74
|
+
*
|
|
75
|
+
* A NAME between the schema's target split and registration; a MEMBER REF once `storedForward` has
|
|
76
|
+
* minted one (`component:Input#props/disabled`), which is the form that puts the edge in the dependency
|
|
77
|
+
* graph. Readers want the name either way, and `'children'` is the default a content route means.
|
|
78
|
+
*/
|
|
79
|
+
declare function intoName(into: unknown): string;
|
|
80
|
+
/**
|
|
81
|
+
* The prop a route ROUTES INTO — the declaration at `<layer>/<prop>`, reached through the layer's
|
|
82
|
+
* element.
|
|
83
|
+
*
|
|
84
|
+
* `undefined` when the layer's element is a TAG rather than a component: a tag's props are the DOM's and
|
|
85
|
+
* there is no declaration to resolve. That is not a failure, and {@link routesContent} reads it as one
|
|
86
|
+
* of the two answers it needs.
|
|
87
|
+
*/
|
|
88
|
+
declare function routedPropIn(config: Config, layers: Readonly<Record<string, unknown>> | undefined, decl: {
|
|
89
|
+
target?: unknown;
|
|
90
|
+
into?: unknown;
|
|
91
|
+
}): PropDecl | undefined;
|
|
92
|
+
/** {@link routedPropIn} for a component the config already holds. The layers are what the resolution
|
|
93
|
+
* needs; a path is the convenience for a caller that has one instead. */
|
|
94
|
+
declare function routedProp(config: Config, componentPath: string, decl: {
|
|
95
|
+
target?: unknown;
|
|
96
|
+
into?: unknown;
|
|
97
|
+
}): PropDecl | undefined;
|
|
98
|
+
declare function routesContent(config: Config, layers: Readonly<Record<string, unknown>> | undefined, decl: {
|
|
99
|
+
target?: unknown;
|
|
100
|
+
into?: unknown;
|
|
101
|
+
}): boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
104
|
+
*
|
|
105
|
+
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
106
|
+
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
107
|
+
*/
|
|
108
|
+
declare function surfaceProps(config: Config, componentPath: string, /** Forwards already followed, so a routing loop terminates. Internal — callers pass nothing. */
|
|
109
|
+
|
|
110
|
+
seen?: ReadonlySet<string>): SurfaceProp[];
|
|
111
|
+
/** One prop by name, or `undefined` when the component doesn't expose it. */
|
|
112
|
+
declare function surfaceProp(config: Config, componentPath: string, name: string): SurfaceProp | undefined;
|
|
113
|
+
/**
|
|
114
|
+
* Each non-root layer a component forwards to, and the sorted prop names each one receives — the
|
|
115
|
+
* emitter's view, which writes a literal key set per layer. Root is absent on purpose: it takes
|
|
116
|
+
* whatever is left, which every emitter already gives it unconditionally.
|
|
117
|
+
*/
|
|
118
|
+
declare function forwardedLayers(config: Config, componentPath: string): Map<string, string[]>;
|
|
119
|
+
/**
|
|
120
|
+
* Who delivers each name a consumer can pass to this component: the component's own declaration, or
|
|
121
|
+
* the layer whose `forwards` entry exposes it. Root is included, since a picker attributing a claim
|
|
122
|
+
* needs to name root as a claimer; `forwardedLayers` is the emitter's view and leaves root out.
|
|
123
|
+
*/
|
|
124
|
+
interface ForwardClaims {
|
|
125
|
+
/** Names declared in the component's own `props`. A forward of one of these never reaches a consumer. */
|
|
126
|
+
readonly own: ReadonlySet<string>;
|
|
127
|
+
/** Forwarded name → the layer whose entry delivers it. The first entry in key order wins an overlap. */
|
|
128
|
+
readonly forwarded: ReadonlyMap<string, string>;
|
|
129
|
+
}
|
|
130
|
+
declare function forwardClaims(config: Config, componentPath: string): ForwardClaims;
|
|
131
|
+
//#endregion
|
|
132
|
+
export { ForwardClaims, SurfaceCompositeProp, SurfaceProp, SurfacePropKind, SurfaceScalarProp, SurfaceSlotProp, SurfaceStylePropertyProp, SurfaceVariantProp, forwardClaims, forwardedLayers, intoName, routedProp, routedPropIn, routesContent, surfaceProp, surfaceProps };
|
|
@@ -0,0 +1,278 @@
|
|
|
1
|
+
import { isRef, kindOf, memberOf, pathOf } from "./utils/refs.js";
|
|
2
|
+
import { forwardsOf, rootLayerOf } from "../entities/system/element.js";
|
|
3
|
+
import { propValueDomain, resolveComponentProps } from "./projections.js";
|
|
4
|
+
import { Component } from "../entities/system/Component.js";
|
|
5
|
+
//#region src/framework/prop-surface.ts
|
|
6
|
+
/**
|
|
7
|
+
* A component's public API, projected for a surface that has to render a CONTROL per prop.
|
|
8
|
+
*
|
|
9
|
+
* The config states each prop as a declaration keyed by name — its type, and what it delegates its
|
|
10
|
+
* value domain to. A control needs one more thing the declarations only imply: for a SLOT that routes
|
|
11
|
+
* into a layer, *what does the prop on the other end accept?* A `label` slot targeting a Text layer's
|
|
12
|
+
* `children` is a text input; one targeting a Pressable layer's `variant` is a select over that
|
|
13
|
+
* component's variant values. So the routing is resolved here, once, and callers switch on the answer
|
|
14
|
+
* instead of re-walking layers per control — which is the whole reason this is a projection rather
|
|
15
|
+
* than each surface reading `props` itself.
|
|
16
|
+
*
|
|
17
|
+
* Everything else is a straight read: `resolveComponentProps` merges what a component exposes through
|
|
18
|
+
* `forwards`, and `propValueDomain` answers what each prop accepts — including a prop that DELEGATES
|
|
19
|
+
* its domain (an icon prop drawing its names from the icon library rather than copying them in),
|
|
20
|
+
* which is why value lists are never read straight off `value`.
|
|
21
|
+
*/
|
|
22
|
+
/** The tail of a ref, when the value is one. */
|
|
23
|
+
function refPath(value) {
|
|
24
|
+
return isRef(value) ? pathOf(value.__ref) : void 0;
|
|
25
|
+
}
|
|
26
|
+
/** Every ref in an `accepts` declaration (one, or a list). */
|
|
27
|
+
function acceptsRefs(accepts) {
|
|
28
|
+
return (Array.isArray(accepts) ? accepts : [accepts]).filter(isRef).map((ref) => ref.__ref);
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* The icon library a variant's value domain delegates to, when the domain is
|
|
32
|
+
* the GROUP itself (`icon:phosphor` — one leaf per glyph). A facet ref keeps
|
|
33
|
+
* its `#field` marker and is not a library: its leaves are the group node's
|
|
34
|
+
* own field values, which a plain list control serves fine. A ref at one ITEM
|
|
35
|
+
* (`icon:phosphor/StarIcon`) is a single-leaf domain, not a library either.
|
|
36
|
+
*/
|
|
37
|
+
function variantIconLibrary(config, value) {
|
|
38
|
+
if (!isRef(value) || kindOf(value) !== "icon") return void 0;
|
|
39
|
+
if (memberOf(value) !== void 0) return void 0;
|
|
40
|
+
const path = pathOf(value);
|
|
41
|
+
if (config.resolve("icon", path)) return void 0;
|
|
42
|
+
return path;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* The prop a slot routes INTO, resolved through the layer it targets: the layer's element is a
|
|
46
|
+
* component, and `into` names one of that component's props. `undefined` when the slot targets
|
|
47
|
+
* nothing, when the layer renders a bare tag (which declares no props), or when the named prop isn't
|
|
48
|
+
* one that component exposes.
|
|
49
|
+
*/
|
|
50
|
+
/**
|
|
51
|
+
* The prop name a route addresses, whichever spelling `into` is in.
|
|
52
|
+
*
|
|
53
|
+
* A NAME between the schema's target split and registration; a MEMBER REF once `storedForward` has
|
|
54
|
+
* minted one (`component:Input#props/disabled`), which is the form that puts the edge in the dependency
|
|
55
|
+
* graph. Readers want the name either way, and `'children'` is the default a content route means.
|
|
56
|
+
*/
|
|
57
|
+
function intoName(into) {
|
|
58
|
+
if (typeof into === "string") return into;
|
|
59
|
+
if (!isRef(into)) return "children";
|
|
60
|
+
const member = memberOf(into) ?? into.__ref;
|
|
61
|
+
return member.slice(member.indexOf("/") + 1);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* The prop a route ROUTES INTO — the declaration at `<layer>/<prop>`, reached through the layer's
|
|
65
|
+
* element.
|
|
66
|
+
*
|
|
67
|
+
* `undefined` when the layer's element is a TAG rather than a component: a tag's props are the DOM's and
|
|
68
|
+
* there is no declaration to resolve. That is not a failure, and {@link routesContent} reads it as one
|
|
69
|
+
* of the two answers it needs.
|
|
70
|
+
*/
|
|
71
|
+
function routedPropIn(config, layers, decl) {
|
|
72
|
+
const layerKey = refPath(decl.target);
|
|
73
|
+
if (!layerKey) return void 0;
|
|
74
|
+
const target = refPath(layers?.[layerKey]);
|
|
75
|
+
if (!target) return void 0;
|
|
76
|
+
return resolveComponentProps(config, target)[intoName(decl.into)];
|
|
77
|
+
}
|
|
78
|
+
/** {@link routedPropIn} for a component the config already holds. The layers are what the resolution
|
|
79
|
+
* needs; a path is the convenience for a caller that has one instead. */
|
|
80
|
+
function routedProp(config, componentPath, decl) {
|
|
81
|
+
const body = Component.get(config, componentPath)?.toJSON();
|
|
82
|
+
return routedPropIn(config, body?.layers, decl);
|
|
83
|
+
}
|
|
84
|
+
function routesContent(config, layers, decl) {
|
|
85
|
+
const routed = routedPropIn(config, layers, decl);
|
|
86
|
+
if (routed) return routed.type === "slot";
|
|
87
|
+
return refPath(decl.target) !== void 0 && intoName(decl.into) === "children";
|
|
88
|
+
}
|
|
89
|
+
function slotProp(config, componentPath, name, decl) {
|
|
90
|
+
const refs = acceptsRefs(decl.accepts);
|
|
91
|
+
const icons = refs.find((ref) => kindOf(ref) === "icon");
|
|
92
|
+
const routed = routedProp(config, componentPath, decl);
|
|
93
|
+
const routedKind = routed?.type;
|
|
94
|
+
const targetLayer = refPath(decl.target);
|
|
95
|
+
const routesIntoText = routed?.type === "slot" && routed.text === true;
|
|
96
|
+
return {
|
|
97
|
+
name,
|
|
98
|
+
kind: "slot",
|
|
99
|
+
required: decl.required === true,
|
|
100
|
+
text: decl.text === true || routesIntoText,
|
|
101
|
+
...targetLayer ? {
|
|
102
|
+
targetLayer,
|
|
103
|
+
into: decl.into ?? "children"
|
|
104
|
+
} : {},
|
|
105
|
+
accepts: refs.filter((ref) => kindOf(ref) === "component").map((ref) => pathOf(ref)),
|
|
106
|
+
...icons ? { acceptsIconLibrary: pathOf(icons) } : {},
|
|
107
|
+
...routedKind ? { valueKind: routedKind } : {},
|
|
108
|
+
...routed ? { valueOptions: propValueDomain(config, routed)?.leaves } : {},
|
|
109
|
+
...routedKind === "composite" ? { compositeName: refPath(routed?.value) } : {}
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Every prop a component exposes, in declaration order, projected for a control surface.
|
|
114
|
+
*
|
|
115
|
+
* A `motion` prop is included as a scalar so it can't silently disappear from a surface that lists
|
|
116
|
+
* what a component accepts; a caller with no editor for it can fall back to a generic one.
|
|
117
|
+
*/
|
|
118
|
+
function surfaceProps(config, componentPath, seen = /* @__PURE__ */ new Set()) {
|
|
119
|
+
const declared = resolveComponentProps(config, componentPath);
|
|
120
|
+
const layers = (Component.get(config, componentPath)?.toJSON())?.layers;
|
|
121
|
+
const props = [];
|
|
122
|
+
for (const [name, decl] of Object.entries(declared)) {
|
|
123
|
+
const required = decl.required === true;
|
|
124
|
+
if (decl.type === "forward") {
|
|
125
|
+
if (routesContent(config, layers, decl)) {
|
|
126
|
+
props.push(slotProp(config, componentPath, name, decl));
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
129
|
+
const routed = boundProp(config, layers, decl, seen);
|
|
130
|
+
if (routed) props.push({
|
|
131
|
+
...routed,
|
|
132
|
+
name,
|
|
133
|
+
required
|
|
134
|
+
});
|
|
135
|
+
continue;
|
|
136
|
+
}
|
|
137
|
+
if (decl.type === "slot") {
|
|
138
|
+
props.push(slotProp(config, componentPath, name, decl));
|
|
139
|
+
continue;
|
|
140
|
+
}
|
|
141
|
+
if (decl.type === "variant") {
|
|
142
|
+
const iconLibrary = variantIconLibrary(config, decl.value);
|
|
143
|
+
props.push({
|
|
144
|
+
name,
|
|
145
|
+
kind: "variant",
|
|
146
|
+
required,
|
|
147
|
+
values: propValueDomain(config, decl)?.leaves ?? [],
|
|
148
|
+
...iconLibrary !== void 0 ? { iconLibrary } : {}
|
|
149
|
+
});
|
|
150
|
+
continue;
|
|
151
|
+
}
|
|
152
|
+
if (decl.type === "styleProperty") {
|
|
153
|
+
const styleProperty = refPath(decl.value);
|
|
154
|
+
if (!styleProperty) continue;
|
|
155
|
+
props.push({
|
|
156
|
+
name,
|
|
157
|
+
kind: "styleProperty",
|
|
158
|
+
required,
|
|
159
|
+
styleProperty
|
|
160
|
+
});
|
|
161
|
+
continue;
|
|
162
|
+
}
|
|
163
|
+
if (decl.type === "composite") {
|
|
164
|
+
const compositeName = refPath(decl.value);
|
|
165
|
+
if (!compositeName) continue;
|
|
166
|
+
props.push({
|
|
167
|
+
name,
|
|
168
|
+
kind: "composite",
|
|
169
|
+
required,
|
|
170
|
+
compositeName
|
|
171
|
+
});
|
|
172
|
+
continue;
|
|
173
|
+
}
|
|
174
|
+
if (decl.type === "string" || decl.type === "number" || decl.type === "boolean" || decl.type === "motion") props.push({
|
|
175
|
+
name,
|
|
176
|
+
kind: decl.type,
|
|
177
|
+
required
|
|
178
|
+
});
|
|
179
|
+
}
|
|
180
|
+
return props;
|
|
181
|
+
}
|
|
182
|
+
/**
|
|
183
|
+
* The prop a forward routes to, resolved as a surface prop of its own.
|
|
184
|
+
*
|
|
185
|
+
* `seen` guards a forward that routes to a forward that routes back: the chain is data, so nothing
|
|
186
|
+
* stops an author writing a loop, and the surface is read on every panel render.
|
|
187
|
+
*/
|
|
188
|
+
function boundProp(config, layers, decl, seen) {
|
|
189
|
+
const propName = intoName(decl.into);
|
|
190
|
+
const target = isRef(decl.into) ? pathOf(decl.into) : refPath(layers?.[refPath(decl.target) ?? ""]);
|
|
191
|
+
if (!target) return void 0;
|
|
192
|
+
const key = `${target}#${propName}`;
|
|
193
|
+
if (seen.has(key)) return void 0;
|
|
194
|
+
return surfaceProps(config, target, new Set([...seen, key])).find((prop) => prop.name === propName);
|
|
195
|
+
}
|
|
196
|
+
/** One prop by name, or `undefined` when the component doesn't expose it. */
|
|
197
|
+
function surfaceProp(config, componentPath, name) {
|
|
198
|
+
return surfaceProps(config, componentPath).find((prop) => prop.name === name);
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* The one precedence walk behind {@link forwardedLayers} and {@link forwardClaims}: every name a
|
|
202
|
+
* `forwards` entry exposes, attributed to the layer that delivers it.
|
|
203
|
+
*
|
|
204
|
+
* The other half of prop routing. {@link surfaceProps} answers what a prop IS by resolving a forward
|
|
205
|
+
* THROUGH to the declaration on the far end; this answers the inverse — given a layer, which of the
|
|
206
|
+
* call site's props land on it. An emitter needs that to write a literal key set per layer, and a
|
|
207
|
+
* design surface needs it to say which layer an edit will actually reach.
|
|
208
|
+
*
|
|
209
|
+
* Two precedence rules, and both are failure modes somebody has already paid for:
|
|
210
|
+
*
|
|
211
|
+
* - **Own props beat every forward, tombstones included.** A tombstone means the prop is declared
|
|
212
|
+
* GONE, not merely undeclared; treating it as absent routed the dropped prop to an inner layer at
|
|
213
|
+
* runtime even though every config projection agreed it did not exist.
|
|
214
|
+
* - **Among forwards, the first entry wins.** Validation rejects overlaps on write, but a later
|
|
215
|
+
* rename or an added prop can create one without rewriting this component, so the total
|
|
216
|
+
* resolution is implemented here rather than assumed.
|
|
217
|
+
*
|
|
218
|
+
* Root claims its forwarded names like any other layer, so a later layer cannot also receive one when
|
|
219
|
+
* an overlap appears after validation.
|
|
220
|
+
*
|
|
221
|
+
* Lives here because prop routing is the config's to answer — the web and native emitters each had
|
|
222
|
+
* their own copy of this walk, and two copies of a precedence rule is two chances for a prop to reach
|
|
223
|
+
* a different layer depending on which platform you built for.
|
|
224
|
+
*/
|
|
225
|
+
function computeForwardClaims(config, componentPath) {
|
|
226
|
+
const body = Component.get(config, componentPath)?.toJSON();
|
|
227
|
+
const own = /* @__PURE__ */ new Set();
|
|
228
|
+
const forwarded = /* @__PURE__ */ new Map();
|
|
229
|
+
if (!body) return {
|
|
230
|
+
own,
|
|
231
|
+
forwarded,
|
|
232
|
+
rootLayer: void 0
|
|
233
|
+
};
|
|
234
|
+
const { layers = {}, props = {}, forwards } = body;
|
|
235
|
+
const [rootLayer] = rootLayerOf(layers);
|
|
236
|
+
for (const name of Object.keys(props)) own.add(name);
|
|
237
|
+
for (const [layer, entry] of Object.entries(forwardsOf({ forwards }))) {
|
|
238
|
+
const element = layers[layer];
|
|
239
|
+
if (!isRef(element)) continue;
|
|
240
|
+
const exposed = resolveComponentProps(config, pathOf(element.__ref));
|
|
241
|
+
const names = entry === "*" ? Object.keys(exposed) : (Array.isArray(entry) ? entry : []).map((ref) => isRef(ref) ? memberOf(ref)?.split("/").pop() : void 0).filter((name) => !!name && name in exposed);
|
|
242
|
+
for (const name of names) {
|
|
243
|
+
if (own.has(name) || forwarded.has(name)) continue;
|
|
244
|
+
forwarded.set(name, layer);
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
own,
|
|
249
|
+
forwarded,
|
|
250
|
+
rootLayer
|
|
251
|
+
};
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Each non-root layer a component forwards to, and the sorted prop names each one receives — the
|
|
255
|
+
* emitter's view, which writes a literal key set per layer. Root is absent on purpose: it takes
|
|
256
|
+
* whatever is left, which every emitter already gives it unconditionally.
|
|
257
|
+
*/
|
|
258
|
+
function forwardedLayers(config, componentPath) {
|
|
259
|
+
const { forwarded, rootLayer } = computeForwardClaims(config, componentPath);
|
|
260
|
+
const out = /* @__PURE__ */ new Map();
|
|
261
|
+
for (const [name, layer] of forwarded) {
|
|
262
|
+
if (layer === rootLayer) continue;
|
|
263
|
+
const names = out.get(layer);
|
|
264
|
+
if (names) names.push(name);
|
|
265
|
+
else out.set(layer, [name]);
|
|
266
|
+
}
|
|
267
|
+
for (const names of out.values()) names.sort();
|
|
268
|
+
return out;
|
|
269
|
+
}
|
|
270
|
+
function forwardClaims(config, componentPath) {
|
|
271
|
+
const { own, forwarded } = computeForwardClaims(config, componentPath);
|
|
272
|
+
return {
|
|
273
|
+
own,
|
|
274
|
+
forwarded
|
|
275
|
+
};
|
|
276
|
+
}
|
|
277
|
+
//#endregion
|
|
278
|
+
export { forwardClaims, forwardedLayers, intoName, routedProp, routedPropIn, routesContent, surfaceProp, surfaceProps };
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
import { Ref } from "./utils/refs.js";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/ref-graph.d.ts
|
|
4
|
+
/** One entity to index: its own `kind:path` ref, and the data to harvest refs from. */
|
|
5
|
+
interface RefGraphEntry {
|
|
6
|
+
readonly ref: string;
|
|
7
|
+
readonly data: unknown;
|
|
8
|
+
/**
|
|
9
|
+
* Edges this entity's data implies by NAME rather than by ref — a style bag keyed `bg` depends on
|
|
10
|
+
* `style-property:bg`, and no `{ __ref }` says so.
|
|
11
|
+
*
|
|
12
|
+
* Supplied by the caller (a kind declares how to read its own names — see `EntityKind.nameEdges`)
|
|
13
|
+
* because nothing generic can find identity in a KEY. Kept a PURE function of the entity's own
|
|
14
|
+
* data, which is what lets these edges ride the same incremental update as the ref-borne ones: an
|
|
15
|
+
* edge that needed another kind's state to compute would go stale whenever that state moved and
|
|
16
|
+
* this entity didn't.
|
|
17
|
+
*/
|
|
18
|
+
readonly extra?: readonly string[];
|
|
19
|
+
}
|
|
20
|
+
interface TraverseOptions {
|
|
21
|
+
/** Follow chains rather than stopping at direct edges (default false). */
|
|
22
|
+
readonly transitive?: boolean;
|
|
23
|
+
}
|
|
24
|
+
/** A node to ask about: the entity's own ref (`Token.ref('color/brand')`) or its string form.
|
|
25
|
+
* Taking the ref itself means a caller names an entity the way it names one everywhere else. */
|
|
26
|
+
type RefTarget = string | Ref;
|
|
27
|
+
interface RefGraph {
|
|
28
|
+
/** Entities that point AT `target` — what breaks if it changes or goes away. */
|
|
29
|
+
dependents(target: RefTarget, opts?: TraverseOptions): string[];
|
|
30
|
+
/** Entities `target` points at — what it needs in order to resolve. */
|
|
31
|
+
dependencies(target: RefTarget, opts?: TraverseOptions): string[];
|
|
32
|
+
/**
|
|
33
|
+
* The shortest dependency chain `from` → … → `to`, inclusive of both ends, or `undefined` when
|
|
34
|
+
* `from` doesn't reach `to`. This is what turns "42 things affected" into a sentence a person can
|
|
35
|
+
* act on: `token:color/brand → modifier:dark → mode:colorMode/dark`.
|
|
36
|
+
*/
|
|
37
|
+
path(from: RefTarget, to: RefTarget): string[] | undefined;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* The raw two-way index behind a {@link RefGraph} — separated from the query facade so it can be
|
|
41
|
+
* carried on an immutable `Snapshot` and UPDATED for the handful of entities a patch touched,
|
|
42
|
+
* instead of rebuilt by a full pass over every item on each mutation.
|
|
43
|
+
*/
|
|
44
|
+
interface RefIndex {
|
|
45
|
+
/** `ref` → the refs it points at. */
|
|
46
|
+
readonly out: ReadonlyMap<string, ReadonlySet<string>>;
|
|
47
|
+
/** `ref` → the refs pointing at it. */
|
|
48
|
+
readonly incoming: ReadonlyMap<string, ReadonlySet<string>>;
|
|
49
|
+
}
|
|
50
|
+
/** One entity's edges changing — `data: undefined` means the entity went away. */
|
|
51
|
+
interface RefIndexChange {
|
|
52
|
+
readonly ref: string;
|
|
53
|
+
readonly data: unknown | undefined;
|
|
54
|
+
/** Name-borne edges for the new data — see {@link RefGraphEntry.extra}. */
|
|
55
|
+
readonly extra?: readonly string[];
|
|
56
|
+
}
|
|
57
|
+
/** Index `entries` in both directions. Pure — callers memoize (see `Snapshot.refs`). */
|
|
58
|
+
declare function buildRefIndex(entries: readonly RefGraphEntry[], linkKinds?: readonly string[], singletonKinds?: readonly string[]): RefIndex;
|
|
59
|
+
/**
|
|
60
|
+
* Re-index only the entities in `changes`, returning a new index that shares nothing mutable with
|
|
61
|
+
* the old one. The top-level maps are copied per CALL (a batch), and only the edge sets actually
|
|
62
|
+
* touched are copied — so the deep `collectRefs` walk, which is the expensive part, runs for the
|
|
63
|
+
* changed entities alone rather than for the whole config.
|
|
64
|
+
*/
|
|
65
|
+
declare function updateRefIndex(index: RefIndex, changes: readonly RefIndexChange[], linkKinds?: readonly string[], singletonKinds?: readonly string[]): RefIndex;
|
|
66
|
+
/** The query facade over a built index — the shape every consumer asks questions through. */
|
|
67
|
+
declare function refGraphOf(index: RefIndex): RefGraph;
|
|
68
|
+
/** Build and query in one step — for a caller with no snapshot to carry the index on. */
|
|
69
|
+
declare function buildRefGraph(entries: readonly RefGraphEntry[]): RefGraph;
|
|
70
|
+
//#endregion
|
|
71
|
+
export { RefGraph, RefGraphEntry, RefIndex, RefIndexChange, RefTarget, TraverseOptions, buildRefGraph, buildRefIndex, refGraphOf, updateRefIndex };
|
|
@@ -0,0 +1,158 @@
|
|
|
1
|
+
import { collectRefs, entityRefOf, isRef, kindOf, singletonRef, sourceOf } from "./utils/refs.js";
|
|
2
|
+
//#region src/framework/ref-graph.ts
|
|
3
|
+
/**
|
|
4
|
+
* The reference graph — every `{ __ref }` in the config, indexed both ways.
|
|
5
|
+
*
|
|
6
|
+
* `collectRefs` already harvests an entity's outgoing edges generically, so the graph needs no
|
|
7
|
+
* per-entity wiring; this just runs it over every item once and keeps both directions. That one
|
|
8
|
+
* index answers the questions each surface asks separately today: what breaks if I delete this
|
|
9
|
+
* (dependents), what does this pull in (dependencies), and — because renames and deletes have to be
|
|
10
|
+
* explained, not just counted — the CHAIN between two entities.
|
|
11
|
+
*
|
|
12
|
+
* Traversal is transitive on request: an edge chain like `token → modifier → mode` is the norm once
|
|
13
|
+
* an entity can point at another that points on, so "which tokens vary in dark mode" is a closure
|
|
14
|
+
* question, not a one-hop one.
|
|
15
|
+
*
|
|
16
|
+
* A MEMBER ref (`component:Pressable#props/gap`) is indexed under both its own form and its
|
|
17
|
+
* entity's, so a lookup by either resolves; traversal normalizes to the entity, since only entities
|
|
18
|
+
* have data to walk on from.
|
|
19
|
+
*/
|
|
20
|
+
/** A target's string form — the key both indexes are built on. */
|
|
21
|
+
const key = (target) => isRef(target) ? target.__ref : target;
|
|
22
|
+
/** The refs `data` points at plus any name-borne ones, minus self-references (never a dependency). */
|
|
23
|
+
function edgesOf(ref, data, extra = [], linkKinds = [], singletonKinds = []) {
|
|
24
|
+
const collected = collectRefs(data);
|
|
25
|
+
const targets = new Set(collected);
|
|
26
|
+
if (singletonKinds.length > 0) for (const target of collected) {
|
|
27
|
+
if (!singletonKinds.includes(kindOf(target))) continue;
|
|
28
|
+
const canonical = singletonRef(target);
|
|
29
|
+
if (canonical === target) continue;
|
|
30
|
+
targets.add(entityRefOf(canonical));
|
|
31
|
+
targets.add(canonical);
|
|
32
|
+
}
|
|
33
|
+
if (linkKinds.length > 0) for (const target of collected) {
|
|
34
|
+
const slug = sourceOf(target);
|
|
35
|
+
if (slug === void 0) continue;
|
|
36
|
+
for (const kind of linkKinds) targets.add(`${kind}:${slug}`);
|
|
37
|
+
}
|
|
38
|
+
for (const target of extra) targets.add(target);
|
|
39
|
+
targets.delete(ref);
|
|
40
|
+
return targets;
|
|
41
|
+
}
|
|
42
|
+
function link(index, from, to) {
|
|
43
|
+
const set = index.get(from) ?? /* @__PURE__ */ new Set();
|
|
44
|
+
set.add(to);
|
|
45
|
+
index.set(from, set);
|
|
46
|
+
}
|
|
47
|
+
/** Index `entries` in both directions. Pure — callers memoize (see `Snapshot.refs`). */
|
|
48
|
+
function buildRefIndex(entries, linkKinds = [], singletonKinds = []) {
|
|
49
|
+
const out = /* @__PURE__ */ new Map();
|
|
50
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
51
|
+
for (const { ref, data, extra } of entries) for (const target of edgesOf(ref, data, extra, linkKinds, singletonKinds)) {
|
|
52
|
+
link(out, ref, target);
|
|
53
|
+
link(incoming, target, ref);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
out,
|
|
57
|
+
incoming
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Re-index only the entities in `changes`, returning a new index that shares nothing mutable with
|
|
62
|
+
* the old one. The top-level maps are copied per CALL (a batch), and only the edge sets actually
|
|
63
|
+
* touched are copied — so the deep `collectRefs` walk, which is the expensive part, runs for the
|
|
64
|
+
* changed entities alone rather than for the whole config.
|
|
65
|
+
*/
|
|
66
|
+
function updateRefIndex(index, changes, linkKinds = [], singletonKinds = []) {
|
|
67
|
+
if (changes.length === 0) return index;
|
|
68
|
+
const out = /* @__PURE__ */ new Map();
|
|
69
|
+
for (const [node, set] of index.out) out.set(node, set);
|
|
70
|
+
const incoming = /* @__PURE__ */ new Map();
|
|
71
|
+
for (const [node, set] of index.incoming) incoming.set(node, set);
|
|
72
|
+
/** Copy-on-write a single edge set, so sets shared with the previous index are never mutated. */
|
|
73
|
+
const mutable = (map, node) => {
|
|
74
|
+
const next = new Set(map.get(node));
|
|
75
|
+
map.set(node, next);
|
|
76
|
+
return next;
|
|
77
|
+
};
|
|
78
|
+
for (const { ref, data, extra } of changes) {
|
|
79
|
+
for (const target of index.out.get(ref) ?? []) {
|
|
80
|
+
const back = mutable(incoming, target);
|
|
81
|
+
back.delete(ref);
|
|
82
|
+
if (back.size === 0) incoming.delete(target);
|
|
83
|
+
}
|
|
84
|
+
out.delete(ref);
|
|
85
|
+
if (data === void 0) continue;
|
|
86
|
+
const targets = edgesOf(ref, data, extra, linkKinds, singletonKinds);
|
|
87
|
+
if (targets.size === 0) continue;
|
|
88
|
+
out.set(ref, targets);
|
|
89
|
+
for (const target of targets) mutable(incoming, target).add(ref);
|
|
90
|
+
}
|
|
91
|
+
return {
|
|
92
|
+
out,
|
|
93
|
+
incoming
|
|
94
|
+
};
|
|
95
|
+
}
|
|
96
|
+
/** The query facade over a built index — the shape every consumer asks questions through. */
|
|
97
|
+
function refGraphOf(index) {
|
|
98
|
+
const { out, incoming } = index;
|
|
99
|
+
/** Outgoing edges of a node — a member ref has none of its own, so read its entity's. */
|
|
100
|
+
const edgesOut = (node) => out.get(node) ?? out.get(entityRefOf(node));
|
|
101
|
+
const walk = (start, step) => {
|
|
102
|
+
const seen = /* @__PURE__ */ new Set();
|
|
103
|
+
const queue = [start];
|
|
104
|
+
while (queue.length) {
|
|
105
|
+
const node = queue.shift();
|
|
106
|
+
for (const next of step(node) ?? []) {
|
|
107
|
+
if (seen.has(next)) continue;
|
|
108
|
+
seen.add(next);
|
|
109
|
+
queue.push(next);
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
seen.delete(start);
|
|
113
|
+
return [...seen];
|
|
114
|
+
};
|
|
115
|
+
return {
|
|
116
|
+
dependents(target, opts) {
|
|
117
|
+
const node = key(target);
|
|
118
|
+
if (!opts?.transitive) return [...incoming.get(node) ?? []];
|
|
119
|
+
return walk(node, (at) => incoming.get(at));
|
|
120
|
+
},
|
|
121
|
+
dependencies(target, opts) {
|
|
122
|
+
const node = key(target);
|
|
123
|
+
if (!opts?.transitive) return [...edgesOut(node) ?? []];
|
|
124
|
+
return walk(node, edgesOut);
|
|
125
|
+
},
|
|
126
|
+
path(fromTarget, toTarget) {
|
|
127
|
+
const from = key(fromTarget);
|
|
128
|
+
const to = key(toTarget);
|
|
129
|
+
if (from === to) return [from];
|
|
130
|
+
const cameFrom = new Map([[from, from]]);
|
|
131
|
+
const queue = [from];
|
|
132
|
+
while (queue.length) {
|
|
133
|
+
const node = queue.shift();
|
|
134
|
+
for (const next of edgesOut(node) ?? []) {
|
|
135
|
+
if (cameFrom.has(next)) continue;
|
|
136
|
+
cameFrom.set(next, node);
|
|
137
|
+
if (next === to) {
|
|
138
|
+
const chain = [next];
|
|
139
|
+
let step = node;
|
|
140
|
+
while (step !== from) {
|
|
141
|
+
chain.unshift(step);
|
|
142
|
+
step = cameFrom.get(step);
|
|
143
|
+
}
|
|
144
|
+
chain.unshift(from);
|
|
145
|
+
return chain;
|
|
146
|
+
}
|
|
147
|
+
queue.push(next);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
}
|
|
153
|
+
/** Build and query in one step — for a caller with no snapshot to carry the index on. */
|
|
154
|
+
function buildRefGraph(entries) {
|
|
155
|
+
return refGraphOf(buildRefIndex(entries));
|
|
156
|
+
}
|
|
157
|
+
//#endregion
|
|
158
|
+
export { buildRefGraph, buildRefIndex, refGraphOf, updateRefIndex };
|