@yahoo/uds-create-config 2.45.0 → 3.0.1
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,194 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/utils/refs.d.ts
|
|
4
|
+
interface Ref {
|
|
5
|
+
readonly __ref: string;
|
|
6
|
+
}
|
|
7
|
+
/** A ref as the authoring API returns it. The method is non-enumerable, so an ordinary ref remains
|
|
8
|
+
* exactly `{ __ref }` in JSON and anywhere that walks its data. Calling it produces the explicit
|
|
9
|
+
* wire value below: a base ref plus the sparse fields this config owns. */
|
|
10
|
+
type ExtendableRef<Delta extends Record<string, unknown>> = Ref & {
|
|
11
|
+
extend(delta: Delta): ExtendedRef<Delta>;
|
|
12
|
+
};
|
|
13
|
+
/** A linked entity plus the sparse local fields layered over it. `extend` is data here, not the
|
|
14
|
+
* authoring method: this is the value stored by Config after `.extend(delta)` is called. */
|
|
15
|
+
interface ExtendedRef<Delta extends Record<string, unknown> = Record<string, unknown>> extends Ref {
|
|
16
|
+
readonly extend: Delta;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Whether `path` can be an entity's own path — the invariant {@link splitSource} rests on, so it is
|
|
20
|
+
* stated next to it.
|
|
21
|
+
*
|
|
22
|
+
* An `@` is legal only as the first character, where it opens an npm scope: `package:@ariakit/react`
|
|
23
|
+
* is that package, and `package:@yahoo/uds-create-config` is this one. Anywhere else it reads as the
|
|
24
|
+
* source marker, and the split is what every provenance surface believes.
|
|
25
|
+
*
|
|
26
|
+
* Without this, a legitimately-named entity misparses in silence. A token called `1@2x` under `size`
|
|
27
|
+
* is a plausible name for a retina scale and was storable, and `token:size/1@2x` then reports its path
|
|
28
|
+
* as `size/1` and invents a source called `2x` — which paints nothing (`renderStyleValue` takes its
|
|
29
|
+
* `if (!source) return ''` escape and the declaration vanishes), reports a false dangling ref naming a
|
|
30
|
+
* source that does not exist, and marks the item borrowed on every provenance surface. Nothing throws.
|
|
31
|
+
*
|
|
32
|
+
* Checked where a path becomes an identity — a create, a rename's target, an authored entry — and
|
|
33
|
+
* deliberately not on reads, so an existing bad path stays addressable and, more to the point,
|
|
34
|
+
* deletable.
|
|
35
|
+
*/
|
|
36
|
+
declare function isEntityPath(path: string): boolean;
|
|
37
|
+
/** What a refused path should say, in one place, so a create, a rename and a register word it alike. */
|
|
38
|
+
declare const ENTITY_PATH_MESSAGE = "An entity path may not contain \"@\" except as a leading npm scope \u2014 \"@\" marks the source a ref is drawn from, so a path carrying one cannot be told apart from a borrowed address.";
|
|
39
|
+
/** A ref's parts. */
|
|
40
|
+
interface RefParts {
|
|
41
|
+
readonly kind: string;
|
|
42
|
+
readonly source: string | undefined;
|
|
43
|
+
/** without the source — `pathOf`'s answer. */
|
|
44
|
+
readonly path: string;
|
|
45
|
+
/** with the source, when there is one — the form an authored value and an emitted union spell,
|
|
46
|
+
* because a string in value position has nowhere to put a second argument. */
|
|
47
|
+
readonly qualifiedPath: string;
|
|
48
|
+
readonly member: string | undefined;
|
|
49
|
+
/** whether a `kind:` marker was present — without one, `kind` and `path` are both the whole
|
|
50
|
+
* string, and each caller reads the one it means. */
|
|
51
|
+
readonly marked: boolean;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* `kind:path[@source][#member]`, split — the one place a ref is read. This is the ref spelling of the
|
|
55
|
+
* address grammar written down whole in `framework/config-op.ts`.
|
|
56
|
+
*
|
|
57
|
+
* Every accessor below goes through this, and so does anything outside this file that needs a part of
|
|
58
|
+
* a ref. Code that slices at `indexOf(':')` or tests `startsWith('token:')` has its own copy of the
|
|
59
|
+
* grammar, which means the grammar cannot move without hunting for the copies — and a copy that is
|
|
60
|
+
* subtly wrong (a prefix test that a sourced ref fails) is silent.
|
|
61
|
+
*/
|
|
62
|
+
declare function splitRef(target: string | Ref): RefParts;
|
|
63
|
+
/**
|
|
64
|
+
* A reference to another entity: `ref('token', 'color/brand')`. Resolution is prefix-or-leaf against
|
|
65
|
+
* the flat store.
|
|
66
|
+
*
|
|
67
|
+
* With a `source` it points into a linked system instead — `ref('token', 'color/brand', 'yahoo-os')`.
|
|
68
|
+
* That is the whole of what a per-entity link marker used to record: the kind is the ref's kind and
|
|
69
|
+
* the source key is its path, while the version lives once on the pin rather than being repeated on
|
|
70
|
+
* every linked entity.
|
|
71
|
+
*/
|
|
72
|
+
declare function ref(kind: string, path: string, source?: string): Ref;
|
|
73
|
+
/** A reference to one member of an entity's sub-entity collection — a component's prop, a layer:
|
|
74
|
+
* `memberRef('component', 'Pressable', 'props', 'gap')` → `component:Pressable#props/gap`. A
|
|
75
|
+
* `source` qualifies the entity the member is reached through. */
|
|
76
|
+
declare function memberRef(kind: string, path: string, sub: string, member: string, source?: string): Ref;
|
|
77
|
+
/** The entity half of any ref — a plain entity ref is itself. This is the form the dependency
|
|
78
|
+
* graph and kind-narrowing speak, so a member ref participates in both unchanged. */
|
|
79
|
+
declare function entityRefOf(target: string): string;
|
|
80
|
+
/** The member half (`props/gap`), or `undefined` for a plain entity ref. Takes the ref itself or its
|
|
81
|
+
* string form, like {@link pathOf} / {@link kindOf} / {@link sourceOf}. */
|
|
82
|
+
declare function memberOf(target: string | Ref): string | undefined;
|
|
83
|
+
/** The path of the entity a ref points at — kind, source and any member stripped, so a member ref
|
|
84
|
+
* resolves to the item that contains it (`component:buttons/Primary#props/gap` → `buttons/Primary`)
|
|
85
|
+
* and a linked ref yields the path as its source spells it (`token:color/brand@yahoo-os` →
|
|
86
|
+
* `color/brand`). Takes the ref itself or its string form, so a caller holding a ref field never
|
|
87
|
+
* spells `__ref`. */
|
|
88
|
+
declare function pathOf(target: string | Ref): string;
|
|
89
|
+
/** The source half — the link slug a ref points through, or `undefined` when it points at something
|
|
90
|
+
* in this config. This is the one question that distinguishes a linked entity from a local one, and
|
|
91
|
+
* it replaces reading a per-entity provenance marker. */
|
|
92
|
+
declare function sourceOf(target: string | Ref): string | undefined;
|
|
93
|
+
/** The kind a ref points at (`component:buttons/Primary#props/gap` → `component`) — the twin of
|
|
94
|
+
* {@link pathOf}, so a consumer holding a `kind:path` string (a `dependentsOf` result) never splits
|
|
95
|
+
* it by hand. Takes the ref itself or its string form. */
|
|
96
|
+
declare function kindOf(target: string | Ref): string;
|
|
97
|
+
/** The zod schema of a ref value — used via {@link orRef} so a field never spells the
|
|
98
|
+
* `{ __ref }` shape by hand. `.meta({ ref: true })` marks it as a ref for any consumer (JSON
|
|
99
|
+
* Schema, an authoring UI) — this generic form carries no target kind (use an entity as the field
|
|
100
|
+
* to bake one in). */
|
|
101
|
+
declare const refSchema: z.ZodObject<{
|
|
102
|
+
__ref: z.ZodString;
|
|
103
|
+
}, z.core.$strip>;
|
|
104
|
+
/** Widen a field's value type to also accept a ref: `value: orRef(z.string())`. */
|
|
105
|
+
declare function orRef<T extends z.ZodTypeAny>(schema: T): z.ZodUnion<readonly [T, z.ZodObject<{
|
|
106
|
+
__ref: z.ZodString;
|
|
107
|
+
}, z.core.$strip>]>;
|
|
108
|
+
declare function isRef(value: unknown): value is Ref;
|
|
109
|
+
/** Whether a ref is the stored result of `.extend(delta)`. Kept separate from {@link isRef}: every
|
|
110
|
+
* existing ref consumer should continue to see the base pointer, while Config is the place that
|
|
111
|
+
* gives the sibling delta its merge semantics. */
|
|
112
|
+
declare function isExtendedRef(value: unknown): value is ExtendedRef;
|
|
113
|
+
/**
|
|
114
|
+
* The key marking a row the build minted rather than a person authored.
|
|
115
|
+
*
|
|
116
|
+
* A link declares what it took; the rows for everything it brings are made by the build, at the paths
|
|
117
|
+
* the source spells them, so they are stored — `list`, the rename gate and every emitter reach them
|
|
118
|
+
* on the way past — without ever having been written down. This is the one thing that tells the two
|
|
119
|
+
* apart, and three readers turn on it: `uds pull` skips a minted row, a write to one lands on the
|
|
120
|
+
* source's `options` instead of the row (`Config.apply`'s update handler), and a serialize keeps it
|
|
121
|
+
* distinguishable rather than laundering it into source.
|
|
122
|
+
*
|
|
123
|
+
* Not `DERIVED` — a config already has an unrelated `derived` KIND (`EntityKind.derived`, what
|
|
124
|
+
* `Package` is), and `Config.derive` clones state on every mutation. A third meaning of the same word
|
|
125
|
+
* on the one marker that most needs to read unambiguously.
|
|
126
|
+
*
|
|
127
|
+
* On the body rather than in a parallel set, so the mark rides with the row through every snapshot
|
|
128
|
+
* change instead of being a second thing to keep in step.
|
|
129
|
+
*/
|
|
130
|
+
declare const MINTED = "__minted";
|
|
131
|
+
/** Whether a stored body is a row the build minted. See {@link MINTED}. */
|
|
132
|
+
declare function isMintedRow(value: unknown): boolean;
|
|
133
|
+
/**
|
|
134
|
+
* Every `kind:path` a definition points at — the one generic edge harvester.
|
|
135
|
+
*
|
|
136
|
+
* A ref can contribute more than one edge, at different granularities, so that a query at any of
|
|
137
|
+
* them resolves:
|
|
138
|
+
* • a member ref contributes its entity edge too, so pointing at a component's prop still counts
|
|
139
|
+
* as depending on that component;
|
|
140
|
+
* A sourced ref's edge at the link is not here. It needs the kind a `@slug` resolves against, which is
|
|
141
|
+
* whichever kind the config declared `sourceIdentity` on — and this is a pure walk with no config to
|
|
142
|
+
* ask. `Config.nameEdgeReaders` contributes it through the ref index's `extra` channel instead, so the
|
|
143
|
+
* grammar names no kind. This function used to hardcode `'linked-system'` for it.
|
|
144
|
+
*/
|
|
145
|
+
declare function collectRefs(value: unknown, acc?: string[]): string[];
|
|
146
|
+
/**
|
|
147
|
+
* Deep-rewrite every ref whose target is `from` to `to`, returning a new structure — the generic
|
|
148
|
+
* rename-cascade the same way `collectRefs` is the generic edge walk.
|
|
149
|
+
*
|
|
150
|
+
* Matching is exact on the entity (or on the `#` boundary for members), which is also what keeps a
|
|
151
|
+
* local rename from reaching across a link: `token:color/brand` and `token:color/brand@yahoo-os` are
|
|
152
|
+
* different strings, so renaming ours leaves theirs alone. Your key and their key were never the
|
|
153
|
+
* same field. Don't loosen this to a prefix match.
|
|
154
|
+
*/
|
|
155
|
+
declare function rewriteRefs(value: unknown, from: string, to: string): unknown;
|
|
156
|
+
/**
|
|
157
|
+
* A value that may be a ref, as the name it names.
|
|
158
|
+
*
|
|
159
|
+
* The read twin of {@link rewriteRefNamespace}: a relative ref namespaced under its owner
|
|
160
|
+
* (`value:variant/solid`) reads back as the leaf every consumer actually compares and emits
|
|
161
|
+
* (`solid`), so storing the ref costs no reader a branch.
|
|
162
|
+
*
|
|
163
|
+
* A non-ref is returned as it is, not stringified, so a condition keeps a real boolean rather than
|
|
164
|
+
* the string `"true"`. A condition compiles `true` to a bare truthiness test and `false` to
|
|
165
|
+
* `eq: false`, and both of those need the boolean to still be one by the time they are read.
|
|
166
|
+
*/
|
|
167
|
+
declare function refLeaf(value: unknown): unknown;
|
|
168
|
+
/**
|
|
169
|
+
* Deep-rewrite the first path segment of every `kind` ref namespaced under `from`.
|
|
170
|
+
*
|
|
171
|
+
* The third rename axis, for a relative ref whose path is `<owner-member>/<name>` — a variant
|
|
172
|
+
* value (`value:variant/solid`) belongs to the prop that declares it, so renaming the prop has to
|
|
173
|
+
* move every value under it or they all dangle at once. {@link rewriteRefs} can't: it matches the
|
|
174
|
+
* whole entity or the `#` boundary, and this is a `/` boundary inside the path.
|
|
175
|
+
*
|
|
176
|
+
* Narrowed to one `kind` so it can't reach a same-named member of another collection — a layer
|
|
177
|
+
* called `variant` is `layer:variant` and is left alone.
|
|
178
|
+
*
|
|
179
|
+
* A sourced ref is skipped outright. {@link rewriteRefs} gets that property from exact-matching —
|
|
180
|
+
* `token:color/brand` and `token:color/brand@yahoo-os` are different strings — but a prefix match
|
|
181
|
+
* would catch both, and renaming our prop is no reason to rewrite a ref into someone else's values.
|
|
182
|
+
*/
|
|
183
|
+
declare function rewriteRefNamespace(value: unknown, kind: string, from: string, to: string): unknown;
|
|
184
|
+
/**
|
|
185
|
+
* Deep-rewrite the source half of every ref pointing through link `from`, leaving what each one
|
|
186
|
+
* points at untouched — the cascade for renaming a link.
|
|
187
|
+
*
|
|
188
|
+
* The twin of {@link rewriteRefs} on the other axis: that one moves an entity and keeps the source,
|
|
189
|
+
* this one moves the source and keeps the entity. A link's slug is a local name like any other, so
|
|
190
|
+
* renaming it has to reach every ref that spells it or they all dangle at once.
|
|
191
|
+
*/
|
|
192
|
+
declare function rewriteRefSource(value: unknown, from: string, to: string): unknown;
|
|
193
|
+
//#endregion
|
|
194
|
+
export { ENTITY_PATH_MESSAGE, ExtendableRef, ExtendedRef, MINTED, Ref, collectRefs, entityRefOf, isEntityPath, isExtendedRef, isMintedRow, isRef, kindOf, memberOf, memberRef, orRef, pathOf, ref, refLeaf, refSchema, rewriteRefNamespace, rewriteRefSource, rewriteRefs, sourceOf, splitRef };
|
|
@@ -0,0 +1,403 @@
|
|
|
1
|
+
import { z } from "zod";
|
|
2
|
+
//#region src/framework/utils/refs.ts
|
|
3
|
+
/**
|
|
4
|
+
* Refs are imported, typed markers pointing at another entity by `kind` + qualified
|
|
5
|
+
* path. Because a ref is just data inside a definition, the dependency graph falls out
|
|
6
|
+
* of a generic walk (`collectRefs`) — no per-entity edge wiring.
|
|
7
|
+
*/
|
|
8
|
+
/** Separates the entity from the member it points inside — the URL convention (a path, then a
|
|
9
|
+
* fragment). Everything before it is byte-identical to a plain entity ref, which is what lets the
|
|
10
|
+
* existing machinery keep working; an entity path may contain `/`, so a distinct character is what
|
|
11
|
+
* keeps the boundary unambiguous. */
|
|
12
|
+
const MEMBER = "#";
|
|
13
|
+
/**
|
|
14
|
+
* Qualifies an entity with the linked system it lives in — the link's local slug, not the source's
|
|
15
|
+
* database id, so the ref stays readable and survives a rename on their side.
|
|
16
|
+
*
|
|
17
|
+
* It sits before {@link member} because it qualifies the entity: `component:Button@yahoo-os` is a
|
|
18
|
+
* whole identity, and `#props/gap` points inside whatever that resolved to.
|
|
19
|
+
*/
|
|
20
|
+
const SOURCE = "@";
|
|
21
|
+
/** The `@source` suffix for a ref, or `''` when it's local. */
|
|
22
|
+
const qualifier = (source) => source === void 0 ? "" : `${SOURCE}${source}`;
|
|
23
|
+
/**
|
|
24
|
+
* Whether `path` can be an entity's own path — the invariant {@link splitSource} rests on, so it is
|
|
25
|
+
* stated next to it.
|
|
26
|
+
*
|
|
27
|
+
* An `@` is legal only as the first character, where it opens an npm scope: `package:@ariakit/react`
|
|
28
|
+
* is that package, and `package:@yahoo/uds-create-config` is this one. Anywhere else it reads as the
|
|
29
|
+
* source marker, and the split is what every provenance surface believes.
|
|
30
|
+
*
|
|
31
|
+
* Without this, a legitimately-named entity misparses in silence. A token called `1@2x` under `size`
|
|
32
|
+
* is a plausible name for a retina scale and was storable, and `token:size/1@2x` then reports its path
|
|
33
|
+
* as `size/1` and invents a source called `2x` — which paints nothing (`renderStyleValue` takes its
|
|
34
|
+
* `if (!source) return ''` escape and the declaration vanishes), reports a false dangling ref naming a
|
|
35
|
+
* source that does not exist, and marks the item borrowed on every provenance surface. Nothing throws.
|
|
36
|
+
*
|
|
37
|
+
* Checked where a path becomes an identity — a create, a rename's target, an authored entry — and
|
|
38
|
+
* deliberately not on reads, so an existing bad path stays addressable and, more to the point,
|
|
39
|
+
* deletable.
|
|
40
|
+
*/
|
|
41
|
+
function isEntityPath(path) {
|
|
42
|
+
return path.lastIndexOf(SOURCE) <= 0;
|
|
43
|
+
}
|
|
44
|
+
/** What a refused path should say, in one place, so a create, a rename and a register word it alike. */
|
|
45
|
+
const ENTITY_PATH_MESSAGE = "An entity path may not contain \"@\" except as a leading npm scope — \"@\" marks the source a ref is drawn from, so a path carrying one cannot be told apart from a borrowed address.";
|
|
46
|
+
/**
|
|
47
|
+
* Splits a qualified path into what it names and where from.
|
|
48
|
+
*
|
|
49
|
+
* A path can OPEN with `@`: a package's path is an npm specifier, and `package:@ariakit/react` is
|
|
50
|
+
* scoped. So the source is the last `@`, and never a leading one — a scope opens a path, it doesn't
|
|
51
|
+
* qualify it. `package:@ariakit/react@yahoo-os` is that package, as their system has it.
|
|
52
|
+
*
|
|
53
|
+
* Total for every path {@link isEntityPath} admits, which is what makes "the last `@`" a rule rather
|
|
54
|
+
* than a heuristic: with at most a leading `@` in the path, any later one is the marker.
|
|
55
|
+
*/
|
|
56
|
+
function splitSource(qualified) {
|
|
57
|
+
const at = qualified.lastIndexOf(SOURCE);
|
|
58
|
+
if (at <= 0) return [qualified, void 0];
|
|
59
|
+
return [qualified.slice(0, at), qualified.slice(at + 1)];
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* `kind:path[@source][#member]`, split — the one place a ref is read. This is the ref spelling of the
|
|
63
|
+
* address grammar written down whole in `framework/config-op.ts`.
|
|
64
|
+
*
|
|
65
|
+
* Every accessor below goes through this, and so does anything outside this file that needs a part of
|
|
66
|
+
* a ref. Code that slices at `indexOf(':')` or tests `startsWith('token:')` has its own copy of the
|
|
67
|
+
* grammar, which means the grammar cannot move without hunting for the copies — and a copy that is
|
|
68
|
+
* subtly wrong (a prefix test that a sourced ref fails) is silent.
|
|
69
|
+
*/
|
|
70
|
+
function splitRef(target) {
|
|
71
|
+
const raw = isRef(target) ? target.__ref : target;
|
|
72
|
+
const hash = raw.indexOf(MEMBER);
|
|
73
|
+
const entity = hash === -1 ? raw : raw.slice(0, hash);
|
|
74
|
+
const member = hash === -1 ? void 0 : raw.slice(hash + 1);
|
|
75
|
+
const colon = entity.indexOf(":");
|
|
76
|
+
const kind = colon === -1 ? entity : entity.slice(0, colon);
|
|
77
|
+
const qualifiedPath = colon === -1 ? entity : entity.slice(colon + 1);
|
|
78
|
+
const [path, source] = splitSource(qualifiedPath);
|
|
79
|
+
return {
|
|
80
|
+
kind,
|
|
81
|
+
source,
|
|
82
|
+
path,
|
|
83
|
+
qualifiedPath,
|
|
84
|
+
member,
|
|
85
|
+
marked: colon !== -1
|
|
86
|
+
};
|
|
87
|
+
}
|
|
88
|
+
/**
|
|
89
|
+
* A reference to another entity: `ref('token', 'color/brand')`. Resolution is prefix-or-leaf against
|
|
90
|
+
* the flat store.
|
|
91
|
+
*
|
|
92
|
+
* With a `source` it points into a linked system instead — `ref('token', 'color/brand', 'yahoo-os')`.
|
|
93
|
+
* That is the whole of what a per-entity link marker used to record: the kind is the ref's kind and
|
|
94
|
+
* the source key is its path, while the version lives once on the pin rather than being repeated on
|
|
95
|
+
* every linked entity.
|
|
96
|
+
*/
|
|
97
|
+
function ref(kind, path, source) {
|
|
98
|
+
const value = { __ref: `${kind}:${path}${qualifier(source)}` };
|
|
99
|
+
Object.defineProperty(value, "extend", {
|
|
100
|
+
enumerable: false,
|
|
101
|
+
configurable: false,
|
|
102
|
+
value: (delta) => ({
|
|
103
|
+
__ref: value.__ref,
|
|
104
|
+
extend: delta
|
|
105
|
+
})
|
|
106
|
+
});
|
|
107
|
+
return value;
|
|
108
|
+
}
|
|
109
|
+
/** A reference to one member of an entity's sub-entity collection — a component's prop, a layer:
|
|
110
|
+
* `memberRef('component', 'Pressable', 'props', 'gap')` → `component:Pressable#props/gap`. A
|
|
111
|
+
* `source` qualifies the entity the member is reached through. */
|
|
112
|
+
function memberRef(kind, path, sub, member, source) {
|
|
113
|
+
return { __ref: `${kind}:${path}${qualifier(source)}${MEMBER}${sub}/${member}` };
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* A ref to a singleton kind, in the form the index and the resolver read: the item at the kind's own
|
|
117
|
+
* name, with whatever path the ref named as its member path. `settings:css/prefix@ds` is
|
|
118
|
+
* `settings:settings@ds#css/prefix`, and `settings:` is `settings:settings`. A ref already at the item
|
|
119
|
+
* is handed back as it came. The caller knows the kind is a singleton; this is pure string work.
|
|
120
|
+
*/
|
|
121
|
+
function singletonRef(target) {
|
|
122
|
+
const { kind, source, path, member } = splitRef(target);
|
|
123
|
+
if (path === kind) return target;
|
|
124
|
+
const tail = [path === "" ? void 0 : path, member].filter((part) => part !== void 0).join("/");
|
|
125
|
+
return `${kind}:${kind}${qualifier(source)}${tail ? `${MEMBER}${tail}` : ""}`;
|
|
126
|
+
}
|
|
127
|
+
/** The entity half of any ref — a plain entity ref is itself. This is the form the dependency
|
|
128
|
+
* graph and kind-narrowing speak, so a member ref participates in both unchanged. */
|
|
129
|
+
function entityRefOf(target) {
|
|
130
|
+
const at = target.indexOf(MEMBER);
|
|
131
|
+
return at === -1 ? target : target.slice(0, at);
|
|
132
|
+
}
|
|
133
|
+
/** The member half (`props/gap`), or `undefined` for a plain entity ref. Takes the ref itself or its
|
|
134
|
+
* string form, like {@link pathOf} / {@link kindOf} / {@link sourceOf}. */
|
|
135
|
+
function memberOf(target) {
|
|
136
|
+
const raw = isRef(target) ? target.__ref : target;
|
|
137
|
+
const at = raw.indexOf(MEMBER);
|
|
138
|
+
return at === -1 ? void 0 : raw.slice(at + 1);
|
|
139
|
+
}
|
|
140
|
+
/** The path of the entity a ref points at — kind, source and any member stripped, so a member ref
|
|
141
|
+
* resolves to the item that contains it (`component:buttons/Primary#props/gap` → `buttons/Primary`)
|
|
142
|
+
* and a linked ref yields the path as its source spells it (`token:color/brand@yahoo-os` →
|
|
143
|
+
* `color/brand`). Takes the ref itself or its string form, so a caller holding a ref field never
|
|
144
|
+
* spells `__ref`. */
|
|
145
|
+
function pathOf(target) {
|
|
146
|
+
return splitRef(target).path;
|
|
147
|
+
}
|
|
148
|
+
/** The source half — the link slug a ref points through, or `undefined` when it points at something
|
|
149
|
+
* in this config. This is the one question that distinguishes a linked entity from a local one, and
|
|
150
|
+
* it replaces reading a per-entity provenance marker. */
|
|
151
|
+
function sourceOf(target) {
|
|
152
|
+
return splitRef(target).source;
|
|
153
|
+
}
|
|
154
|
+
/** The kind a ref points at (`component:buttons/Primary#props/gap` → `component`) — the twin of
|
|
155
|
+
* {@link pathOf}, so a consumer holding a `kind:path` string (a `dependentsOf` result) never splits
|
|
156
|
+
* it by hand. Takes the ref itself or its string form. */
|
|
157
|
+
function kindOf(target) {
|
|
158
|
+
return splitRef(target).kind;
|
|
159
|
+
}
|
|
160
|
+
/** The zod schema of a ref value — used via {@link orRef} so a field never spells the
|
|
161
|
+
* `{ __ref }` shape by hand. `.meta({ ref: true })` marks it as a ref for any consumer (JSON
|
|
162
|
+
* Schema, an authoring UI) — this generic form carries no target kind (use an entity as the field
|
|
163
|
+
* to bake one in). */
|
|
164
|
+
const refSchema = z.object({ __ref: z.string() }).meta({ ref: true });
|
|
165
|
+
/** Widen a field's value type to also accept a ref: `value: orRef(z.string())`. */
|
|
166
|
+
function orRef(schema) {
|
|
167
|
+
return z.union([schema, refSchema]);
|
|
168
|
+
}
|
|
169
|
+
function isRef(value) {
|
|
170
|
+
return typeof value === "object" && value !== null && "__ref" in value;
|
|
171
|
+
}
|
|
172
|
+
/** Whether a ref is the stored result of `.extend(delta)`. Kept separate from {@link isRef}: every
|
|
173
|
+
* existing ref consumer should continue to see the base pointer, while Config is the place that
|
|
174
|
+
* gives the sibling delta its merge semantics. */
|
|
175
|
+
function isExtendedRef(value) {
|
|
176
|
+
return isRef(value) && "extend" in value && typeof value.extend === "object" && value.extend !== null && !Array.isArray(value.extend);
|
|
177
|
+
}
|
|
178
|
+
/**
|
|
179
|
+
* The key marking a row the build minted rather than a person authored.
|
|
180
|
+
*
|
|
181
|
+
* A link declares what it took; the rows for everything it brings are made by the build, at the paths
|
|
182
|
+
* the source spells them, so they are stored — `list`, the rename gate and every emitter reach them
|
|
183
|
+
* on the way past — without ever having been written down. This is the one thing that tells the two
|
|
184
|
+
* apart, and three readers turn on it: `uds pull` skips a minted row, a write to one lands on the
|
|
185
|
+
* source's `options` instead of the row (`Config.apply`'s update handler), and a serialize keeps it
|
|
186
|
+
* distinguishable rather than laundering it into source.
|
|
187
|
+
*
|
|
188
|
+
* Not `DERIVED` — a config already has an unrelated `derived` KIND (`EntityKind.derived`, what
|
|
189
|
+
* `Package` is), and `Config.derive` clones state on every mutation. A third meaning of the same word
|
|
190
|
+
* on the one marker that most needs to read unambiguously.
|
|
191
|
+
*
|
|
192
|
+
* On the body rather than in a parallel set, so the mark rides with the row through every snapshot
|
|
193
|
+
* change instead of being a second thing to keep in step.
|
|
194
|
+
*/
|
|
195
|
+
const MINTED = "__minted";
|
|
196
|
+
/** Whether a stored body is a row the build minted. See {@link MINTED}. */
|
|
197
|
+
function isMintedRow(value) {
|
|
198
|
+
return typeof value === "object" && value !== null && value["__minted"] === true;
|
|
199
|
+
}
|
|
200
|
+
/**
|
|
201
|
+
* Every `kind:path` a definition points at — the one generic edge harvester.
|
|
202
|
+
*
|
|
203
|
+
* A ref can contribute more than one edge, at different granularities, so that a query at any of
|
|
204
|
+
* them resolves:
|
|
205
|
+
* • a member ref contributes its entity edge too, so pointing at a component's prop still counts
|
|
206
|
+
* as depending on that component;
|
|
207
|
+
* A sourced ref's edge at the link is not here. It needs the kind a `@slug` resolves against, which is
|
|
208
|
+
* whichever kind the config declared `sourceIdentity` on — and this is a pure walk with no config to
|
|
209
|
+
* ask. `Config.nameEdgeReaders` contributes it through the ref index's `extra` channel instead, so the
|
|
210
|
+
* grammar names no kind. This function used to hardcode `'linked-system'` for it.
|
|
211
|
+
*/
|
|
212
|
+
function collectRefs(value, acc = []) {
|
|
213
|
+
if (isRef(value)) {
|
|
214
|
+
const entity = entityRefOf(value.__ref);
|
|
215
|
+
if (entity !== value.__ref) acc.push(entity);
|
|
216
|
+
acc.push(value.__ref);
|
|
217
|
+
if (isExtendedRef(value)) collectRefs(value.extend, acc);
|
|
218
|
+
} else if (Array.isArray(value)) for (const item of value) collectRefs(item, acc);
|
|
219
|
+
else if (value && typeof value === "object") for (const nested of Object.values(value)) collectRefs(nested, acc);
|
|
220
|
+
return acc;
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Deep-rewrite every ref whose target is `from` to `to`, returning a new structure — the generic
|
|
224
|
+
* rename-cascade the same way `collectRefs` is the generic edge walk.
|
|
225
|
+
*
|
|
226
|
+
* Matching is exact on the entity (or on the `#` boundary for members), which is also what keeps a
|
|
227
|
+
* local rename from reaching across a link: `token:color/brand` and `token:color/brand@yahoo-os` are
|
|
228
|
+
* different strings, so renaming ours leaves theirs alone. Your key and their key were never the
|
|
229
|
+
* same field. Don't loosen this to a prefix match.
|
|
230
|
+
*/
|
|
231
|
+
function rewriteRefs(value, from, to) {
|
|
232
|
+
if (isRef(value)) {
|
|
233
|
+
const siblings = {
|
|
234
|
+
...isExtendedRef(value) ? { extend: rewriteRefs(value.extend, from, to) } : {},
|
|
235
|
+
...isMintedRow(value) ? { [MINTED]: true } : {}
|
|
236
|
+
};
|
|
237
|
+
if (value.__ref === from) return {
|
|
238
|
+
__ref: to,
|
|
239
|
+
...siblings
|
|
240
|
+
};
|
|
241
|
+
if (value.__ref.startsWith(`${from}${MEMBER}`)) return {
|
|
242
|
+
__ref: `${to}${value.__ref.slice(from.length)}`,
|
|
243
|
+
...siblings
|
|
244
|
+
};
|
|
245
|
+
return isExtendedRef(value) ? {
|
|
246
|
+
__ref: value.__ref,
|
|
247
|
+
...siblings
|
|
248
|
+
} : value;
|
|
249
|
+
}
|
|
250
|
+
if (Array.isArray(value)) return value.map((item) => rewriteRefs(item, from, to));
|
|
251
|
+
if (value && typeof value === "object") {
|
|
252
|
+
const out = {};
|
|
253
|
+
for (const [key, nested] of Object.entries(value)) out[key] = rewriteRefs(nested, from, to);
|
|
254
|
+
return out;
|
|
255
|
+
}
|
|
256
|
+
return value;
|
|
257
|
+
}
|
|
258
|
+
/**
|
|
259
|
+
* A value that may be a ref, as the name it names.
|
|
260
|
+
*
|
|
261
|
+
* The read twin of {@link rewriteRefNamespace}: a relative ref namespaced under its owner
|
|
262
|
+
* (`value:variant/solid`) reads back as the leaf every consumer actually compares and emits
|
|
263
|
+
* (`solid`), so storing the ref costs no reader a branch.
|
|
264
|
+
*
|
|
265
|
+
* A non-ref is returned as it is, not stringified, so a condition keeps a real boolean rather than
|
|
266
|
+
* the string `"true"`. A condition compiles `true` to a bare truthiness test and `false` to
|
|
267
|
+
* `eq: false`, and both of those need the boolean to still be one by the time they are read.
|
|
268
|
+
*/
|
|
269
|
+
function refLeaf(value) {
|
|
270
|
+
if (!isRef(value)) return value;
|
|
271
|
+
const path = pathOf(value);
|
|
272
|
+
const slash = path.indexOf("/");
|
|
273
|
+
return slash === -1 ? path : path.slice(slash + 1);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Deep-rewrite the first path segment of every `kind` ref namespaced under `from`.
|
|
277
|
+
*
|
|
278
|
+
* The third rename axis, for a relative ref whose path is `<owner-member>/<name>` — a variant
|
|
279
|
+
* value (`value:variant/solid`) belongs to the prop that declares it, so renaming the prop has to
|
|
280
|
+
* move every value under it or they all dangle at once. {@link rewriteRefs} can't: it matches the
|
|
281
|
+
* whole entity or the `#` boundary, and this is a `/` boundary inside the path.
|
|
282
|
+
*
|
|
283
|
+
* Narrowed to one `kind` so it can't reach a same-named member of another collection — a layer
|
|
284
|
+
* called `variant` is `layer:variant` and is left alone.
|
|
285
|
+
*
|
|
286
|
+
* A sourced ref is skipped outright. {@link rewriteRefs} gets that property from exact-matching —
|
|
287
|
+
* `token:color/brand` and `token:color/brand@yahoo-os` are different strings — but a prefix match
|
|
288
|
+
* would catch both, and renaming our prop is no reason to rewrite a ref into someone else's values.
|
|
289
|
+
*/
|
|
290
|
+
function rewriteRefNamespace(value, kind, from, to) {
|
|
291
|
+
if (isRef(value)) {
|
|
292
|
+
const siblings = isExtendedRef(value) ? { extend: rewriteRefNamespace(value.extend, kind, from, to) } : {};
|
|
293
|
+
if (sourceOf(value) !== void 0) return isExtendedRef(value) ? {
|
|
294
|
+
__ref: value.__ref,
|
|
295
|
+
...siblings
|
|
296
|
+
} : value;
|
|
297
|
+
const prefix = `${kind}:${from}/`;
|
|
298
|
+
return value.__ref.startsWith(prefix) ? {
|
|
299
|
+
__ref: `${kind}:${to}/${value.__ref.slice(prefix.length)}`,
|
|
300
|
+
...siblings
|
|
301
|
+
} : isExtendedRef(value) ? {
|
|
302
|
+
__ref: value.__ref,
|
|
303
|
+
...siblings
|
|
304
|
+
} : value;
|
|
305
|
+
}
|
|
306
|
+
if (Array.isArray(value)) return value.map((item) => rewriteRefNamespace(item, kind, from, to));
|
|
307
|
+
if (value && typeof value === "object") {
|
|
308
|
+
const out = {};
|
|
309
|
+
for (const [key, nested] of Object.entries(value)) out[key] = rewriteRefNamespace(nested, kind, from, to);
|
|
310
|
+
return out;
|
|
311
|
+
}
|
|
312
|
+
return value;
|
|
313
|
+
}
|
|
314
|
+
/**
|
|
315
|
+
* Deep-qualify every unqualified ref with `source` — how a borrowed body's refs read once they have
|
|
316
|
+
* been resolved into the config doing the borrowing.
|
|
317
|
+
*
|
|
318
|
+
* A source spells its own refs locally, because from where it was authored they are local. Merged
|
|
319
|
+
* into a consumer unchanged, each one then names something that consumer was never supposed to own:
|
|
320
|
+
* `file:components/card.tsx` is the publisher's sealed file and the borrower has no such file, so it
|
|
321
|
+
* dangles. The quieter half is worse — a borrower that happens to declare its own `bg` binds
|
|
322
|
+
* `style-property:bg` to its property rather than the one the render was written against, and
|
|
323
|
+
* nothing reads as broken.
|
|
324
|
+
*
|
|
325
|
+
* `owns` decides what counts as an entity reference: only a kind the source actually owns. A ref to
|
|
326
|
+
* a sub-entity (`layer:root`) is scoped to the body holding it and means the same thing on either
|
|
327
|
+
* side of the seam, so qualifying it would invent a link no config could follow.
|
|
328
|
+
*
|
|
329
|
+
* A ref at the kind root (`motion:`, no path) is the same case one level up: it names the kind rather
|
|
330
|
+
* than an entity — the domain a prop is bound to, as `Box`'s `motion` prop is bound to every motion —
|
|
331
|
+
* and a domain means the same thing on either side of the seam too. Qualifying it produced
|
|
332
|
+
* `motion:@uds`, which is not an entity anywhere and cannot be: borrowing a component whose prop is
|
|
333
|
+
* bound to a whole kind left one dangling ref that no amount of linking could satisfy, because there
|
|
334
|
+
* is nothing at that path to link.
|
|
335
|
+
*
|
|
336
|
+
* An already-qualified ref is left alone. It points through the source's own pin, which this config
|
|
337
|
+
* has no slug for — a chain, and a different thing to report.
|
|
338
|
+
*
|
|
339
|
+
* And a ref the borrower already names is left alone too — see `namesItAlready`. That is the one case
|
|
340
|
+
* where the quieter half above does not apply: the borrower's row at that path is a pointer at the very
|
|
341
|
+
* entity the ref means, so binding to it is binding to the same thing, spelled the way everything local
|
|
342
|
+
* spells it.
|
|
343
|
+
*/
|
|
344
|
+
function qualifyRefs({ value, source, owns, namesItAlready }) {
|
|
345
|
+
const walk = (node) => {
|
|
346
|
+
if (isRef(node)) {
|
|
347
|
+
const siblings = isExtendedRef(node) ? { extend: walk(node.extend) } : {};
|
|
348
|
+
if (sourceOf(node) !== void 0 || !owns(kindOf(node)) || pathOf(node) === "" || namesItAlready?.(node) === true) return isExtendedRef(node) ? {
|
|
349
|
+
__ref: node.__ref,
|
|
350
|
+
...siblings
|
|
351
|
+
} : node;
|
|
352
|
+
const member = memberOf(node.__ref);
|
|
353
|
+
const rebuilt = ref(kindOf(node), pathOf(node), source).__ref;
|
|
354
|
+
return {
|
|
355
|
+
__ref: member === void 0 ? rebuilt : `${rebuilt}${MEMBER}${member}`,
|
|
356
|
+
...siblings
|
|
357
|
+
};
|
|
358
|
+
}
|
|
359
|
+
if (Array.isArray(node)) return node.map(walk);
|
|
360
|
+
if (node && typeof node === "object") {
|
|
361
|
+
const out = {};
|
|
362
|
+
for (const [key, nested] of Object.entries(node)) out[key] = walk(nested);
|
|
363
|
+
return out;
|
|
364
|
+
}
|
|
365
|
+
return node;
|
|
366
|
+
};
|
|
367
|
+
return walk(value);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Deep-rewrite the source half of every ref pointing through link `from`, leaving what each one
|
|
371
|
+
* points at untouched — the cascade for renaming a link.
|
|
372
|
+
*
|
|
373
|
+
* The twin of {@link rewriteRefs} on the other axis: that one moves an entity and keeps the source,
|
|
374
|
+
* this one moves the source and keeps the entity. A link's slug is a local name like any other, so
|
|
375
|
+
* renaming it has to reach every ref that spells it or they all dangle at once.
|
|
376
|
+
*/
|
|
377
|
+
function rewriteRefSource(value, from, to) {
|
|
378
|
+
if (isRef(value)) {
|
|
379
|
+
const siblings = {
|
|
380
|
+
...isExtendedRef(value) ? { extend: rewriteRefSource(value.extend, from, to) } : {},
|
|
381
|
+
...isMintedRow(value) ? { [MINTED]: true } : {}
|
|
382
|
+
};
|
|
383
|
+
if (sourceOf(value) !== from) return isExtendedRef(value) ? {
|
|
384
|
+
__ref: value.__ref,
|
|
385
|
+
...siblings
|
|
386
|
+
} : value;
|
|
387
|
+
const member = memberOf(value.__ref);
|
|
388
|
+
const rebuilt = ref(kindOf(value), pathOf(value), to).__ref;
|
|
389
|
+
return {
|
|
390
|
+
__ref: member === void 0 ? rebuilt : `${rebuilt}${MEMBER}${member}`,
|
|
391
|
+
...siblings
|
|
392
|
+
};
|
|
393
|
+
}
|
|
394
|
+
if (Array.isArray(value)) return value.map((item) => rewriteRefSource(item, from, to));
|
|
395
|
+
if (value && typeof value === "object") {
|
|
396
|
+
const out = {};
|
|
397
|
+
for (const [key, nested] of Object.entries(value)) out[key] = rewriteRefSource(nested, from, to);
|
|
398
|
+
return out;
|
|
399
|
+
}
|
|
400
|
+
return value;
|
|
401
|
+
}
|
|
402
|
+
//#endregion
|
|
403
|
+
export { ENTITY_PATH_MESSAGE, MINTED, collectRefs, entityRefOf, isEntityPath, isExtendedRef, isMintedRow, isRef, kindOf, memberOf, memberRef, orRef, pathOf, qualifyRefs, ref, refLeaf, refSchema, rewriteRefNamespace, rewriteRefSource, rewriteRefs, singletonRef, sourceOf, splitRef };
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Config } from "./Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/validate-spec.d.ts
|
|
4
|
+
/**
|
|
5
|
+
* A node in a render spec — what it renders, its prop values, its children. The spec is the
|
|
6
|
+
* HIERARCHY half of rendering and config-v2 does not render: it validates a spec against the config
|
|
7
|
+
* (are these things real, are these prop values in domain) and leaves drawing to codegen's emitted
|
|
8
|
+
* components. This type lives here because validation is what config-v2 does with a spec.
|
|
9
|
+
*
|
|
10
|
+
* `type` is a REF — the same string an entity ref serializes to, so what a design file stores is
|
|
11
|
+
* what the config resolves:
|
|
12
|
+
*
|
|
13
|
+
* component:studio/Button — a component of this system
|
|
14
|
+
* icon:phosphor/TrophyIcon — a glyph from one of its libraries
|
|
15
|
+
* package:ariakit/TooltipAnchor — an export of a package it renders through
|
|
16
|
+
*/
|
|
17
|
+
interface SpecNode {
|
|
18
|
+
readonly type: string;
|
|
19
|
+
readonly props?: Record<string, unknown>;
|
|
20
|
+
readonly children?: readonly SpecNode[];
|
|
21
|
+
readonly text?: string;
|
|
22
|
+
}
|
|
23
|
+
/** Validate a design-file spec against the config — every node's `type` a real component and its
|
|
24
|
+
* props that component's props. Returns per-node error strings (empty = a valid design). */
|
|
25
|
+
declare function validateSpec(config: Config, spec: SpecNode): string[];
|
|
26
|
+
//#endregion
|
|
27
|
+
export { SpecNode, validateSpec };
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { kindOf, memberOf, pathOf, splitRef } from "./utils/refs.js";
|
|
2
|
+
import { childrenPolicy } from "../entities/system/element.js";
|
|
3
|
+
import { resolveComponentProps } from "./projections.js";
|
|
4
|
+
import { refResolves } from "./ref-integrity.js";
|
|
5
|
+
//#region src/framework/validate-spec.ts
|
|
6
|
+
/**
|
|
7
|
+
* `validateSpec` — validate a design-file spec (a tree of component INSTANCES) against a config.
|
|
8
|
+
* Every node is checked against the REAL component: its `type` must be a registered component and
|
|
9
|
+
* its props must be that component's (effective, inheritance included) props. Returns per-node
|
|
10
|
+
* error strings so a caller can reject a bad node and self-correct — the config-v2 edge over
|
|
11
|
+
* composing against loosely-checked tools.
|
|
12
|
+
*
|
|
13
|
+
* Pure over a Config (no mutation): a design file is a document. This is the check the design-file
|
|
14
|
+
* config's `Artboard` entity runs on its `spec` against the SYSTEM config.
|
|
15
|
+
*/
|
|
16
|
+
/** `package:@ariakit/react#Menu` → `@ariakit/react#Menu` — the whole address a node named, minus
|
|
17
|
+
* the kind, for a message that has to say WHICH export was not found. */
|
|
18
|
+
function qualifiedPathOf(target) {
|
|
19
|
+
const { qualifiedPath, member } = splitRef(target);
|
|
20
|
+
return member === void 0 ? qualifiedPath : `${qualifiedPath}#${member}`;
|
|
21
|
+
}
|
|
22
|
+
function walk(config, node, path, errors) {
|
|
23
|
+
const kind = kindOf(node.type);
|
|
24
|
+
const target = pathOf(node.type);
|
|
25
|
+
if (!refResolves(config, node.type)) {
|
|
26
|
+
const named = config.resolve(kind, target) !== void 0 && memberOf(node.type) ? qualifiedPathOf(node.type) : target;
|
|
27
|
+
errors.push(`${path}: unknown ${kind} "${named}"`);
|
|
28
|
+
} else if (kind === "component") {
|
|
29
|
+
const props = resolveComponentProps(config, target);
|
|
30
|
+
for (const name of Object.keys(node.props ?? {})) if (!(name in props)) errors.push(`${path}: unknown prop "${name}" on "${node.type}"`);
|
|
31
|
+
if (node.children?.length && childrenPolicy(config, target) === "none") errors.push(`${path}: "${node.type}" takes no children`);
|
|
32
|
+
}
|
|
33
|
+
(node.children ?? []).forEach((child, i) => {
|
|
34
|
+
walk(config, child, `${path} > ${node.type}[${i}]`, errors);
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Validate a design-file spec against the config — every node's `type` a real component and its
|
|
38
|
+
* props that component's props. Returns per-node error strings (empty = a valid design). */
|
|
39
|
+
function validateSpec(config, spec) {
|
|
40
|
+
const errors = [];
|
|
41
|
+
walk(config, spec, "root", errors);
|
|
42
|
+
return errors;
|
|
43
|
+
}
|
|
44
|
+
//#endregion
|
|
45
|
+
export { validateSpec };
|