@yahoo/uds-create-config 2.44.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,49 @@
|
|
|
1
|
+
import { Ref } from "./utils/refs.js";
|
|
2
|
+
//#region src/framework/inline-sources.d.ts
|
|
3
|
+
/**
|
|
4
|
+
* One value, with every ref through `slug` — or through any source when `slug` is omitted — replaced by
|
|
5
|
+
* what it resolves to.
|
|
6
|
+
*
|
|
7
|
+
* **Resolution hops configs.** A source's own value may be a ref into a third system, under a slug only
|
|
8
|
+
* that source declares, so the recursion continues in the config that answered rather than in ours, and
|
|
9
|
+
* `configFor` is what knows which one that is. Recursing against our own config would leave a ref naming
|
|
10
|
+
* a slug we never declared — the chained-link case in `inline-sources.test.ts`.
|
|
11
|
+
*
|
|
12
|
+
* The recursion takes all sources even when the top-level call is scoped to one, because a value about
|
|
13
|
+
* to become ours must not keep pointing anywhere.
|
|
14
|
+
*/
|
|
15
|
+
/**
|
|
16
|
+
* What to do with a sourced ref that names something with no value — a component, a `file`, a style
|
|
17
|
+
* property. There is nothing to substitute for one, so it needs its own answer, and which answer
|
|
18
|
+
* depends on whether the pin survives the edit.
|
|
19
|
+
*
|
|
20
|
+
* **It survives** for publishing and for reading a repo-local chain. The seam stays, so the ref stays:
|
|
21
|
+
* `keepIdentityRefs`. A borrowed component's `file` has to keep naming the system that owns the
|
|
22
|
+
* implementation or nothing can find it.
|
|
23
|
+
*
|
|
24
|
+
* **It is dropped** when a whole source is being taken in. Keeping the ref would dangle it the moment
|
|
25
|
+
* the declaration goes, and `delete` would refuse while the ref is still a referrer. It mustn't be
|
|
26
|
+
* refused either, because what it names is usually about to become this config's own — the same walk
|
|
27
|
+
* materializes it. So the ref is adopted, requalified at the local entity, and only a target that lands
|
|
28
|
+
* nowhere local is refused. See {@link adoptedRefs}.
|
|
29
|
+
*/
|
|
30
|
+
interface InlineOptions {
|
|
31
|
+
readonly keepIdentityRefs?: boolean;
|
|
32
|
+
/**
|
|
33
|
+
* Called for a ref that can be neither inlined nor requalified, in place of the refusal. The ref is
|
|
34
|
+
* left as it is so the walk reaches every other ref. A plan sets this to name every such ref rather
|
|
35
|
+
* than the first.
|
|
36
|
+
*/
|
|
37
|
+
readonly onUnadoptable?: (ref: Ref) => void;
|
|
38
|
+
/**
|
|
39
|
+
* Where each thing borrowed through the slug will live once the pin is gone, as
|
|
40
|
+
* `style-property:bg@ds` → `style-property:bg`.
|
|
41
|
+
*
|
|
42
|
+
* Derived, not a caller's choice: whoever is dropping the pin builds it ({@link adoptedRefs}) and
|
|
43
|
+
* the walk threads it. It is in the options bag rather than a parameter because the walk is
|
|
44
|
+
* recursive and every hop needs it; its presence is what says "the seam is going".
|
|
45
|
+
*/
|
|
46
|
+
readonly adopted?: ReadonlyMap<string, string>;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { InlineOptions };
|
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
import { rejectData } from "./rejection.js";
|
|
2
|
+
import { MINTED, collectRefs, entityRefOf, isRef, kindOf, pathOf, ref, rewriteRefs, sourceOf } from "./utils/refs.js";
|
|
3
|
+
import { kindBorrowable } from "./registry.js";
|
|
4
|
+
//#region src/framework/inline-sources.ts
|
|
5
|
+
/**
|
|
6
|
+
* Why a sourced ref with no value could not be carried across a dropped pin.
|
|
7
|
+
*
|
|
8
|
+
* Two different dead ends, and telling them apart is the whole point: the advice for one is a real
|
|
9
|
+
* Next step and the advice for the other is impossible, so a single sentence covering both sends half
|
|
10
|
+
* its readers somewhere `link` refuses to go.
|
|
11
|
+
*
|
|
12
|
+
* **A borrowable kind** — a `style-property`, a component. The ref can become ours, but only by being
|
|
13
|
+
* copied first, so `linked-system/copy` is the fix. What this must not say is that we have no entity
|
|
14
|
+
* at the path: we may well have one, and it is simply not the entity this ref names. A local `bg`
|
|
15
|
+
* that happens to share a name with theirs is a different declaration, and quietly repointing at it
|
|
16
|
+
* would change what every callsite means.
|
|
17
|
+
*
|
|
18
|
+
* **A kind that is not borrowable** — a `file`, which is how a borrowed component's implementation
|
|
19
|
+
* travels. `link` refuses these by design (they belong to the system that holds them), so "link it
|
|
20
|
+
* too" is advice with nowhere to go. The honest next step is the other end: the borrow that pulled the
|
|
21
|
+
* file in is what has to be detached or dropped.
|
|
22
|
+
*/
|
|
23
|
+
function unadoptableMessage({ value, config, slug }) {
|
|
24
|
+
const kind = kindOf(value);
|
|
25
|
+
const path = pathOf(value);
|
|
26
|
+
const source = config.sourceFor(slug);
|
|
27
|
+
if (!kindBorrowable(config.entityOf(kind), {
|
|
28
|
+
config,
|
|
29
|
+
source
|
|
30
|
+
})) return `Cannot inline "${value.__ref}": ${kind} entries are not borrowable — they belong to "${slug}", and dropping the pin would leave this one unreachable. Detach what borrows it first (a borrowed component's implementation travels as its ${kind}), or drop what references it.`;
|
|
31
|
+
return `Cannot inline "${value.__ref}": nothing there has a value to keep, and this config has not taken over "${slug}"'s ${kind} "${path}" — a local ${kind} at the same path is a different declaration, so pointing at it would change what every callsite means. Link that ${kind} too, then break the link — or drop what references it.`;
|
|
32
|
+
}
|
|
33
|
+
function inlineSourcedRefs(value, config, slug, options) {
|
|
34
|
+
if (isRef(value)) {
|
|
35
|
+
const source = sourceOf(value);
|
|
36
|
+
if (source === void 0) return value;
|
|
37
|
+
if (slug !== void 0 && source !== slug) return value;
|
|
38
|
+
const owner = config.configFor(value);
|
|
39
|
+
if (!owner) rejectData(`Cannot inline "${value.__ref}": link "${source}" has no source attached and the artifact recorded nothing for it. Rebuild with the link installed before breaking it.`);
|
|
40
|
+
const target = config.resolveRef(value);
|
|
41
|
+
const body = target?.toJSON();
|
|
42
|
+
if (!target && !declaresGroup(owner, value)) rejectData(`Cannot inline "${value.__ref}": "${source}" has no ${kindOf(value)} at "${pathOf(value)}". A pin is exact, so this is a ref into a version that does not declare it.`);
|
|
43
|
+
if (body?.value === void 0) {
|
|
44
|
+
if (options?.keepIdentityRefs) return value;
|
|
45
|
+
const adopted = options?.adopted?.get(entityRefOf(value.__ref));
|
|
46
|
+
if (adopted !== void 0) return rewriteRefs(value, entityRefOf(value.__ref), adopted);
|
|
47
|
+
if (config.entityOf(kindOf(value))?.authoredRefs === false) return;
|
|
48
|
+
if (options?.onUnadoptable) {
|
|
49
|
+
options.onUnadoptable(value);
|
|
50
|
+
return value;
|
|
51
|
+
}
|
|
52
|
+
rejectData(unadoptableMessage({
|
|
53
|
+
value,
|
|
54
|
+
config,
|
|
55
|
+
slug: source
|
|
56
|
+
}));
|
|
57
|
+
}
|
|
58
|
+
return inlineSourcedRefs(body.value, owner, void 0, options);
|
|
59
|
+
}
|
|
60
|
+
if (Array.isArray(value)) return value.map((item) => inlineSourcedRefs(item, config, slug, options));
|
|
61
|
+
if (value && typeof value === "object") {
|
|
62
|
+
const out = {};
|
|
63
|
+
for (const [key, nested] of Object.entries(value)) out[key] = inlineSourcedRefs(nested, config, slug, options);
|
|
64
|
+
return out;
|
|
65
|
+
}
|
|
66
|
+
return value;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* One entity's body, with a borrowed entity taken whole rather than field by field.
|
|
70
|
+
*
|
|
71
|
+
* A ref names an entity, so borrowing one takes everything it declares: a token's conditional values come
|
|
72
|
+
* with its default, the way they came together in the source. Inlining only `value` is a silent partial
|
|
73
|
+
* copy — a colour that flips in dark mode arrives flat, and nothing says so.
|
|
74
|
+
*
|
|
75
|
+
* The merge is the borrower's fields over the target's, the same `{ ...base, ...override }` rule
|
|
76
|
+
* `resolveDerived` uses for a derived member, so a reader learns it once. Declaring your own `overrides`
|
|
77
|
+
* therefore replaces theirs rather than layering on them, which is the plain reading of a field you did
|
|
78
|
+
* state.
|
|
79
|
+
*
|
|
80
|
+
* Only the primary field position is treated this way. A ref elsewhere in a body — a modifier's
|
|
81
|
+
* `selector`, a canvas role's `component` — is a pointer to a thing rather than a borrowing of it, so it
|
|
82
|
+
* keeps the plain value substitution.
|
|
83
|
+
*
|
|
84
|
+
* The kind says which field that is (`entry.primaryField`), the same field `link` writes a bare ref into.
|
|
85
|
+
* Reading `body.value` instead would name the primary field of `token` and of nothing else, so a borrowed
|
|
86
|
+
* `style-property`, whose primary is `properties`, would miss this path, fall through to the plain
|
|
87
|
+
* substitution and throw "nothing there has a value to keep" — making any system that borrows a
|
|
88
|
+
* non-token entity impossible to publish or take in. See
|
|
89
|
+
* `.claude/rules/config-framework-kind-agnostic.md`.
|
|
90
|
+
*/
|
|
91
|
+
function inlineWholeEntity({ body, kind, config, slug, options }) {
|
|
92
|
+
const primary = config.entityOf(kind)?.primaryField;
|
|
93
|
+
const pointer = primary === void 0 ? void 0 : body[primary];
|
|
94
|
+
if (primary !== void 0 && isRef(pointer) && wants(pointer, slug)) {
|
|
95
|
+
const target = config.resolveRef(pointer);
|
|
96
|
+
const owner = config.configFor(pointer);
|
|
97
|
+
if (target && owner) {
|
|
98
|
+
const { [primary]: theirValue, ...theirFields } = borrowWhole({
|
|
99
|
+
fields: target.toJSON(),
|
|
100
|
+
kind,
|
|
101
|
+
source: owner
|
|
102
|
+
});
|
|
103
|
+
const { [primary]: _ourRef, ...ourFields } = body;
|
|
104
|
+
const merged = {
|
|
105
|
+
...inlineSourcedRefs(theirFields, owner, void 0, options),
|
|
106
|
+
...inlineSourcedRefs(ourFields, config, slug, options),
|
|
107
|
+
[primary]: inlineSourcedRefs(theirValue, owner, void 0, options)
|
|
108
|
+
};
|
|
109
|
+
assertCarriedRefsResolve(merged, config, pointer.__ref);
|
|
110
|
+
return merged;
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return inlineSourcedRefs(body, config, slug, options);
|
|
114
|
+
}
|
|
115
|
+
/**
|
|
116
|
+
* A borrowed entity's fields, following the source's own aliases to the bottom.
|
|
117
|
+
*
|
|
118
|
+
* Their `color/primary` may alias their `spectrum/gray/0`, and the alias target is often where the
|
|
119
|
+
* interesting fields live: a semantic token points at a palette token, and the palette token carries the
|
|
120
|
+
* light and dark values. Stopping at the first hop leaves a ref to one of their entities sitting in our
|
|
121
|
+
* body, pointing at nothing of ours, and drops the conditional values with it.
|
|
122
|
+
*
|
|
123
|
+
* Each hop merges the way the borrow itself does — the outer entity's fields over the inner's — so a
|
|
124
|
+
* semantic token stating its own `overrides` keeps them, and one stating none inherits the palette
|
|
125
|
+
* Token's. The primary field always comes from the bottom, which is what an alias chain is for.
|
|
126
|
+
*
|
|
127
|
+
* Each hop asks the kind it is in for that field rather than assuming the chain stays one kind: an alias
|
|
128
|
+
*/
|
|
129
|
+
function borrowWhole({ fields, kind, source, seen = [] }) {
|
|
130
|
+
const primary = source.entityOf(kind)?.primaryField;
|
|
131
|
+
if (primary === void 0) return fields;
|
|
132
|
+
const alias = fields[primary];
|
|
133
|
+
if (!isRef(alias) || sourceOf(alias) !== void 0) return fields;
|
|
134
|
+
const innerKind = kindOf(alias);
|
|
135
|
+
const inner = source.resolve(innerKind, pathOf(alias));
|
|
136
|
+
if (!inner) return fields;
|
|
137
|
+
if (seen.includes(alias.__ref)) rejectData(`Cannot inline through "${alias.__ref}": the source aliases in a cycle (${[...seen, alias.__ref].join(" → ")}).`);
|
|
138
|
+
const resolved = borrowWhole({
|
|
139
|
+
fields: inner.toJSON(),
|
|
140
|
+
kind: innerKind,
|
|
141
|
+
source,
|
|
142
|
+
seen: [...seen, alias.__ref]
|
|
143
|
+
});
|
|
144
|
+
const innerPrimary = source.entityOf(innerKind)?.primaryField ?? primary;
|
|
145
|
+
return {
|
|
146
|
+
...resolved,
|
|
147
|
+
...fields,
|
|
148
|
+
[primary]: resolved[innerPrimary]
|
|
149
|
+
};
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Every local ref in a carried body has to resolve here, or the borrowed entity depends on something this
|
|
153
|
+
* Config doesn't have.
|
|
154
|
+
*
|
|
155
|
+
* A borrowed entity arrives whole, and what it brought may point at things: a token's conditional value
|
|
156
|
+
* names the modifier it varies under, and other kinds name other kinds. Those refs were written in the
|
|
157
|
+
* source's vocabulary and now live in ours, so they resolve against us. That is the answer a consumer
|
|
158
|
+
* wants — a token you pulled in flips under your dark mode — and an obligation at the same time.
|
|
159
|
+
*
|
|
160
|
+
* The failure is loud and names the fix. A dangling `on` would emit a conditional value under no
|
|
161
|
+
* condition, reading as "this colour is always that" rather than "this colour changes in dark mode", and
|
|
162
|
+
* nothing downstream could tell the difference. That is the class this refuses: a borrowed entity that
|
|
163
|
+
* silently behaves like a lesser version of itself.
|
|
164
|
+
*
|
|
165
|
+
* A sourced ref is skipped. It still names the source's world, and it either inlined already or belongs
|
|
166
|
+
* to a link we aren't resolving.
|
|
167
|
+
*/
|
|
168
|
+
function assertCarriedRefsResolve(fields, config, borrowed) {
|
|
169
|
+
for (const target of collectRefs(fields)) {
|
|
170
|
+
if (sourceOf(target) !== void 0) continue;
|
|
171
|
+
const kind = kindOf(target);
|
|
172
|
+
const name = pathOf(target);
|
|
173
|
+
if (config.resolve(kind, name)) continue;
|
|
174
|
+
rejectData(`Cannot inline "${borrowed}": it depends on ${kind} "${name}", which this config does not declare. A borrowed entity comes whole, and what it brought resolves against YOUR entities of the same name — so declare "${name}", or state your own value for this one to replace what it carried.`);
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
/** Whether `owner` declares a group at the path this ref names — the half of "does the target exist"
|
|
178
|
+
* that `resolveRef` cannot answer, because it narrows to an item. */
|
|
179
|
+
function declaresGroup(owner, value) {
|
|
180
|
+
return owner.groups(kindOf(value)).some((group) => group.path === pathOf(value));
|
|
181
|
+
}
|
|
182
|
+
/** Whether this ref is one the caller asked to inline — any source, or the one named. Takes the ref
|
|
183
|
+
* either way it is spelled, because `collectRefs` hands back the string form. */
|
|
184
|
+
function wants(value, slug) {
|
|
185
|
+
const source = sourceOf(value);
|
|
186
|
+
return source !== void 0 && (slug === void 0 || source === slug);
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Whether a body holds a ref this walk is asked to take — the cheap prefilter on the way to
|
|
190
|
+
* {@link rewrittenBody}, and the reason a detach doesn't walk entities it has no business touching.
|
|
191
|
+
*
|
|
192
|
+
* It answers "is there anything here for this walk", not "will this walk change anything". The second
|
|
193
|
+
* question is the one a write depends on, and only running the walk answers it — a ref can be present
|
|
194
|
+
* and deliberately kept. So this is the skip, not the decision.
|
|
195
|
+
*
|
|
196
|
+
* Deep, because the walk is: a conditional value that varies under a borrowed modifier holds its ref a
|
|
197
|
+
* level down, and a shallow test would call that item local and leave it pointing at a dropped pin.
|
|
198
|
+
*/
|
|
199
|
+
function holdsWantedRef(body, slug) {
|
|
200
|
+
return collectRefs(body).some((target) => wants(target, slug));
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Whether two bodies say the same thing — the test that decides whether a walk wrote anything.
|
|
204
|
+
*
|
|
205
|
+
* Structural, because an identity check cannot be: `inlineSourcedRefs` allocates a fresh object for
|
|
206
|
+
* every object it visits, so `!==` reports "changed" for every body it touched. What it does not
|
|
207
|
+
* reallocate is a leaf it decided to leave alone, which is why `Object.is` still short-circuits most
|
|
208
|
+
* of the walk.
|
|
209
|
+
*/
|
|
210
|
+
function sameBody(left, right) {
|
|
211
|
+
if (Object.is(left, right)) return true;
|
|
212
|
+
if (Array.isArray(left) || Array.isArray(right)) return Array.isArray(left) && Array.isArray(right) && left.length === right.length && left.every((item, index) => sameBody(item, right[index]));
|
|
213
|
+
if (typeof left !== "object" || typeof right !== "object" || left === null || right === null) return false;
|
|
214
|
+
const theirs = right;
|
|
215
|
+
const ours = Object.entries(left);
|
|
216
|
+
return ours.length === Object.keys(theirs).length && ours.every(([key, value]) => key in theirs && sameBody(value, theirs[key]));
|
|
217
|
+
}
|
|
218
|
+
/**
|
|
219
|
+
* One body walked, or `undefined` when the walk gave back what it was handed — the whole of "does this
|
|
220
|
+
* Entity need an `update`?", and the guard every write site here goes through.
|
|
221
|
+
*
|
|
222
|
+
* {@link holdsWantedRef} is a prefilter and cannot be the whole answer, because holding a sourced ref
|
|
223
|
+
* and being rewritten are not the same question. `keepIdentityRefs` is on for publishing and for every
|
|
224
|
+
* scoped detach — the pin survives both — so a row whose only tie to the link is a ref at something
|
|
225
|
+
* with no value (a component's `file`, a `style-property` a prop names) passes the prefilter, keeps its
|
|
226
|
+
* ref exactly as it was by design, and is left byte-identical.
|
|
227
|
+
*
|
|
228
|
+
* Writing the `update` anyway is not harmless in the snapshot's sense of harmless: the row lands in the
|
|
229
|
+
* branch's draft and in the changes panel claiming an edit nobody made, and reports a detach that
|
|
230
|
+
* detached nothing as a success. It is the same thing the prefilter exists to prevent, one step later.
|
|
231
|
+
*/
|
|
232
|
+
function rewrittenBody({ body, kind, config, slug, options }) {
|
|
233
|
+
if (!holdsWantedRef(body, slug)) return void 0;
|
|
234
|
+
const inlined = inlineWholeEntity({
|
|
235
|
+
body,
|
|
236
|
+
kind,
|
|
237
|
+
config,
|
|
238
|
+
slug,
|
|
239
|
+
options
|
|
240
|
+
});
|
|
241
|
+
return sameBody(body, inlined) ? void 0 : inlined;
|
|
242
|
+
}
|
|
243
|
+
/**
|
|
244
|
+
* Every item and group body of `config`, rewritten by {@link inlineSourcedRefs}.
|
|
245
|
+
*
|
|
246
|
+
* `linked-system` is skipped: the pins are not values that inline, and they stay — provenance is
|
|
247
|
+
* information a consumer's tooling still wants for attribution and upgrade detection. Deleting one is
|
|
248
|
+
* the pin's own `delete`, once nothing refers through it.
|
|
249
|
+
*
|
|
250
|
+
* Groups are walked as well as items. A group body carries fields like any entity, so a ref hiding in
|
|
251
|
+
* one would otherwise survive a walk that only visited items — and "nothing sourced survives" is the
|
|
252
|
+
* guarantee, not "nothing sourced survives in the places we remembered to look".
|
|
253
|
+
*/
|
|
254
|
+
/**
|
|
255
|
+
* Where each thing borrowed through `slug` will live once the pin is gone — `style-property:bg@ds` →
|
|
256
|
+
* `style-property:bg`.
|
|
257
|
+
*
|
|
258
|
+
* The third answer for a ref that names an identity rather than a value, and the one that makes "link
|
|
259
|
+
* everything, then break the link" work. A borrowed component declares a `styleProperty` prop pointing
|
|
260
|
+
* at `style-property:bg@ds`, and taking the source in materializes their style-property locally. So the
|
|
261
|
+
* pointer is neither a seam to keep, since there will be no pin, nor a value to inline, since a
|
|
262
|
+
* style-property has none. It is a pointer at something that is now ours.
|
|
263
|
+
*
|
|
264
|
+
* Read before anything moves, because a borrowed item is a stored pointer and materializing it is what
|
|
265
|
+
* erases the pointer this map is built from.
|
|
266
|
+
*
|
|
267
|
+
* Two ways a borrow lands somewhere, and the map needs both:
|
|
268
|
+
*
|
|
269
|
+
* - an item, whose local path is whatever this config filed it under. `link` takes a `to`, so their
|
|
270
|
+
* `bg` may be our `theirBg`, and path equality would point at an unrelated entity of ours.
|
|
271
|
+
* - a folder, which may have a group node pointing through the pin, or may be emergent from members
|
|
272
|
+
* that each do. The second has nothing stored to read, so the local group's own path answers, and a
|
|
273
|
+
* ref at `token:color@ds` becomes our `token:color`.
|
|
274
|
+
*
|
|
275
|
+
* A target in neither is left out deliberately: the refusal downstream names it, which is the right
|
|
276
|
+
* outcome for borrowing a component without the style-property it uses.
|
|
277
|
+
*/
|
|
278
|
+
function adoptedRefs(config, slug) {
|
|
279
|
+
const moved = /* @__PURE__ */ new Map();
|
|
280
|
+
for (const kind of config.ownedKinds()) {
|
|
281
|
+
for (const item of config.list(kind)) {
|
|
282
|
+
const body = config.storedBody(kind, item.path);
|
|
283
|
+
if (!isRef(body) || sourceOf(body) !== slug) continue;
|
|
284
|
+
moved.set(entityRefOf(body.__ref), ref(kind, item.path).__ref);
|
|
285
|
+
}
|
|
286
|
+
for (const group of config.groups(kind)) {
|
|
287
|
+
const local = ref(kind, group.path).__ref;
|
|
288
|
+
moved.set(ref(kind, group.path, slug).__ref, local);
|
|
289
|
+
const pointer = group.meta.ref;
|
|
290
|
+
if (isRef(pointer) && sourceOf(pointer) === slug) moved.set(entityRefOf(pointer.__ref), local);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
return moved;
|
|
294
|
+
}
|
|
295
|
+
function inlineAllSources(config, slug, options) {
|
|
296
|
+
const walk = slug === void 0 ? options : {
|
|
297
|
+
...options,
|
|
298
|
+
adopted: adoptedRefs(config, slug)
|
|
299
|
+
};
|
|
300
|
+
const materialized = config.withMaterializedExtensions({ slug });
|
|
301
|
+
let next = materialized;
|
|
302
|
+
for (const kind of materialized.ownedKinds()) {
|
|
303
|
+
if (materialized.entityOf(kind)?.sourceIdentity) continue;
|
|
304
|
+
for (const item of materialized.list(kind)) {
|
|
305
|
+
const data = rewrittenBody({
|
|
306
|
+
body: item.toJSON(),
|
|
307
|
+
kind,
|
|
308
|
+
config: materialized,
|
|
309
|
+
slug,
|
|
310
|
+
options: walk
|
|
311
|
+
});
|
|
312
|
+
if (data === void 0) continue;
|
|
313
|
+
next = next.apply({
|
|
314
|
+
kind,
|
|
315
|
+
operation: "update",
|
|
316
|
+
path: item.path,
|
|
317
|
+
data
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
for (const group of materialized.groups(kind)) {
|
|
321
|
+
const inlined = detachedGroupMeta({
|
|
322
|
+
config: materialized,
|
|
323
|
+
kind,
|
|
324
|
+
groupPath: group.path,
|
|
325
|
+
slug,
|
|
326
|
+
options: walk
|
|
327
|
+
});
|
|
328
|
+
if (!inlined) continue;
|
|
329
|
+
next = next.apply({
|
|
330
|
+
kind,
|
|
331
|
+
operation: "group-update",
|
|
332
|
+
path: group.path,
|
|
333
|
+
data: inlined
|
|
334
|
+
});
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
return next;
|
|
338
|
+
}
|
|
339
|
+
/**
|
|
340
|
+
* A group's body with its borrow through `slug` dissolved — the pointer dropped, and what it was
|
|
341
|
+
* inheriting kept as its own.
|
|
342
|
+
*
|
|
343
|
+
* A group's `ref` is the one sourced ref that must not be inlined, and the difference is what it names.
|
|
344
|
+
* A ref in a value position stands in for a value; this names a folder, and a folder has no value to
|
|
345
|
+
* collapse to. Handed to {@link inlineSourcedRefs} it takes the "nothing there has a value to keep"
|
|
346
|
+
* throw, so a config holding a linked group can't be unlinked or published at all.
|
|
347
|
+
*
|
|
348
|
+
* Dropping it is also right rather than a way around the throw. Being borrowed is derived for a folder,
|
|
349
|
+
* from every member agreeing on one slug, so once the members are local the pointer is a claim that has
|
|
350
|
+
* stopped being true, and leaving it would report the folder as linked to a system nothing else draws
|
|
351
|
+
* through.
|
|
352
|
+
*
|
|
353
|
+
* `ref: null` rather than an omission, because a `group-update` merges over the stored body and a key
|
|
354
|
+
* left out is a key left alone. The label comes from `Config.groups`, which has already merged the
|
|
355
|
+
* source's in, and reading the inherited meta is what keeps "Palette" on the folder after the link that
|
|
356
|
+
* supplied it is gone.
|
|
357
|
+
*
|
|
358
|
+
* `undefined` when the folder draws through nothing this walk takes, including the ordinary case of an
|
|
359
|
+
* emergent folder with no stored node, which a `group-update` would otherwise mint out of nothing for
|
|
360
|
+
* every prefix of every kind.
|
|
361
|
+
*/
|
|
362
|
+
/**
|
|
363
|
+
* A folder's meta with its borrow dropped — the pointer, and the mark that was only true while it
|
|
364
|
+
* pointed.
|
|
365
|
+
*
|
|
366
|
+
* A folder the build minted is minted because it points through a link, so once the pointer is gone
|
|
367
|
+
* the mark is a claim that has stopped being true. It also has to go for a mechanical reason: no kind
|
|
368
|
+
* declares `__minted` as a group field, so a `group-update` carrying it is refused outright.
|
|
369
|
+
*/
|
|
370
|
+
function withoutPointer(meta) {
|
|
371
|
+
const { ref: _dropped, [MINTED]: _wasMinted, ...kept } = meta;
|
|
372
|
+
return kept;
|
|
373
|
+
}
|
|
374
|
+
function detachedGroupMeta({ config, kind, groupPath, slug, options }) {
|
|
375
|
+
const meta = config.groups(kind).find((group) => group.path === groupPath)?.meta ?? {};
|
|
376
|
+
const pointer = meta.ref;
|
|
377
|
+
if (!isRef(pointer) || !wants(pointer, slug)) {
|
|
378
|
+
if (!holdsWantedRef(meta, slug)) return void 0;
|
|
379
|
+
const inlined = inlineSourcedRefs(meta, config, slug, options);
|
|
380
|
+
return sameBody(meta, inlined) ? void 0 : inlined;
|
|
381
|
+
}
|
|
382
|
+
return {
|
|
383
|
+
...inlineSourcedRefs(withoutPointer(meta), config, slug, options),
|
|
384
|
+
ref: null
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
//#endregion
|
|
388
|
+
export { inlineAllSources };
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { Config } from "./Config.js";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/layer-styles.d.ts
|
|
4
|
+
/** Whether every prop a rule names holds the value it asks for. Compared as strings, because a
|
|
5
|
+
* condition is canonicalized into the rule's key and a variant value is a string there. */
|
|
6
|
+
declare function ruleApplies(when: Record<string, unknown> | null | undefined, state: Record<string, unknown>): boolean;
|
|
7
|
+
interface LayerStyleOptions {
|
|
8
|
+
/**
|
|
9
|
+
* Modifiers to treat as active — `['hover']` for a matrix column showing the hover state.
|
|
10
|
+
*
|
|
11
|
+
* A modifier's styles live in a `_<modifier>` block inside a layer's bag, which is where the
|
|
12
|
+
* stylesheet reads them from too. Forcing one flattens that block up into the bag, so a surface sees
|
|
13
|
+
* the values that state actually paints rather than the block itself.
|
|
14
|
+
*/
|
|
15
|
+
readonly forced?: readonly string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* The resolved style bag per layer, for the props an instance was given.
|
|
19
|
+
*
|
|
20
|
+
* Layers with nothing to say are absent rather than empty, so a caller can tell "no styling" from
|
|
21
|
+
* "styled with nothing".
|
|
22
|
+
*/
|
|
23
|
+
declare function layerStyles(config: Config, path: string, props?: Record<string, unknown>, options?: LayerStyleOptions): Record<string, Record<string, unknown>>;
|
|
24
|
+
//#endregion
|
|
25
|
+
export { LayerStyleOptions, layerStyles, ruleApplies };
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { isRef, refLeaf } from "./utils/refs.js";
|
|
2
|
+
import { authoredBag } from "./projections.js";
|
|
3
|
+
//#region src/framework/layer-styles.ts
|
|
4
|
+
/** Whether every prop a rule names holds the value it asks for. Compared as strings, because a
|
|
5
|
+
* condition is canonicalized into the rule's key and a variant value is a string there. */
|
|
6
|
+
function ruleApplies(when, state) {
|
|
7
|
+
return Object.entries(when ?? {}).every(([prop, value]) => String(state[prop]) === String(refLeaf(value)));
|
|
8
|
+
}
|
|
9
|
+
/**
|
|
10
|
+
* Merge a bag over another, flattening any forced modifier block as it goes.
|
|
11
|
+
*
|
|
12
|
+
* The bag arrives already read back through {@link authoredBag}, so what's merged is the leaf an
|
|
13
|
+
* author wrote rather than the ref the bag stores — this projection answers "what is this layer styled
|
|
14
|
+
* with" for a panel and a matrix cell, and a picker's options are leaves.
|
|
15
|
+
*/
|
|
16
|
+
function mergeBag(into, bag, forced) {
|
|
17
|
+
for (const [key, value] of Object.entries(bag)) {
|
|
18
|
+
const modifier = key.startsWith("_") ? key.slice(1) : void 0;
|
|
19
|
+
if (modifier && value && typeof value === "object" && !isRef(value)) {
|
|
20
|
+
if (forced.includes(modifier)) mergeBag(into, value, forced);
|
|
21
|
+
else into[key] = value;
|
|
22
|
+
continue;
|
|
23
|
+
}
|
|
24
|
+
into[key] = value;
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* The resolved style bag per layer, for the props an instance was given.
|
|
29
|
+
*
|
|
30
|
+
* Layers with nothing to say are absent rather than empty, so a caller can tell "no styling" from
|
|
31
|
+
* "styled with nothing".
|
|
32
|
+
*/
|
|
33
|
+
function layerStyles(config, path, props = {}, options = {}) {
|
|
34
|
+
const { styles = {}, defaultProps = {} } = config.resolve("component", path)?.toJSON() ?? {};
|
|
35
|
+
const state = {
|
|
36
|
+
...defaultProps,
|
|
37
|
+
...props
|
|
38
|
+
};
|
|
39
|
+
const forced = options.forced ?? [];
|
|
40
|
+
const applicable = Object.values(styles).filter((rule) => ruleApplies(rule.when, state)).sort((left, right) => Object.keys(left.when ?? {}).length - Object.keys(right.when ?? {}).length);
|
|
41
|
+
const out = {};
|
|
42
|
+
for (const rule of applicable) for (const [layer, bag] of Object.entries(rule.layers ?? {})) {
|
|
43
|
+
out[layer] ??= {};
|
|
44
|
+
mergeBag(out[layer], authoredBag(config, bag ?? {}), forced);
|
|
45
|
+
}
|
|
46
|
+
return out;
|
|
47
|
+
}
|
|
48
|
+
//#endregion
|
|
49
|
+
export { layerStyles, ruleApplies };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { Snapshot } from "./snapshot.js";
|
|
2
|
+
|
|
3
|
+
//#region src/framework/memo.d.ts
|
|
4
|
+
/** The structural shape a memo needs — any config-like that can produce its snapshot. Structural
|
|
5
|
+
* rather than an import of `Config`, which would be a cycle (Config memoizes through this). */
|
|
6
|
+
interface HasSnapshot {
|
|
7
|
+
readonly snapshot: Snapshot;
|
|
8
|
+
/**
|
|
9
|
+
* The live source a LINKED kind reads through, when there is one.
|
|
10
|
+
*
|
|
11
|
+
* Optional, so a bare `{ snapshot }` is still a valid config-like — but a real `Config` must
|
|
12
|
+
* implement it, because a linked kind's data isn't in the consumer's snapshot at all.
|
|
13
|
+
*/
|
|
14
|
+
linkedSource?(kind: string): {
|
|
15
|
+
readonly config: HasSnapshot;
|
|
16
|
+
} | undefined;
|
|
17
|
+
/**
|
|
18
|
+
* The linked SOURCES attached to this config, in a stable order.
|
|
19
|
+
*
|
|
20
|
+
* Part of every key, and not optional to correctness: a source's entities live in the source's
|
|
21
|
+
* snapshot, so a config that swapped one — hydrating with `{ sources }`, re-attaching after a
|
|
22
|
+
* republish — has the same slices and different data. Keyed on the source configs themselves, a
|
|
23
|
+
* derivation that reads a borrowed value recomputes when the source it read from changes.
|
|
24
|
+
*/
|
|
25
|
+
attachedSources?(): readonly object[];
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Wrap `compute` in a cache keyed on the identity of the `kinds` slices it reads.
|
|
29
|
+
*
|
|
30
|
+
* Entries are held in a chain of `WeakMap`s — one level per kind — so a cached result dies with the
|
|
31
|
+
* snapshot slices that produced it. Nothing to invalidate, and no version arithmetic.
|
|
32
|
+
*
|
|
33
|
+
* ```ts
|
|
34
|
+
* const tokenViews = createSliceMemo({
|
|
35
|
+
* kinds: ['token', 'modifier'],
|
|
36
|
+
* compute: (config: Config) => …,
|
|
37
|
+
* });
|
|
38
|
+
* ```
|
|
39
|
+
*/
|
|
40
|
+
declare function createSliceMemo<C extends HasSnapshot, T>({
|
|
41
|
+
kinds,
|
|
42
|
+
compute
|
|
43
|
+
}: {
|
|
44
|
+
readonly kinds: readonly string[];
|
|
45
|
+
readonly compute: (config: C) => T;
|
|
46
|
+
}): (config: C) => T;
|
|
47
|
+
//#endregion
|
|
48
|
+
export { HasSnapshot, createSliceMemo };
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
//#region src/framework/memo.ts
|
|
2
|
+
/** Distinguishes "cached `undefined`" from "not cached" without an extra `has` lookup per level. */
|
|
3
|
+
const MISS = Symbol("miss");
|
|
4
|
+
/**
|
|
5
|
+
* The level a cached value hangs off, so every slice is an interior key.
|
|
6
|
+
*
|
|
7
|
+
* Chains vary in length — one config links a kind and another doesn't — and without a terminator a
|
|
8
|
+
* short chain would read its value where a long one expects another level.
|
|
9
|
+
*/
|
|
10
|
+
const RESULT = Object.freeze({});
|
|
11
|
+
/**
|
|
12
|
+
* Every slice a computation reads for one kind: this config's, then its source's, and so on down
|
|
13
|
+
* the link chain.
|
|
14
|
+
*
|
|
15
|
+
* A linked kind reads THROUGH — `Config.list(kind)` returns the source's items — so the consumer's
|
|
16
|
+
* own slice is the wrong thing to key on by itself. It never changes (the consumer owns nothing of
|
|
17
|
+
* that kind), so a memo keyed on it alone caches the source's first answer forever.
|
|
18
|
+
*/
|
|
19
|
+
function sliceChain(config, kind, acc, seen) {
|
|
20
|
+
if (seen.has(config)) return;
|
|
21
|
+
seen.add(config);
|
|
22
|
+
acc.push(config.snapshot.slice(kind));
|
|
23
|
+
const source = config.linkedSource?.(kind)?.config;
|
|
24
|
+
if (source) sliceChain(source, kind, acc, seen);
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* The identity of the data a computation over `kinds` reads: every attached source, then each kind's
|
|
28
|
+
* slice chain.
|
|
29
|
+
*
|
|
30
|
+
* Exported because two things need it and they must agree. A memo hangs its cache off these objects;
|
|
31
|
+
* a change hook compares this run's against the last one's to decide whether the derivation can be
|
|
32
|
+
* skipped (`runChangeHooks`). Two statements of "what this computation reads" would drift, and the
|
|
33
|
+
* failure is silent both ways — a stale cache hit, or a paint that never happens.
|
|
34
|
+
*
|
|
35
|
+
* Sources come first: they qualify every slice below them, and a config with none contributes nothing.
|
|
36
|
+
*/
|
|
37
|
+
function sliceKeys({ config, kinds }) {
|
|
38
|
+
const keys = [...config.attachedSources?.() ?? []];
|
|
39
|
+
for (const kind of kinds) sliceChain(config, kind, keys, /* @__PURE__ */ new Set());
|
|
40
|
+
return keys;
|
|
41
|
+
}
|
|
42
|
+
/** Whether two key lists name the same data — the skip test for a change hook. */
|
|
43
|
+
function sameSliceKeys({ before, after }) {
|
|
44
|
+
return before.length === after.length && before.every((key, index) => key === after[index]);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
* Wrap `compute` in a cache keyed on the identity of the `kinds` slices it reads.
|
|
48
|
+
*
|
|
49
|
+
* Entries are held in a chain of `WeakMap`s — one level per kind — so a cached result dies with the
|
|
50
|
+
* snapshot slices that produced it. Nothing to invalidate, and no version arithmetic.
|
|
51
|
+
*
|
|
52
|
+
* ```ts
|
|
53
|
+
* const tokenViews = createSliceMemo({
|
|
54
|
+
* kinds: ['token', 'modifier'],
|
|
55
|
+
* compute: (config: Config) => …,
|
|
56
|
+
* });
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
function createSliceMemo({ kinds, compute }) {
|
|
60
|
+
if (kinds.length === 0) throw new Error("createSliceMemo needs at least one kind — a computation that reads nothing has nothing to key on");
|
|
61
|
+
const root = /* @__PURE__ */ new WeakMap();
|
|
62
|
+
return (config) => {
|
|
63
|
+
const keys = sliceKeys({
|
|
64
|
+
config,
|
|
65
|
+
kinds
|
|
66
|
+
});
|
|
67
|
+
let level = root;
|
|
68
|
+
for (const key of keys) {
|
|
69
|
+
let next = level.get(key);
|
|
70
|
+
if (!next) {
|
|
71
|
+
next = /* @__PURE__ */ new WeakMap();
|
|
72
|
+
level.set(key, next);
|
|
73
|
+
}
|
|
74
|
+
level = next;
|
|
75
|
+
}
|
|
76
|
+
const cached = level.has(RESULT) ? level.get(RESULT) : MISS;
|
|
77
|
+
if (cached !== MISS) return cached;
|
|
78
|
+
const value = compute(config);
|
|
79
|
+
level.set(RESULT, value);
|
|
80
|
+
return value;
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
//#endregion
|
|
84
|
+
export { createSliceMemo, sameSliceKeys, sliceKeys };
|