@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,478 @@
|
|
|
1
|
+
import { collectRefs, isExtendedRef, isRef, kindOf, memberOf, pathOf, sourceOf, splitRef } from "./utils/refs.js";
|
|
2
|
+
import { isPlainObject, setAtPath } from "./utils/field-path.js";
|
|
3
|
+
//#region src/framework/source-integrity.ts
|
|
4
|
+
/**
|
|
5
|
+
* Every `@source` ref in `config` that does not resolve against its attached source.
|
|
6
|
+
*
|
|
7
|
+
* This is the guarantee the emitted types can only approximate. A union narrows what an author can type, but
|
|
8
|
+
* nothing types a Studio-authored patch, a js consumer, or a config whose source moved on since the last
|
|
9
|
+
* install — and an unresolvable ref renders as the empty string, so the stylesheet gets `--x: ;`: syntactically
|
|
10
|
+
* a declaration, semantically nothing, and silent. Precisely the failure mode a build should refuse.
|
|
11
|
+
*
|
|
12
|
+
* Only sourced refs are checked here. A dangling local ref is the dependency graph's own complaint and has its
|
|
13
|
+
* own reporting; this is about the seam between systems, where the other side can change without us.
|
|
14
|
+
*
|
|
15
|
+
* Walks what this config authored, not what it currently resolves to, and the difference is two bugs
|
|
16
|
+
* rather than a nicety. Resolution loses the subject in both directions:
|
|
17
|
+
*
|
|
18
|
+
* • An extension whose base cannot be found resolves to nothing, so the item drops out of `list` and
|
|
19
|
+
* the broken ref goes unreported — a build passing on a config whose token has silently vanished.
|
|
20
|
+
* That is the case a `Token.ref('palette@ds')` naming a group produces, since a group is not an
|
|
21
|
+
* item and the lookup misses.
|
|
22
|
+
* • An extension that can be found resolves to its source's fields merged over ours, so the walk sees
|
|
23
|
+
* the source's refs through the source's slugs. A source that itself borrows made this config
|
|
24
|
+
* report `@upstream` — a slug it never declared and cannot resolve — and refuse a legitimate chain.
|
|
25
|
+
*
|
|
26
|
+
* The authored body has neither problem: it is exactly the set of refs this config is answerable for.
|
|
27
|
+
*/
|
|
28
|
+
function danglingSourcedRefs(config) {
|
|
29
|
+
const found = [];
|
|
30
|
+
/**
|
|
31
|
+
* Whether a slug is answerable — the three-state question, not the two-state one.
|
|
32
|
+
*
|
|
33
|
+
* `sourceStatus` keeps three answers and only two of them are a problem here. Nobody asked
|
|
34
|
+
* (`undefined`, an ordinary `fromJSON` in an editor) is not a broken ref: the config was never
|
|
35
|
+
* resolved, so every sourced ref would read as dangling and the report would be noise. Asked and
|
|
36
|
+
* could not (`unavailable`) is broken, and is exactly what a build must refuse.
|
|
37
|
+
*
|
|
38
|
+
* Reading only `liveSourceFor` collapsed those into one, which is why the sole non-build caller —
|
|
39
|
+
* `orphanedBorrowsFromJSON` in the studio — had to filter its results down to the one slug it had
|
|
40
|
+
* attached, with a comment explaining that otherwise "its every sourced ref dangles". That filter is
|
|
41
|
+
* a workaround for this line.
|
|
42
|
+
*
|
|
43
|
+
* Both halves are needed, and `sourceStatus` alone is not enough: `registerSources` attaches a
|
|
44
|
+
* source without recording a state, so a config assembled that way answers `undefined` while
|
|
45
|
+
* holding a perfectly good source. So the question is whether there is anything to be answerable
|
|
46
|
+
* against — an attached source, or a resolver's recorded answer.
|
|
47
|
+
*/
|
|
48
|
+
const answerable = (slug) => config.liveSourceFor(slug) !== void 0 || config.sourceStatus(slug) !== void 0;
|
|
49
|
+
for (const kind of config.ownedKinds()) {
|
|
50
|
+
for (const item of config.authoredItems(kind)) for (const target of collectRefs(item.body)) {
|
|
51
|
+
const slug = sourceOf(target);
|
|
52
|
+
if (slug === void 0) continue;
|
|
53
|
+
if (!answerable(slug)) continue;
|
|
54
|
+
if (config.liveSourceFor(slug)?.resolve(kindOf(target), pathOf(target))) continue;
|
|
55
|
+
found.push({
|
|
56
|
+
from: `${kind}:${item.path}`,
|
|
57
|
+
ref: target,
|
|
58
|
+
slug
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
for (const group of config.groups(kind)) {
|
|
62
|
+
const ref = group.meta.ref;
|
|
63
|
+
if (!isRef(ref)) continue;
|
|
64
|
+
const slug = sourceOf(ref);
|
|
65
|
+
if (slug === void 0) continue;
|
|
66
|
+
if (!answerable(slug)) continue;
|
|
67
|
+
const path = pathOf(ref);
|
|
68
|
+
if (config.liveSourceFor(slug)?.members(kind, path).length) continue;
|
|
69
|
+
found.push({
|
|
70
|
+
from: `${kind} group:${group.path}`,
|
|
71
|
+
ref: ref.__ref,
|
|
72
|
+
slug
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return found;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Every extended borrow whose merged body this config's kind will not parse.
|
|
80
|
+
*
|
|
81
|
+
* The third way a link can be broken, and the only one that is nobody's mistake: the source resolved
|
|
82
|
+
* perfectly and said something this config has no way to hold. Two config types need not share a
|
|
83
|
+
* value domain — a native modifier activates on `{ state: 'pressed' }` where a web one takes a CSS
|
|
84
|
+
* fragment, a mode, a composite or a list of modes — so the same kind string can name two shapes
|
|
85
|
+
* neither of which contains the other. `mobile-app`'s `size/control` is the same crossing answered
|
|
86
|
+
* rather than broken: `1rem` has no arm in `NativeToken`, and the local `extend: { value: 16 }` is
|
|
87
|
+
* what makes the merged body legal.
|
|
88
|
+
*
|
|
89
|
+
* A report rather than a throw. Reads answer "nothing" for
|
|
90
|
+
* a row they cannot express, because they must: `list`, `sourceClosure` and `toJSON` all reach stored
|
|
91
|
+
* rows, and a throw from inside serialization has no caller in a position to catch it. So the refusal
|
|
92
|
+
* has to live somewhere a caller asks, which is here — a build refuses on it, and a surface says which
|
|
93
|
+
* Entity and which field.
|
|
94
|
+
*
|
|
95
|
+
* Walks what this config authored, for the reason {@link danglingSourcedRefs} does: a row that fails
|
|
96
|
+
* to resolve is absent from `list`, so a walk over resolved entities is a walk with the subject
|
|
97
|
+
* already removed from it.
|
|
98
|
+
*/
|
|
99
|
+
function unreadableBorrows(config) {
|
|
100
|
+
const found = [];
|
|
101
|
+
for (const kind of config.ownedKinds()) for (const item of config.authoredItems(kind)) {
|
|
102
|
+
if (!isExtendedRef(item.body)) continue;
|
|
103
|
+
const slug = sourceOf(item.body);
|
|
104
|
+
if (slug === void 0) continue;
|
|
105
|
+
const verdict = config.canBorrow({
|
|
106
|
+
kind,
|
|
107
|
+
path: pathOf(item.body),
|
|
108
|
+
slug,
|
|
109
|
+
extend: item.body.extend
|
|
110
|
+
});
|
|
111
|
+
if (verdict.ok) continue;
|
|
112
|
+
found.push({
|
|
113
|
+
from: `${kind}:${item.path}`,
|
|
114
|
+
ref: item.body.__ref,
|
|
115
|
+
slug,
|
|
116
|
+
error: verdict.error
|
|
117
|
+
});
|
|
118
|
+
}
|
|
119
|
+
return found;
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Every sourced ref whose target this config already holds at that path, so the qualifier says
|
|
123
|
+
* nothing the bare path doesn't.
|
|
124
|
+
*
|
|
125
|
+
* A link brings a row per entity it takes, at the path the source spells it, so after the build
|
|
126
|
+
* `token:palette/violet` and `token:palette/violet@ds` are one entity with two names. Two spellings
|
|
127
|
+
* for one thing is what this refuses. It reads as harmless and isn't: the qualified form resolves
|
|
128
|
+
* through the seam, so it breaks the moment the pin is retargeted or dropped while the bare form
|
|
129
|
+
* follows the row wherever it goes, and a config with both in it has half its references surviving the
|
|
130
|
+
* pin's deletion.
|
|
131
|
+
*
|
|
132
|
+
* The one qualified spelling that stays is an entity pointer — `Token.ref('violet@ds').extend({ … })`
|
|
133
|
+
* stored as the row's own body, and a linked folder's `ref`. Both are authored at the local key the
|
|
134
|
+
* bare form would name, so there is nothing else they could say. Everything below that key is a value
|
|
135
|
+
* pointing at another entity, and that is what this walks.
|
|
136
|
+
*
|
|
137
|
+
* A row the pin declares is the subject, never one reachability derived. `sourceClosure` seeds from
|
|
138
|
+
* this config's own refs too, so a hand-written borrow with no `link` declaration derives a row at its
|
|
139
|
+
* target — and telling that author to drop the qualifier would delete the only reason the row exists,
|
|
140
|
+
* leaving a bare ref pointing at nothing. Hence {@link Config.adoptedFrom}: what stands without the
|
|
141
|
+
* ref asking.
|
|
142
|
+
*
|
|
143
|
+
* Walks what this config authored, for the reason {@link danglingSourcedRefs} does — a resolved
|
|
144
|
+
* borrow carries its source's refs through its source's slugs, none of which this config wrote.
|
|
145
|
+
*/
|
|
146
|
+
function redundantQualifiers(config) {
|
|
147
|
+
const found = [];
|
|
148
|
+
/**
|
|
149
|
+
* Whether a row of this config's stands at `path` pointing at the same entity as the ref.
|
|
150
|
+
*
|
|
151
|
+
* Nothing here asks whether that row was derived. A row is minted for what a pin adopts and for
|
|
152
|
+
* nothing else, so a derived row is a declared one — where a row seeded by reachability would have
|
|
153
|
+
* existed because of the very ref being judged, and telling that author to drop the qualifier would
|
|
154
|
+
* delete the only reason the row is there.
|
|
155
|
+
*/
|
|
156
|
+
const named = (kind, path, slug) => {
|
|
157
|
+
const pointsHere = (body) => isRef(body) && sourceOf(body) === slug && pathOf(body) === path;
|
|
158
|
+
return pointsHere(config.storedBody(kind, path)) || pointsHere(config.groupMeta(kind, path)?.ref);
|
|
159
|
+
};
|
|
160
|
+
const check = (from, data) => {
|
|
161
|
+
for (const target of new Set(collectRefs(data))) {
|
|
162
|
+
if (memberOf(target) !== void 0) continue;
|
|
163
|
+
const slug = sourceOf(target);
|
|
164
|
+
if (slug === void 0) continue;
|
|
165
|
+
const kind = kindOf(target);
|
|
166
|
+
const path = pathOf(target);
|
|
167
|
+
if (!named(kind, path, slug)) continue;
|
|
168
|
+
found.push({
|
|
169
|
+
from,
|
|
170
|
+
ref: target,
|
|
171
|
+
slug,
|
|
172
|
+
local: `${kind}:${path}`
|
|
173
|
+
});
|
|
174
|
+
}
|
|
175
|
+
};
|
|
176
|
+
for (const kind of config.ownedKinds()) {
|
|
177
|
+
for (const item of config.authoredItems(kind)) {
|
|
178
|
+
let body = item.body;
|
|
179
|
+
if (isRef(item.body)) body = isExtendedRef(item.body) ? item.body.extend : {};
|
|
180
|
+
check(`${kind}:${item.path}`, body);
|
|
181
|
+
}
|
|
182
|
+
for (const group of config.groups(kind)) {
|
|
183
|
+
const { ref: _pointer, ...rest } = group.meta;
|
|
184
|
+
check(`${kind} group:${group.path}`, rest);
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
return found;
|
|
188
|
+
}
|
|
189
|
+
function segmentsOf(field) {
|
|
190
|
+
return typeof field === "string" ? field.split(".") : field;
|
|
191
|
+
}
|
|
192
|
+
/** A leaf is anything that is not a plain object to walk into. A ref is one value, not a shape. */
|
|
193
|
+
function leafEntries(value, prefix = []) {
|
|
194
|
+
if (!isPlainObject(value) || isRef(value)) return [[prefix, value]];
|
|
195
|
+
return Object.entries(value).flatMap(([key, child]) => leafEntries(child, [...prefix, key]));
|
|
196
|
+
}
|
|
197
|
+
/** Every leaf address under `body`, as segments, so a member key that contains a dot stays one key. */
|
|
198
|
+
function leafAddresses(body) {
|
|
199
|
+
return leafEntries(body).map(([address]) => address).filter((address) => address.length > 0);
|
|
200
|
+
}
|
|
201
|
+
/** The value at a leaf address, or `undefined` where the body has none. A ref is one value, not walked into. */
|
|
202
|
+
function valueAt(body, field) {
|
|
203
|
+
return segmentsOf(field).reduce((at, key) => isPlainObject(at) && !isRef(at) ? at[key] : void 0, body);
|
|
204
|
+
}
|
|
205
|
+
/**
|
|
206
|
+
* The verb one local leaf is against the source's value at the same address: `extend` where the
|
|
207
|
+
* source has nothing there, `override` where it has something different, and `undefined` where
|
|
208
|
+
* nothing local sits there or the two agree. A leaf carried along unchanged is not overlaid: a sub-op
|
|
209
|
+
* copies the whole record it touched into the delta, so a token given one local condition holds the
|
|
210
|
+
* source's other conditions beside it.
|
|
211
|
+
*/
|
|
212
|
+
function leafVerb({ ours, theirs }) {
|
|
213
|
+
if (ours === void 0) return void 0;
|
|
214
|
+
if (theirs === void 0) return "extend";
|
|
215
|
+
return sameValue(ours, theirs) ? void 0 : "override";
|
|
216
|
+
}
|
|
217
|
+
/**
|
|
218
|
+
* Which verb this config's value at `field` is, in the pin's vocabulary — `override` where the source
|
|
219
|
+
* defines the leaf, `extend` where it does not — and `undefined` where nothing local sits there. A
|
|
220
|
+
* record field answers `override` when any member under it does, else `extend` when any was added.
|
|
221
|
+
*/
|
|
222
|
+
function overlayVerb(overlay, field) {
|
|
223
|
+
if (valueAt(overlay.override, field) !== void 0) return "override";
|
|
224
|
+
if (valueAt(overlay.extend, field) !== void 0) return "extend";
|
|
225
|
+
}
|
|
226
|
+
/** Structural equality over JSON-shaped values. */
|
|
227
|
+
function sameValue(a, b) {
|
|
228
|
+
if (a === b) return true;
|
|
229
|
+
if (Array.isArray(a) && Array.isArray(b)) return a.length === b.length && a.every((item, i) => sameValue(item, b[i]));
|
|
230
|
+
if (isPlainObject(a) && isPlainObject(b)) {
|
|
231
|
+
const keys = Object.keys(a);
|
|
232
|
+
return keys.length === Object.keys(b).length && keys.every((key) => sameValue(a[key], b[key]));
|
|
233
|
+
}
|
|
234
|
+
return false;
|
|
235
|
+
}
|
|
236
|
+
/**
|
|
237
|
+
* Every overlay whose verb the source disagrees with — an `extend` at a field they already define, or
|
|
238
|
+
* an `override` at one they do not.
|
|
239
|
+
*
|
|
240
|
+
* The verb is derivable, and this is the derivation. It runs anyway because a declared verb is the
|
|
241
|
+
* only thing that notices the source moving: a field they add in a later version turns an extension
|
|
242
|
+
* into an override, and without the declaration there is nothing for that to contradict. The same
|
|
243
|
+
* check catches the first-order mistake, which is writing an extension for something they already had.
|
|
244
|
+
*
|
|
245
|
+
* Judged leaf by leaf, because one entity legitimately carries both — a token overridden under one
|
|
246
|
+
* modifier and extended under another is one body with two verbs, and a whole-entity comparison would
|
|
247
|
+
* have to call it one or the other.
|
|
248
|
+
*/
|
|
249
|
+
function misdeclaredOverlays(config) {
|
|
250
|
+
const found = [];
|
|
251
|
+
for (const slug of config.sourceSlugs()) {
|
|
252
|
+
const source = config.liveSourceFor(slug);
|
|
253
|
+
if (!source) continue;
|
|
254
|
+
for (const { kind, path } of config.sourceDirectives(slug)) {
|
|
255
|
+
if (kind === void 0) continue;
|
|
256
|
+
const overlay = config.sourceOverlay(slug, kind, path);
|
|
257
|
+
if (!overlay) continue;
|
|
258
|
+
const theirs = source.resolve(kind, path)?.toJSON();
|
|
259
|
+
for (const field of leafAddresses(overlay.extend)) if (valueAt(theirs, field) !== void 0) found.push({
|
|
260
|
+
slug,
|
|
261
|
+
kind,
|
|
262
|
+
path,
|
|
263
|
+
declared: "extend",
|
|
264
|
+
field
|
|
265
|
+
});
|
|
266
|
+
for (const field of leafAddresses(overlay.override)) if (valueAt(theirs, field) === void 0) found.push({
|
|
267
|
+
slug,
|
|
268
|
+
kind,
|
|
269
|
+
path,
|
|
270
|
+
declared: "override",
|
|
271
|
+
field
|
|
272
|
+
});
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
return found;
|
|
276
|
+
}
|
|
277
|
+
/**
|
|
278
|
+
* Split a merged body into `override`/`extend` by judging each leaf against the source — the forward
|
|
279
|
+
* direction of the walk {@link misdeclaredOverlays} runs to check one. A leaf the source defines
|
|
280
|
+
* differently is an override; one it lacks is an extension; one it spells the same is neither, and is
|
|
281
|
+
* left out.
|
|
282
|
+
*
|
|
283
|
+
* What a directive written this way can never do is trip the check that classified it: every leaf
|
|
284
|
+
* lands on the side the live source agrees it belongs on, by construction.
|
|
285
|
+
*/
|
|
286
|
+
function classifyOverlay(local, theirs) {
|
|
287
|
+
let override = {};
|
|
288
|
+
let extend = {};
|
|
289
|
+
for (const [address, value] of leafEntries(local)) {
|
|
290
|
+
if (address.length === 0) continue;
|
|
291
|
+
const verb = leafVerb({
|
|
292
|
+
ours: value,
|
|
293
|
+
theirs: valueAt(theirs, address)
|
|
294
|
+
});
|
|
295
|
+
if (verb === "override") override = setAtPath(override, address, value);
|
|
296
|
+
else if (verb === "extend") extend = setAtPath(extend, address, value);
|
|
297
|
+
}
|
|
298
|
+
return {
|
|
299
|
+
...Object.keys(override).length > 0 ? { override } : {},
|
|
300
|
+
...Object.keys(extend).length > 0 ? { extend } : {}
|
|
301
|
+
};
|
|
302
|
+
}
|
|
303
|
+
/**
|
|
304
|
+
* Every hide the pin aims at a kind it does not adopt.
|
|
305
|
+
*
|
|
306
|
+
* A hide takes a name back, and a config that never adopted the kind never had it: their entity is
|
|
307
|
+
* reachable only qualified either way, so the entry changes nothing and reads as though it did.
|
|
308
|
+
* Reported rather than ignored, because the fix is usually the missing adoption.
|
|
309
|
+
*
|
|
310
|
+
* An overlay on an unadopted path is a different question and is not this one — it would be laid over
|
|
311
|
+
* a row that is never minted, which is worth reporting too, but the message is about a body rather
|
|
312
|
+
* than about a name.
|
|
313
|
+
*/
|
|
314
|
+
function unadoptedDirectives(config) {
|
|
315
|
+
const found = [];
|
|
316
|
+
for (const slug of config.sourceSlugs()) for (const { kind, path } of config.sourceDirectives(slug)) {
|
|
317
|
+
if (kind === void 0) continue;
|
|
318
|
+
if (config.sourceStance(slug, kind, path).adopted) continue;
|
|
319
|
+
if (config.sourceOverlay(slug, kind, path)?.hidden === true) found.push({
|
|
320
|
+
slug,
|
|
321
|
+
kind,
|
|
322
|
+
path,
|
|
323
|
+
act: "hide"
|
|
324
|
+
});
|
|
325
|
+
}
|
|
326
|
+
return found;
|
|
327
|
+
}
|
|
328
|
+
/**
|
|
329
|
+
* Every directive aimed at nothing — an accessor this config has no kind for, or a path the source
|
|
330
|
+
* does not have.
|
|
331
|
+
*
|
|
332
|
+
* The one mistake the other checks structurally cannot see. Each of them answers for a path it is
|
|
333
|
+
* already holding, so it asks "does the declaration mention this one" — and a name nobody has is
|
|
334
|
+
* never a question anyone puts. `toknes` and `palette/nope` both simply cover nothing, silently, and
|
|
335
|
+
* an overlay that covers nothing looks exactly like one that was never needed.
|
|
336
|
+
*
|
|
337
|
+
* Also what notices the source dropping a path. A directive written against an entity a later version
|
|
338
|
+
* removed keeps parsing and keeps doing nothing, which is the same failure the declared verb exists to
|
|
339
|
+
* catch one level down.
|
|
340
|
+
*/
|
|
341
|
+
function danglingDirectives(config) {
|
|
342
|
+
const found = [];
|
|
343
|
+
for (const slug of config.sourceSlugs()) {
|
|
344
|
+
const source = config.liveSourceFor(slug);
|
|
345
|
+
if (!source) continue;
|
|
346
|
+
for (const { kind, accessor, path } of config.sourceDirectives(slug)) {
|
|
347
|
+
if (kind === void 0) {
|
|
348
|
+
found.push({
|
|
349
|
+
slug,
|
|
350
|
+
accessor,
|
|
351
|
+
path,
|
|
352
|
+
missing: "accessor"
|
|
353
|
+
});
|
|
354
|
+
continue;
|
|
355
|
+
}
|
|
356
|
+
if (source.resolve(kind, path) || source.members(kind, path).length > 0) continue;
|
|
357
|
+
found.push({
|
|
358
|
+
slug,
|
|
359
|
+
accessor,
|
|
360
|
+
path,
|
|
361
|
+
missing: "path"
|
|
362
|
+
});
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
return found;
|
|
366
|
+
}
|
|
367
|
+
/**
|
|
368
|
+
* Every borrowed token that varies under a modifier this config does not declare.
|
|
369
|
+
*
|
|
370
|
+
* A borrowed token's conditional values apply under your modifier of that name — so if you don't have the
|
|
371
|
+
* name, the condition is unstatable and the token silently behaves like a lesser version of itself: one
|
|
372
|
+
* colour where the source had two. Refusing is the same rule inlining already enforces; this is the other
|
|
373
|
+
* path to the same place, for a token a consumer references directly rather than one that got inlined.
|
|
374
|
+
*/
|
|
375
|
+
function unstatableConditions(config) {
|
|
376
|
+
const found = [];
|
|
377
|
+
for (const slug of config.sourceSlugs()) {
|
|
378
|
+
const source = config.liveSourceFor(slug);
|
|
379
|
+
if (!source) continue;
|
|
380
|
+
for (const target of config.sourceClosure(slug, "token")) {
|
|
381
|
+
const token = pathOf(target);
|
|
382
|
+
const { overrides } = source.resolve("token", token)?.toJSON() ?? {};
|
|
383
|
+
if (!overrides) continue;
|
|
384
|
+
for (const entry of Object.values(overrides)) {
|
|
385
|
+
const refs = Array.isArray(entry.on) ? entry.on : [entry.on];
|
|
386
|
+
for (const ref of refs) {
|
|
387
|
+
if (!isRef(ref)) continue;
|
|
388
|
+
const modifier = splitRef(ref.__ref).qualifiedPath;
|
|
389
|
+
if (config.resolve("modifier", modifier)) continue;
|
|
390
|
+
found.push({
|
|
391
|
+
slug,
|
|
392
|
+
token,
|
|
393
|
+
modifier
|
|
394
|
+
});
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
}
|
|
399
|
+
return found;
|
|
400
|
+
}
|
|
401
|
+
/**
|
|
402
|
+
* Which of this item's own fields point outside the config, and through which slug — the walk behind
|
|
403
|
+
* the `linked` computed the framework installs on every kind.
|
|
404
|
+
*
|
|
405
|
+
* This is the one fact resolution cannot supply, and it is what a provenance surface names: reading a
|
|
406
|
+
* ref is uniform (`resolveFieldValue` chases local and sourced refs identically, which is what makes
|
|
407
|
+
* referencing one feature rather than two), so nothing about the read says a value came from another
|
|
408
|
+
* System. A badge, a link adornment and a "Source" row all want that, and this is where they get it.
|
|
409
|
+
*
|
|
410
|
+
* Not the write gate, which is {@link borrowedSlug}. Naming where a value comes from and deciding
|
|
411
|
+
* whose the entity is are different questions, and this one answers the first: a ref this config
|
|
412
|
+
* declared is ours to retarget however far away it points, so an edit gated on this locks a pointer
|
|
413
|
+
* its own author wrote.
|
|
414
|
+
*
|
|
415
|
+
* Shallow and structural — no field is named and no kind is asked. A ref sitting one level down is a
|
|
416
|
+
* value this item uses, not a claim about the item, so `{ styles: { bg: violet@ds } }` reports nothing
|
|
417
|
+
* while `{ styles: violet@ds }` reports the slug.
|
|
418
|
+
*
|
|
419
|
+
* A local ref reports nothing on purpose. It resolves through the same chase, but it points inside
|
|
420
|
+
* this config, and there is no other system for a surface to name.
|
|
421
|
+
*
|
|
422
|
+
* One kind is asked, not named: a ref at a kind declaring `linkable: false` (`File`) can never be
|
|
423
|
+
* copied in, so the pin stays qualified forever by design — that permanence is an implementation
|
|
424
|
+
* detail of how the item's code loads, not a claim that the item itself still follows the link. A
|
|
425
|
+
* `config` lets this tell the two apart; without one (a bare fixture with no config to ask) every
|
|
426
|
+
* qualified ref still counts, which is the answer this gave before the distinction existed.
|
|
427
|
+
*/
|
|
428
|
+
function sourcedFields(member, config) {
|
|
429
|
+
const fields = {};
|
|
430
|
+
for (const [field, value] of Object.entries(member)) {
|
|
431
|
+
if (!isRef(value)) continue;
|
|
432
|
+
const slug = sourceOf(value);
|
|
433
|
+
if (slug === void 0) continue;
|
|
434
|
+
if (config?.entityOf(kindOf(value))?.linkable === false) continue;
|
|
435
|
+
fields[field] = slug;
|
|
436
|
+
}
|
|
437
|
+
return fields;
|
|
438
|
+
}
|
|
439
|
+
/**
|
|
440
|
+
* The dependencies this item's own fields point through, deduped — the `sources` computed the
|
|
441
|
+
* framework installs on every kind.
|
|
442
|
+
*
|
|
443
|
+
* Which fields borrow is {@link sourcedFields}; which dependencies they borrow from is every
|
|
444
|
+
* provenance surface's question, and it is the same walk. Sorted so the value is stable across field
|
|
445
|
+
* order, because it lands in a memoized entity that dep arrays hold.
|
|
446
|
+
*
|
|
447
|
+
* Usually one slug. Two means the item's fields disagree about where it comes from, and the callers
|
|
448
|
+
* split there rather than here: `Entity.sources.length > 0` says the item draws on something outside
|
|
449
|
+
* this config at all, while `Entity.source` answers `undefined`, because naming one of two would put
|
|
450
|
+
* a confident wrong label on screen.
|
|
451
|
+
*/
|
|
452
|
+
function sourceSlugs(member, config) {
|
|
453
|
+
return [...new Set(Object.values(sourcedFields(member, config)))].sort();
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* The dependency this item's stored body is borrowed from — the `borrowedFrom` computed the framework
|
|
457
|
+
* installs on every kind, and the question {@link sourcedFields} cannot answer.
|
|
458
|
+
*
|
|
459
|
+
* An item stored as a ref into a source (`Token.ref('palette/accent@ds').extend({ value: 16 })`) is
|
|
460
|
+
* that source's item, resolved there and shallowly overlaid by the fields named here. An item this
|
|
461
|
+
* Config authored is its own, and stays its own no matter where its fields point.
|
|
462
|
+
*
|
|
463
|
+
* That is the whole distinction, and it is the one a write gate needs. `sources` reports where a
|
|
464
|
+
* value comes from, which is what a provenance badge names — and for a local item holding a sourced
|
|
465
|
+
* ref (`{ value: token:palette/accent@ds }`) it reports the source while the item is ours, so gating
|
|
466
|
+
* an edit on it locks a pointer we declared. Retargeting that pointer is an ordinary local edit; the
|
|
467
|
+
* ref is in our artifact, and nothing on the other side changes when it moves.
|
|
468
|
+
*
|
|
469
|
+
* Reads the stored body rather than the resolved one, because resolution is exactly what erases the
|
|
470
|
+
* difference: an extension resolves to the source's fields merged with ours, and those fields hold
|
|
471
|
+
* whatever literals the source authored — so the resolved item looks local and `sources` on it reads
|
|
472
|
+
* empty. The pointer only exists before the merge.
|
|
473
|
+
*/
|
|
474
|
+
function borrowedSlug(body) {
|
|
475
|
+
return isRef(body) ? sourceOf(body) : void 0;
|
|
476
|
+
}
|
|
477
|
+
//#endregion
|
|
478
|
+
export { borrowedSlug, classifyOverlay, danglingDirectives, danglingSourcedRefs, leafAddresses, leafVerb, misdeclaredOverlays, overlayVerb, redundantQualifiers, sourceSlugs, unadoptedDirectives, unreadableBorrows, unstatableConditions, valueAt };
|