@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.
Files changed (376) hide show
  1. package/README.md +129 -0
  2. package/dist/ai-lanes.d.ts +23 -0
  3. package/dist/ai-lanes.js +34 -0
  4. package/dist/authoring/define-component.d.ts +85 -0
  5. package/dist/configs/CanvasConfig.d.ts +3237 -0
  6. package/dist/configs/CanvasConfig.js +332 -0
  7. package/dist/configs/build-options.d.ts +10 -0
  8. package/dist/configs/build-options.js +68 -0
  9. package/dist/configs/platform.d.ts +15 -0
  10. package/dist/configs/platform.js +17 -0
  11. package/dist/configs/react-native-system.d.ts +3026 -0
  12. package/dist/configs/react-native-system.js +64 -0
  13. package/dist/configs/system.d.ts +2771 -0
  14. package/dist/configs/system.js +74 -0
  15. package/dist/css/properties.generated.d.ts +14 -0
  16. package/dist/css/properties.generated.js +6260 -0
  17. package/dist/css/value-type.d.ts +48 -0
  18. package/dist/css/value-type.js +131 -0
  19. package/dist/css/values.d.ts +33 -0
  20. package/dist/css/values.js +116 -0
  21. package/dist/entities/native/NativeModifier.d.ts +25 -0
  22. package/dist/entities/native/NativeModifier.js +41 -0
  23. package/dist/entities/native/NativeSettings.d.ts +44 -0
  24. package/dist/entities/native/NativeSettings.js +39 -0
  25. package/dist/entities/native/NativeStyleProperty.d.ts +355 -0
  26. package/dist/entities/native/NativeStyleProperty.js +28 -0
  27. package/dist/entities/native/NativeToken.d.ts +31 -0
  28. package/dist/entities/native/NativeToken.js +49 -0
  29. package/dist/entities/system/CanvasRole.d.ts +34 -0
  30. package/dist/entities/system/CanvasRole.js +45 -0
  31. package/dist/entities/system/Component.d.ts +1287 -0
  32. package/dist/entities/system/Component.js +1840 -0
  33. package/dist/entities/system/Composite.d.ts +12 -0
  34. package/dist/entities/system/Composite.js +26 -0
  35. package/dist/entities/system/Device.d.ts +11 -0
  36. package/dist/entities/system/Device.js +18 -0
  37. package/dist/entities/system/File.d.ts +72 -0
  38. package/dist/entities/system/File.js +136 -0
  39. package/dist/entities/system/Font.d.ts +48 -0
  40. package/dist/entities/system/Font.js +56 -0
  41. package/dist/entities/system/GlobalStyle.d.ts +26 -0
  42. package/dist/entities/system/GlobalStyle.js +54 -0
  43. package/dist/entities/system/Guidance.d.ts +85 -0
  44. package/dist/entities/system/Guidance.js +59 -0
  45. package/dist/entities/system/GuidanceStyle.d.ts +14 -0
  46. package/dist/entities/system/GuidanceStyle.js +8 -0
  47. package/dist/entities/system/Icon.d.ts +46 -0
  48. package/dist/entities/system/Icon.js +46 -0
  49. package/dist/entities/system/LinkedSystem.d.ts +504 -0
  50. package/dist/entities/system/LinkedSystem.js +814 -0
  51. package/dist/entities/system/Modifier.d.ts +92 -0
  52. package/dist/entities/system/Modifier.js +120 -0
  53. package/dist/entities/system/Motion.d.ts +28 -0
  54. package/dist/entities/system/Motion.js +48 -0
  55. package/dist/entities/system/Operation.d.ts +100 -0
  56. package/dist/entities/system/Operation.js +236 -0
  57. package/dist/entities/system/Package.d.ts +42 -0
  58. package/dist/entities/system/Package.js +75 -0
  59. package/dist/entities/system/Settings.d.ts +94 -0
  60. package/dist/entities/system/Settings.js +166 -0
  61. package/dist/entities/system/StyleProperty.d.ts +135 -0
  62. package/dist/entities/system/StyleProperty.js +438 -0
  63. package/dist/entities/system/Token.d.ts +67 -0
  64. package/dist/entities/system/Token.js +129 -0
  65. package/dist/entities/system/Tool.d.ts +134 -0
  66. package/dist/entities/system/Tool.js +124 -0
  67. package/dist/entities/system/color.d.ts +64 -0
  68. package/dist/entities/system/color.js +123 -0
  69. package/dist/entities/system/component-module.d.ts +63 -0
  70. package/dist/entities/system/component-module.js +258 -0
  71. package/dist/entities/system/copy-plan.d.ts +98 -0
  72. package/dist/entities/system/copy-plan.js +451 -0
  73. package/dist/entities/system/defineComponent.d.ts +428 -0
  74. package/dist/entities/system/defineComponent.js +337 -0
  75. package/dist/entities/system/element.d.ts +101 -0
  76. package/dist/entities/system/element.js +171 -0
  77. package/dist/entities/system/icon-library.d.ts +64 -0
  78. package/dist/entities/system/icon-library.js +112 -0
  79. package/dist/entities/system/icon-metadata.d.ts +72 -0
  80. package/dist/entities/system/icon-metadata.js +111 -0
  81. package/dist/entities/system/link-declaration.d.ts +27 -0
  82. package/dist/entities/system/link-declaration.js +64 -0
  83. package/dist/entities/system/link-plan.d.ts +160 -0
  84. package/dist/entities/system/link-plan.js +770 -0
  85. package/dist/entities/system/runtime-modules.d.ts +25 -0
  86. package/dist/entities/system/runtime-modules.js +38 -0
  87. package/dist/entities/system/style-bag.d.ts +20 -0
  88. package/dist/entities/system/style-bag.js +246 -0
  89. package/dist/entities/system/token-index.d.ts +89 -0
  90. package/dist/entities/system/token-index.js +112 -0
  91. package/dist/framework/Config.d.ts +2472 -0
  92. package/dist/framework/Config.js +5023 -0
  93. package/dist/framework/Entity.d.ts +127 -0
  94. package/dist/framework/Entity.js +125 -0
  95. package/dist/framework/authoring.d.ts +24 -0
  96. package/dist/framework/authoring.js +7 -0
  97. package/dist/framework/change-hooks.d.ts +119 -0
  98. package/dist/framework/change-hooks.js +131 -0
  99. package/dist/framework/changes.d.ts +88 -0
  100. package/dist/framework/changes.js +246 -0
  101. package/dist/framework/class-names.d.ts +260 -0
  102. package/dist/framework/class-names.js +630 -0
  103. package/dist/framework/coalesce.d.ts +25 -0
  104. package/dist/framework/coalesce.js +60 -0
  105. package/dist/framework/config-op.d.ts +76 -0
  106. package/dist/framework/config-op.js +43 -0
  107. package/dist/framework/config-operation-kind.d.ts +14 -0
  108. package/dist/framework/config-operation-kind.js +14 -0
  109. package/dist/framework/config-ops.d.ts +34 -0
  110. package/dist/framework/config-ops.js +187 -0
  111. package/dist/framework/defineConfig.d.ts +196 -0
  112. package/dist/framework/defineConfig.js +100 -0
  113. package/dist/framework/defineDerivedEntity.d.ts +74 -0
  114. package/dist/framework/defineDerivedEntity.js +83 -0
  115. package/dist/framework/defineEntity.d.ts +318 -0
  116. package/dist/framework/defineEntity.js +183 -0
  117. package/dist/framework/defineSubEntity.d.ts +148 -0
  118. package/dist/framework/defineSubEntity.js +121 -0
  119. package/dist/framework/derived-mutations.d.ts +20 -0
  120. package/dist/framework/derived-mutations.js +38 -0
  121. package/dist/framework/entity-search.d.ts +29 -0
  122. package/dist/framework/entity-search.js +117 -0
  123. package/dist/framework/inline-sources.d.ts +49 -0
  124. package/dist/framework/inline-sources.js +388 -0
  125. package/dist/framework/layer-styles.d.ts +25 -0
  126. package/dist/framework/layer-styles.js +49 -0
  127. package/dist/framework/memo.d.ts +48 -0
  128. package/dist/framework/memo.js +84 -0
  129. package/dist/framework/overlay.d.ts +49 -0
  130. package/dist/framework/overlay.js +17 -0
  131. package/dist/framework/plan.d.ts +49 -0
  132. package/dist/framework/plan.js +73 -0
  133. package/dist/framework/projections.d.ts +480 -0
  134. package/dist/framework/projections.js +974 -0
  135. package/dist/framework/prop-surface.d.ts +132 -0
  136. package/dist/framework/prop-surface.js +278 -0
  137. package/dist/framework/ref-graph.d.ts +71 -0
  138. package/dist/framework/ref-graph.js +158 -0
  139. package/dist/framework/ref-integrity.d.ts +55 -0
  140. package/dist/framework/ref-integrity.js +171 -0
  141. package/dist/framework/registered.d.ts +95 -0
  142. package/dist/framework/registry-dir.d.ts +42 -0
  143. package/dist/framework/registry-dir.js +48 -0
  144. package/dist/framework/registry.d.ts +300 -0
  145. package/dist/framework/registry.js +104 -0
  146. package/dist/framework/rejection.d.ts +58 -0
  147. package/dist/framework/rejection.js +111 -0
  148. package/dist/framework/rename-inference.d.ts +26 -0
  149. package/dist/framework/rename-inference.js +50 -0
  150. package/dist/framework/render-spec.d.ts +296 -0
  151. package/dist/framework/render-spec.js +809 -0
  152. package/dist/framework/schema-version.d.ts +140 -0
  153. package/dist/framework/schema-version.js +214 -0
  154. package/dist/framework/schemas.d.ts +109 -0
  155. package/dist/framework/schemas.js +615 -0
  156. package/dist/framework/session.d.ts +196 -0
  157. package/dist/framework/session.js +367 -0
  158. package/dist/framework/signature.d.ts +15 -0
  159. package/dist/framework/signature.js +83 -0
  160. package/dist/framework/snapshot.d.ts +115 -0
  161. package/dist/framework/snapshot.js +277 -0
  162. package/dist/framework/source-integrity.d.ts +226 -0
  163. package/dist/framework/source-integrity.js +478 -0
  164. package/dist/framework/sources.d.ts +211 -0
  165. package/dist/framework/sources.js +89 -0
  166. package/dist/framework/utils/compiled-schema.d.ts +23 -0
  167. package/dist/framework/utils/compiled-schema.js +46 -0
  168. package/dist/framework/utils/content-key.d.ts +15 -0
  169. package/dist/framework/utils/content-key.js +33 -0
  170. package/dist/framework/utils/enumerated.d.ts +13 -0
  171. package/dist/framework/utils/enumerated.js +19 -0
  172. package/dist/framework/utils/field-path.d.ts +95 -0
  173. package/dist/framework/utils/field-path.js +136 -0
  174. package/dist/framework/utils/field-schema.d.ts +55 -0
  175. package/dist/framework/utils/field-schema.js +183 -0
  176. package/dist/framework/utils/group.d.ts +37 -0
  177. package/dist/framework/utils/group.js +13 -0
  178. package/dist/framework/utils/package-path.d.ts +37 -0
  179. package/dist/framework/utils/package-path.js +61 -0
  180. package/dist/framework/utils/refs.d.ts +194 -0
  181. package/dist/framework/utils/refs.js +403 -0
  182. package/dist/framework/validate-spec.d.ts +27 -0
  183. package/dist/framework/validate-spec.js +45 -0
  184. package/dist/framework/value-domain.d.ts +26 -0
  185. package/dist/framework/value-domain.js +202 -0
  186. package/dist/framework/views-facade.d.ts +15 -0
  187. package/dist/framework/views-facade.js +19 -0
  188. package/dist/index.d.ts +90 -42
  189. package/dist/index.js +86 -37
  190. package/dist/migrations/2.0.0/raw-css.d.ts +11 -0
  191. package/dist/migrations/2.0.0/raw-css.js +72 -0
  192. package/dist/migrations/2.0.0/v1-artifact.d.ts +1559 -0
  193. package/dist/migrations/2.0.0/v1-artifact.js +1018 -0
  194. package/dist/migrations/20260908171448_settings_as_kind.d.ts +22 -0
  195. package/dist/migrations/20260908171448_settings_as_kind.js +89 -0
  196. package/dist/migrations/20260908194245_visible_state_pointer.d.ts +19 -0
  197. package/dist/migrations/20260908194245_visible_state_pointer.js +115 -0
  198. package/dist/migrations/20260909183001_icon_knockout_variants.d.ts +18 -0
  199. package/dist/migrations/20260909183001_icon_knockout_variants.js +8 -0
  200. package/dist/migrations/20260910212453_linked_system_link_ops.d.ts +13 -0
  201. package/dist/migrations/20260910212453_linked_system_link_ops.js +8 -0
  202. package/dist/migrations/index.d.ts +2 -0
  203. package/dist/migrations/index.js +2 -0
  204. package/dist/react-native/style-keys.generated.d.ts +10 -0
  205. package/dist/react-native/style-keys.generated.js +167 -0
  206. package/dist/renderer/RendererErrorBoundary.d.ts +32 -5
  207. package/dist/renderer/RendererErrorBoundary.js +59 -10
  208. package/dist/renderer/UdsRenderer.d.ts +11 -10
  209. package/dist/renderer/UdsRenderer.js +1 -1
  210. package/dist/renderer/assetEntries.d.ts +37 -0
  211. package/dist/renderer/assetEntries.js +39 -0
  212. package/dist/renderer/assetRenderable.d.ts +14 -6
  213. package/dist/renderer/assetRenderable.js +8 -2
  214. package/dist/renderer/componentEntry.d.ts +58 -0
  215. package/dist/renderer/componentEntry.js +71 -0
  216. package/dist/renderer/icon-library.d.ts +20 -0
  217. package/dist/renderer/index.d.ts +7 -7
  218. package/dist/renderer/index.js +5 -5
  219. package/dist/renderer/primitives/SlotRenderer.d.ts +1 -1
  220. package/dist/renderer/primitives/SlotRenderer.js +1 -1
  221. package/dist/renderer/runtimeComponent.d.ts +33 -0
  222. package/dist/renderer/runtimeComponent.js +113 -0
  223. package/dist/renderer/spec-content.d.ts +43 -0
  224. package/dist/renderer/spec-content.js +95 -0
  225. package/dist/renderer/wrapRegistry.d.ts +22 -37
  226. package/dist/renderer/wrapRegistry.js +10 -20
  227. package/dist/renderer/wrappers/event-bridge.js +6 -5
  228. package/dist/renderer/wrappers/hex-normalize.js +6 -5
  229. package/dist/renderer/wrappers/html-aliases.d.ts +7 -2
  230. package/dist/renderer/wrappers/html-aliases.js +36 -19
  231. package/dist/renderer/wrappers/inline-styles.js +7 -6
  232. package/dist/spec/asset-jsx.d.ts +18 -5
  233. package/dist/spec/asset-jsx.js +27 -16
  234. package/dist/spec/collapse-text-labels.d.ts +5 -15
  235. package/dist/spec/collapse-text-labels.js +26 -19
  236. package/dist/spec/empty-node-slots.d.ts +56 -34
  237. package/dist/spec/empty-node-slots.js +87 -47
  238. package/dist/spec/index.d.ts +21 -10
  239. package/dist/spec/index.js +21 -10
  240. package/dist/spec/jsxToSpec.d.ts +14 -9
  241. package/dist/spec/jsxToSpec.js +20 -3
  242. package/dist/spec/preview-elements.d.ts +63 -0
  243. package/dist/spec/preview-elements.js +89 -0
  244. package/dist/spec/rewrite-refs.d.ts +58 -0
  245. package/dist/spec/rewrite-refs.js +250 -0
  246. package/dist/spec/specToJsx.js +18 -29
  247. package/dist/tsconfig.tsbuildinfo +1 -1
  248. package/package.json +39 -52
  249. package/dist/AssetGroup.d.ts +0 -77
  250. package/dist/AssetGroup.js +0 -125
  251. package/dist/Component.d.ts +0 -333
  252. package/dist/Component.js +0 -1061
  253. package/dist/ComponentGroup.d.ts +0 -22
  254. package/dist/ComponentGroup.js +0 -51
  255. package/dist/CompositeStyle.d.ts +0 -30
  256. package/dist/CompositeStyle.js +0 -59
  257. package/dist/Config.d.ts +0 -528
  258. package/dist/Config.js +0 -1712
  259. package/dist/Mode.d.ts +0 -41
  260. package/dist/Mode.js +0 -81
  261. package/dist/Modifier.d.ts +0 -51
  262. package/dist/Modifier.js +0 -97
  263. package/dist/MotionDef.d.ts +0 -81
  264. package/dist/MotionDef.js +0 -212
  265. package/dist/Props.d.ts +0 -332
  266. package/dist/Props.js +0 -35
  267. package/dist/Provider.d.ts +0 -20
  268. package/dist/Provider.js +0 -14
  269. package/dist/StyleProp.d.ts +0 -145
  270. package/dist/StyleProp.js +0 -239
  271. package/dist/Token.d.ts +0 -76
  272. package/dist/Token.js +0 -133
  273. package/dist/TokenGroup.d.ts +0 -33
  274. package/dist/TokenGroup.js +0 -69
  275. package/dist/asset-kind.d.ts +0 -55
  276. package/dist/asset-kind.js +0 -29
  277. package/dist/asset-value.d.ts +0 -23
  278. package/dist/asset-value.js +0 -40
  279. package/dist/brands.d.ts +0 -30
  280. package/dist/brands.js +0 -20
  281. package/dist/captureCallerPath.d.ts +0 -48
  282. package/dist/captureCallerPath.js +0 -95
  283. package/dist/colorExpressions.d.ts +0 -131
  284. package/dist/colorExpressions.js +0 -148
  285. package/dist/component-referrers.d.ts +0 -30
  286. package/dist/component-referrers.js +0 -40
  287. package/dist/config-diagnostics.d.ts +0 -21
  288. package/dist/config-diagnostics.js +0 -12
  289. package/dist/defineAssetGroup.d.ts +0 -200
  290. package/dist/defineAssetGroup.js +0 -323
  291. package/dist/defineProvider.d.ts +0 -29
  292. package/dist/defineProvider.js +0 -60
  293. package/dist/element-marker.d.ts +0 -63
  294. package/dist/element-marker.js +0 -113
  295. package/dist/entity-utils.d.ts +0 -56
  296. package/dist/entity-utils.js +0 -105
  297. package/dist/extension.d.ts +0 -55
  298. package/dist/extension.js +0 -214
  299. package/dist/factories.d.ts +0 -863
  300. package/dist/factories.js +0 -475
  301. package/dist/font-face.d.ts +0 -25
  302. package/dist/font-face.js +0 -72
  303. package/dist/foreign-component-name.d.ts +0 -21
  304. package/dist/foreign-component-name.js +0 -42
  305. package/dist/interpolate.d.ts +0 -20
  306. package/dist/interpolate.js +0 -10
  307. package/dist/jsx/__fixtures__/cross-component-preview.d.ts +0 -3
  308. package/dist/jsx/__fixtures__/cross-component-preview.js +0 -15
  309. package/dist/jsx/jsx-dev-runtime.d.ts +0 -15
  310. package/dist/jsx/jsx-dev-runtime.js +0 -11
  311. package/dist/jsx/jsx-runtime.d.ts +0 -48
  312. package/dist/jsx/jsx-runtime.js +0 -305
  313. package/dist/linked-system-pins.d.ts +0 -30
  314. package/dist/linked-system-pins.js +0 -45
  315. package/dist/linkedNodePrefixes.d.ts +0 -73
  316. package/dist/linkedNodePrefixes.js +0 -99
  317. package/dist/markers.d.ts +0 -235
  318. package/dist/markers.js +0 -70
  319. package/dist/motion-constants.d.ts +0 -37
  320. package/dist/motion-constants.js +0 -61
  321. package/dist/native/NativeConfig.d.ts +0 -56
  322. package/dist/native/NativeConfig.js +0 -162
  323. package/dist/native/assets.d.ts +0 -20
  324. package/dist/native/assets.js +0 -17
  325. package/dist/native/components.d.ts +0 -139
  326. package/dist/native/components.js +0 -67
  327. package/dist/native/index.d.ts +0 -18
  328. package/dist/native/index.js +0 -17
  329. package/dist/native/modes.d.ts +0 -10
  330. package/dist/native/modes.js +0 -11
  331. package/dist/native/types.d.ts +0 -95
  332. package/dist/native/types.js +0 -0
  333. package/dist/native/validation.d.ts +0 -8
  334. package/dist/native/validation.js +0 -885
  335. package/dist/native/values.d.ts +0 -7
  336. package/dist/native/values.js +0 -15
  337. package/dist/native.d.ts +0 -12
  338. package/dist/native.js +0 -10
  339. package/dist/refs.d.ts +0 -204
  340. package/dist/refs.js +0 -129
  341. package/dist/registry-aliases.d.ts +0 -33
  342. package/dist/registry-aliases.js +0 -35
  343. package/dist/registry-dir.d.ts +0 -22
  344. package/dist/registry-dir.js +0 -10
  345. package/dist/renderer/makeRegistry.d.ts +0 -34
  346. package/dist/renderer/makeRegistry.js +0 -52
  347. package/dist/renderer/makeUdsRenderer.d.ts +0 -13
  348. package/dist/renderer/makeUdsRenderer.js +0 -51
  349. package/dist/renderer/wrappers/component-slots.d.ts +0 -41
  350. package/dist/renderer/wrappers/component-slots.js +0 -66
  351. package/dist/renderer/wrappers/slot-resolution.d.ts +0 -25
  352. package/dist/renderer/wrappers/slot-resolution.js +0 -68
  353. package/dist/renderer/wrappers/void-elements.d.ts +0 -37
  354. package/dist/renderer/wrappers/void-elements.js +0 -40
  355. package/dist/spec/layer-props.d.ts +0 -52
  356. package/dist/spec/layer-props.js +0 -149
  357. package/dist/spec/preview-controls.d.ts +0 -44
  358. package/dist/spec/preview-controls.js +0 -139
  359. package/dist/spec/slot-refs.d.ts +0 -39
  360. package/dist/spec/slot-refs.js +0 -56
  361. package/dist/token-override-rows.d.ts +0 -68
  362. package/dist/token-override-rows.js +0 -233
  363. package/dist/tokenValueType.d.ts +0 -34
  364. package/dist/tokenValueType.js +0 -138
  365. package/dist/types/css-properties.d.ts +0 -233
  366. package/dist/types/css-properties.js +0 -14
  367. package/dist/types/css-property-keywords.d.ts +0 -156
  368. package/dist/types/css-property-keywords.js +0 -616
  369. package/dist/types/css-values.d.ts +0 -63
  370. package/dist/types/css-values.js +0 -16
  371. package/dist/types.d.ts +0 -1138
  372. package/dist/types.js +0 -12
  373. package/dist/units.d.ts +0 -14
  374. package/dist/units.js +0 -16
  375. package/dist/utils/index.d.ts +0 -4
  376. package/dist/utils/index.js +0 -4
@@ -0,0 +1,300 @@
1
+ import { DerivedOp, SchemaEntry } from "./schemas.js";
2
+ import { SubEntityClass } from "./defineSubEntity.js";
3
+ import { BulkOverlayWrite, BulkQuery, SourceOverlay, SourceResolutionSchemas } from "./sources.js";
4
+ import { Config } from "./Config.js";
5
+ import { z } from "zod";
6
+
7
+ //#region src/framework/registry.d.ts
8
+ /** What a computed field is handed: the member's own stored fields, the config it lives in, and the
9
+ * path it is filed under. An object because three arguments in a fixed order is an order to
10
+ * remember, and because `config` was previously named `source` at both declaration sites — a word
11
+ * that now means the config a dependency resolves to. */
12
+ interface ComputedInput {
13
+ readonly member: Record<string, unknown>;
14
+ readonly config: Config;
15
+ /** Identity, so a field that defaults to it can say so (`LinkedSystem.displayName`). */
16
+ readonly path: string;
17
+ }
18
+ /**
19
+ * Virtual fields, recomputed on read and never stored — a pure fn of {@link ComputedInput}.
20
+ *
21
+ * Declared by stored kinds too, not only derived ones. A fact that is a derivation of what an entity
22
+ * already holds belongs on the entity, computed: provenance is the case that forced this — whether a
23
+ * Token is borrowed, and from where, is read off the source qualifier in its own `value`, so any
24
+ * consumer re-deriving it is a second place that knows the entity's shape and a second place to get it
25
+ * wrong. Studio had one; the CLI and the AI read tools would each have wanted their own.
26
+ */
27
+ type ComputedFields = Record<string, (input: ComputedInput) => unknown>;
28
+ /** A derived kind's compute metadata — set via `defineDerivedEntity`. Members are computed from a
29
+ * source config (`deriveMembers`); `overridable` fields accept a sparse user override; `computed`
30
+ * fields are recomputed on read (never stored). Absent for a normal (stored) kind. */
31
+ interface DerivedKind {
32
+ readonly deriveMembers: (source: Config) => Record<string, Record<string, unknown>>;
33
+ readonly overridable?: readonly string[];
34
+ readonly computed?: ComputedFields;
35
+ }
36
+ /**
37
+ * Whether a kind may be borrowed from a linked source: a flat answer, or one judged per pair of
38
+ * configs. See {@link EntityKind.linkable}.
39
+ */
40
+ type Linkable = boolean | ((args: {
41
+ readonly config: Config;
42
+ readonly source: Config;
43
+ }) => boolean);
44
+ interface EntityKind {
45
+ readonly name: string;
46
+ /** The entity class's name (`style-property` → `StyleProperty`) — what a consumer writes to reach
47
+ * it (`StyleProperty.ref(...)`, `Token.group(...)`).
48
+ *
49
+ * Derived once, here, because three places used to re-derive it from the kind and one of them
50
+ * drifted: the authoring reference told consumers the helper was `styleProperty` while the code
51
+ * emitters wrote `StyleProperty`. A fact about a kind belongs on the kind.
52
+ *
53
+ * A variant declares its own, since the derivation can't reach it: `NativeToken` implements kind
54
+ * `token`, so deriving the name from the kind would emit `Token.item(…)` into a native config — a
55
+ * class that file never imports, checking the body against the wrong schema. `extend({ entityName })`
56
+ * is where the entity says its own name instead. */
57
+ readonly entityName: string;
58
+ /** Human label for one item — for UI/docs surfaces (a folder header, a tool label). Defaults
59
+ * to a title-cased `name`; set via `defineEntity({ label })`. */
60
+ readonly label: string;
61
+ /** Human label for the collection (a folder of items). Defaults to `label + 's'`; set via
62
+ * `defineEntity({ labelPlural })` when the naive plural is wrong (`Style Properties`). */
63
+ readonly labelPlural: string;
64
+ readonly fieldKeys: string[];
65
+ readonly groupFieldKeys: string[];
66
+ /** {@link ComputedFields} this kind declares — evaluated by `Config.resolve`, present on reads, and
67
+ * excluded from `toJSON` so no derivation is ever written into an artifact. */
68
+ readonly computed?: ComputedFields;
69
+ readonly computedKeys: readonly string[];
70
+ /** The first declared field — a bare value (`'color/brand': '#1167f4'`) is shorthand
71
+ * for it, so the common case skips the object wrapper. */
72
+ readonly primaryField: string;
73
+ /** The keyed sub-entity collections, field name → its definition (`layers` → `Layer`). These
74
+ * are the fields sub-entity CRUD (create/update/delete/reorder a member) may target, and each
75
+ * definition carries the member's own schema + labels rather than them being inferred. */
76
+ readonly subEntities: Readonly<Record<string, SubEntityClass>>;
77
+ readonly groupCreateSchema: z.ZodTypeAny;
78
+ /** The kind's canonical op map, keyed by verb — defaults (CRUD + reads + sub-*) merged with the
79
+ * author's `schemas` param (override / add / remove). `opsForKind` and the Operation entity read
80
+ * it. Empty for a derived kind. */
81
+ readonly schemas: Readonly<Record<string, SchemaEntry>>;
82
+ /** Set for a kind declared via `defineDerivedEntity` — its members are computed, read-only
83
+ * (+ optional sparse overrides), and it derives no CRUD operations. */
84
+ readonly derived?: DerivedKind;
85
+ /**
86
+ * Declared by a kind whose items name an external source, listing the fields that decide which
87
+ * source. An item of such a kind is a slug other entities borrow through, so values recorded from
88
+ * it are only true while these fields hold — editing one invalidates them, editing any other field
89
+ * (a display label) does not.
90
+ *
91
+ * Declared here rather than tested for by name in the framework, which knows borrowing as a
92
+ * mechanism and must not know which kind implements it.
93
+ */
94
+ readonly sourceIdentity?: readonly string[];
95
+ /**
96
+ * The subset of {@link sourceIdentity} that names *which* system, leaving out the fields that name a
97
+ * version of it. Two pins agreeing on these draw on one origin at possibly different versions, which
98
+ * is what {@link Config.originOf} compares. Falls back to `sourceIdentity` when not declared.
99
+ */
100
+ readonly sourceOrigin?: readonly string[];
101
+ /**
102
+ * Whether an author ever writes a ref to this kind by hand. Default true; a kind whose paths the
103
+ * build mints declares `false`.
104
+ *
105
+ * What reads it is the emitted `uds-env.d.ts`, whose `RegisteredPaths` exists to type
106
+ * `<Entity>.ref(...)` at an authoring site. A kind with no authoring site gets nothing from being
107
+ * enumerated there and costs something real: `file`'s paths are paths in the source tree, so a
108
+ * checked-in `uds-env.d.ts` would change every time a component file is added, renamed or moved —
109
+ * churn on a generated artifact for a reason that has nothing to do with the design system.
110
+ *
111
+ * Declared by the kind rather than tested for by name, the same as {@link sourceIdentity}: the
112
+ * emitter knows "these paths are a type surface" as a property, and must not know which kinds have
113
+ * it. Omitting a kind is safe by construction — `PathOf` falls back to `string` for any kind the
114
+ * augmentation does not mention, which is the same branch an empty kind already takes.
115
+ */
116
+ readonly authoredRefs?: boolean;
117
+ /**
118
+ * Whether this kind may be borrowed from a linked source at all — default true; a kind that is
119
+ * about this config rather than about design declares `false`.
120
+ *
121
+ * A statement about meaning, not capability: every kind a source owns and this config declares
122
+ * could land (`Config.borrowableKinds` is exactly that intersection), and these are the ones where
123
+ * landing is incoherent — a `file`'s path is a path in your own source tree, and a linked-system pin
124
+ * would make that source's own dependencies yours, at their versions.
125
+ *
126
+ * Declared by the kind rather than tested for by name, the same as {@link sourceIdentity} — the
127
+ * borrow op knows "some kinds are not borrowable" as a property, never which. Omitting it is safe:
128
+ * a kind that says nothing is borrowable, which is every design-bearing kind.
129
+ *
130
+ * A kind whose answer depends on the pair of configs declares a predicate instead. A `package` row is
131
+ * a claim about what the holding config's renders import, so it carries across two configs of one
132
+ * platform and not across a web system and a native one. Readers go through {@link kindBorrowable}.
133
+ */
134
+ readonly linkable?: Linkable;
135
+ /**
136
+ * The group fields a borrowed group does NOT inherit — default none, so a source's group node
137
+ * arrives whole.
138
+ *
139
+ * A group node carries two sorts of field, and only one of them is the source's to say. `variants`
140
+ * and `sizes` on an icon library describe the set itself, so a consumer that borrows the library
141
+ * needs them: without `variants` the borrowed `Icon`'s `variant` prop has no domain and
142
+ * `icon:<slug>#variants` resolves to nothing. `cssPrefix` describes how a config EMITS — a borrowed
143
+ * component's classes carry the consumer's prefix, so inheriting the source's would name classes
144
+ * this stylesheet does not contain.
145
+ *
146
+ * Declared by the kind rather than tested for by name, the same as {@link linkable}: `Config`
147
+ * knows "some group fields are local" as a property, never which. Omitting it inherits everything,
148
+ * which is right for every kind whose group node only describes the group.
149
+ */
150
+ readonly localGroupFields?: readonly string[];
151
+ /**
152
+ * Whether a `/` in this kind's paths is a folder boundary — default true. A kind whose slash is
153
+ * part of the name (a `Package`'s npm specifier) declares `false`, and `Config.groups` then
154
+ * synthesizes nothing from a path prefix. See {@link EntityKindSpec.emergentGroups}.
155
+ */
156
+ readonly emergentGroups?: boolean;
157
+ /**
158
+ * Declared by a kind that has exactly one item, at a path equal to the kind's name — a config's
159
+ * `settings`, where the thing being written is the config itself and there is nothing to create,
160
+ * delete, rename or reorder.
161
+ *
162
+ * What the framework does with it: registering the kind seeds the item from the schema's defaults,
163
+ * so every field has to be optional or defaulted (checked when the kind is built); the catalog drops
164
+ * `create`, `delete`, `rename`, `reorder` and the group verbs; every op's `path` defaults to the kind
165
+ * name so a caller can omit it; and `register` takes the item's body under the accessor directly,
166
+ * with no path level. Whether the item is borrowed or refed is the kind's own declaration, as for
167
+ * any other kind.
168
+ *
169
+ * Declared here so a singleton is an ordinary kind to every surface — patches, undo, rebase, the
170
+ * changes list, the agent catalog — rather than a second thing each of them special-cases.
171
+ */
172
+ readonly singleton?: true;
173
+ /**
174
+ * The collection a member ref addresses when it names no collection — `package:react-native#View`
175
+ * rather than `#View`.
176
+ *
177
+ * Declared, never inferred from "the kind has exactly one sub-entity": that rule would silently
178
+ * re-point every stored ref the day a second one is added. A kind that declares none keeps the
179
+ * qualified form, which is what `component:Input#props/disabled` needs, since several collections
180
+ * mean the ref has to say which.
181
+ */
182
+ readonly bareMember?: string;
183
+ /**
184
+ * Declared by a source kind that can be resolved: the schemas its resolutions' two branches are
185
+ * validated against — `{ resolved, unavailable }`, see {@link SourceResolutionSchemas}.
186
+ *
187
+ * Separate from {@link sourceIdentity} because they are separate capabilities. `sourceIdentity` makes
188
+ * a kind borrowable — its items become slugs a ref can qualify with, which is all an emit-and-read
189
+ * path needs. This makes it resolvable, which only `Config.load` needs. A kind can honestly be the
190
+ * first without the second.
191
+ *
192
+ * Here rather than in the framework because the payloads are the kind's vocabulary: what "resolved"
193
+ * means for a linked system (a config path, or a systemId at a version) is not what it would mean
194
+ * for a linked package (a lockfile entry), and a union naming one is a shape the other cannot fill.
195
+ * The framework contributes the `status` tag and nothing else — `resolutionSchema` composes the two.
196
+ */
197
+ readonly sourceResolution?: SourceResolutionSchemas;
198
+ /**
199
+ * Declared by a source kind that records a bulk take: whether one of its pins still covers a
200
+ * borrowed entity — `bulkAdopts(pin's body, the borrow's kind/accessor/source path)`.
201
+ *
202
+ * Read by the delete gate. Taking a kind wholesale and then deleting one of the entities that
203
+ * arrived is two statements that disagree — a re-run can't tell a path you removed on purpose from
204
+ * one you never took — so the delete is refused while the declaration still covers it. The
205
+ * framework knows that shape; only the kind knows where the record lives and how it's keyed.
206
+ *
207
+ * The `path` handed in is the path the source spells, not the local one, since a declaration names
208
+ * what was taken from the source and `to` lets the two differ. A kind that records nothing declares
209
+ * nothing, and no delete is ever refused for it.
210
+ */
211
+ readonly bulkAdopts?: (args: BulkQuery) => boolean;
212
+ /** What the declared source lays over the entity at this path, when it declares anything. */
213
+ readonly bulkOverlay?: (args: BulkQuery) => SourceOverlay | undefined;
214
+ /**
215
+ * Every path this declaration says anything about, as written — the three reads above answer for a
216
+ * path you already have, and this is what enumerates them.
217
+ *
218
+ * The inverse direction, and the only one that can see a directive aimed at nothing: a check driven
219
+ * by the source's catalogue asks "does the declaration mention this path", so a misspelled path is
220
+ * never a question anyone puts. It also costs less, since the declarations are a handful of entries
221
+ * where a catalogue is thousands.
222
+ *
223
+ * `accessor` is returned as the declaration spells it, unresolved, since an accessor this config has
224
+ * no kind for is exactly one of the mistakes worth reporting.
225
+ */
226
+ readonly bulkDirectives?: (body: Record<string, unknown>) => {
227
+ accessor: string;
228
+ path: string;
229
+ }[];
230
+ /**
231
+ * The field-path delta that lands `overlay` on this path — the write {@link bulkOverlay} has no
232
+ * counterpart for, since only the kind knows where a directive is stored.
233
+ *
234
+ * Asked by `Config.apply`'s `update` handler when an edit lands on a minted row: the row has no
235
+ * body of its own to take the edit, so the edit becomes a patch on the declared source's own item
236
+ * instead, at whatever field this returns. A kind that declares {@link bulkOverlay} but not this one
237
+ * can be read but never edited through a minted row.
238
+ */
239
+ readonly bulkOverlayWrite?: (args: BulkOverlayWrite) => Record<string, unknown>;
240
+ /**
241
+ * Edges this kind's data implies by name rather than by ref — `nameEdges(body)` for one item.
242
+ *
243
+ * A record that carries identity in a key is invisible to `collectRefs`: a component's style bag is
244
+ * keyed `bg`, so nothing said it depends on `style-property:bg`, and both halves of a rename broke
245
+ * quietly — the delete wasn't refused and the cascade had nothing to rewrite. `namesMembersOf`
246
+ * already draws this distinction for a sibling collection's names; this is the same statement about
247
+ * another kind's items.
248
+ *
249
+ * Must be a pure function of the body it is handed. That is what lets these edges ride the same
250
+ * incremental index update as ref-borne ones — a derivation that read another kind's state would be
251
+ * recomputed only when this entity changed, so renaming the thing it read would leave it stale, and
252
+ * silently-stale reporting is what this whole mechanism exists to remove.
253
+ */
254
+ readonly nameEdges?: (data: unknown) => string[];
255
+ /**
256
+ * Whether an item's leaf (its last path segment) is unique across the kind, so the leaf alone names
257
+ * it. `Config.resolve` then answers a bare leaf, and an edge keyed by the leaf (a style bag's `_dark`)
258
+ * counts as pointing at the item. A modifier declares it: a bag key and a force attribute spell the
259
+ * leaf, since neither can hold a slash.
260
+ */
261
+ readonly uniqueLeaves?: boolean;
262
+ /**
263
+ * Rules that hold across the kind's items and groups together, which no single item's schema can
264
+ * see — a typed group nested under another typed group. Returns the violations as sentences; a
265
+ * write that leaves any is refused. Checked after registration and after every patch on the kind,
266
+ * never on hydration, so a stored artifact stays loadable.
267
+ */
268
+ readonly invariants?: (config: Config) => string[];
269
+ /**
270
+ * Rewrite one name wherever this kind's data holds it as a key — the cascade half of
271
+ * {@link nameEdges}, applied by `Config.apply`'s rename alongside `rewriteRefs`.
272
+ *
273
+ * Takes and returns the whole body. Order-preserving is the caller's responsibility and it matters:
274
+ * a style bag's key order is declaration order in the emitted rule, so rebuilding a record in a
275
+ * different order changes what paints.
276
+ */
277
+ readonly rewriteName?: (data: unknown, from: string, to: string) => unknown;
278
+ /**
279
+ * Where this kind keeps its style bags — a set of declarations keyed by the property being set.
280
+ *
281
+ * The third statement about the same records {@link nameEdges} and {@link rewriteName} describe, and
282
+ * the one a reader needs: those two answer for a bag's keys, and a bag's values carry names too. A
283
+ * leaf that resolves is stored as a ref (`bindBagTokens`), so the ref graph sees it — but a leaf
284
+ * that resolves to nothing stays a plain string, which is exactly the case worth reporting and the
285
+ * one nothing could find, because no generic walk knew where a kind's bags were.
286
+ *
287
+ * Declared per kind for the same reason as the other two: only the kind knows that a component's
288
+ * bags are its style rules' per-layer maps, its anatomy nodes' props, and its own defaults. Missing
289
+ * a position is not a partial answer but a silent one.
290
+ */
291
+ readonly styleBags?: (data: unknown) => {
292
+ bag: Record<string, unknown>;
293
+ }[];
294
+ }
295
+ /** Every operation a kind exposes — its merged `schemas` map, flattened to `{ kind, verb, ... }`.
296
+ * The single derivation the Operation entity maps over; nothing hardcodes a CRUD list. Reads the
297
+ * kind def a `Config` holds (`config.entityOf(kind)`); `undefined` → no ops. */
298
+ declare function opsForKind(entry: EntityKind | undefined, config?: Config): DerivedOp[];
299
+ //#endregion
300
+ export { ComputedFields, ComputedInput, EntityKind, Linkable, opsForKind };
@@ -0,0 +1,104 @@
1
+ import { compileSchema } from "./utils/compiled-schema.js";
2
+ import { deriveCreateSchema, fieldKeys } from "./utils/field-schema.js";
3
+ import { dataSchema, defaultSchemas, mergeSchemas, resolveFields, resolveInputSchema } from "./schemas.js";
4
+ import { sourceSlugs } from "./source-integrity.js";
5
+ //#region src/framework/registry.ts
6
+ /**
7
+ * Whether `entry`'s kind may be borrowed into `config` from `source`. The one reader of
8
+ * {@link EntityKind.linkable}, so a predicate and a boolean are asked the same way everywhere.
9
+ *
10
+ * A predicate with no source to judge answers no: the question is about a pair, and half of one is
11
+ * not enough to say the borrow is sound.
12
+ */
13
+ function kindBorrowable(entry, { config, source }) {
14
+ if (!entry) return false;
15
+ const { linkable } = entry;
16
+ if (typeof linkable === "function") return source !== void 0 && linkable({
17
+ config,
18
+ source
19
+ });
20
+ return linkable !== false;
21
+ }
22
+ /** `style-property` → `StyleProperty`. The kind→class-name rule, in one place. */
23
+ function entityClassName(kind) {
24
+ const camel = kind.replace(/-([a-z])/g, (_, char) => char.toUpperCase());
25
+ return camel.charAt(0).toUpperCase() + camel.slice(1);
26
+ }
27
+ /** A kind name → a Title-Cased default label (`style-property` → `Style Property`). The fallback for
28
+ * an unregistered name (a synthetic UI group); `Config.entityLabel` uses it. */
29
+ function titleCase(kind) {
30
+ return kind.split(/[-_]/).filter(Boolean).map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
31
+ }
32
+ /** Derive a kind's immutable metadata from its field schemas — the value a `defineEntity`/
33
+ * `defineDerivedEntity` attaches to its class and a `Config.register` stores in `#entities`. */
34
+ function buildKind(spec) {
35
+ const { name, fields, groupFields, subEntities = {}, computed, label, labelPlural, schemas: userSchemas, derived, sourceIdentity, sourceOrigin, authoredRefs, linkable, localGroupFields, emergentGroups, singleton = false, bareMember, sourceResolution, bulkAdopts, bulkOverlay, bulkDirectives, bulkOverlayWrite, nameEdges, rewriteName, styleBags, uniqueLeaves, invariants } = spec;
36
+ const allComputed = {
37
+ sources: ({ member, config }) => sourceSlugs(member, config),
38
+ borrowedFrom: ({ config, path }) => config.borrowedFrom(name, path),
39
+ ...computed
40
+ };
41
+ const resolvedLabel = label ?? titleCase(name);
42
+ const keys = fieldKeys(resolveFields(fields));
43
+ const subs = Object.fromEntries(Object.entries(subEntities).filter(([, def]) => def !== void 0));
44
+ const schemas = derived ? {} : mergeSchemas(name, defaultSchemas(name, fields, groupFields, subs, { singleton }), userSchemas, fields);
45
+ if (singleton) {
46
+ const seeded = dataSchema(schemas, "replace")?.safeParse({});
47
+ if (!seeded?.success) throw new Error(`defineEntity: singleton kind "${name}" cannot be seeded from its defaults — every field of a singleton has to be optional or carry a default.${seeded ? ` ${seeded.error.issues.map((issue) => `${issue.path.join(".")}: ${issue.message}`).join("; ")}` : ""}`);
48
+ }
49
+ return {
50
+ name,
51
+ label: resolvedLabel,
52
+ entityName: spec.entityName ?? entityClassName(name),
53
+ labelPlural: labelPlural ?? `${resolvedLabel}s`,
54
+ fieldKeys: keys,
55
+ groupFieldKeys: fieldKeys(groupFields),
56
+ computed: allComputed,
57
+ computedKeys: Object.keys(allComputed),
58
+ primaryField: singleton ? "" : keys[0] ?? "",
59
+ subEntities: subs,
60
+ groupCreateSchema: compileSchema(deriveCreateSchema(groupFields)),
61
+ schemas,
62
+ derived,
63
+ ...sourceIdentity ? { sourceIdentity } : {},
64
+ ...sourceOrigin ? { sourceOrigin } : {},
65
+ ...authoredRefs === false ? { authoredRefs } : {},
66
+ ...linkable !== void 0 && linkable !== true ? { linkable } : {},
67
+ ...localGroupFields?.length ? { localGroupFields } : {},
68
+ ...emergentGroups === false ? { emergentGroups } : {},
69
+ ...singleton ? { singleton: true } : {},
70
+ ...bareMember ? { bareMember } : {},
71
+ ...sourceResolution ? { sourceResolution } : {},
72
+ ...bulkAdopts ? { bulkAdopts } : {},
73
+ ...bulkOverlay ? { bulkOverlay } : {},
74
+ ...bulkDirectives ? { bulkDirectives } : {},
75
+ ...bulkOverlayWrite ? { bulkOverlayWrite } : {},
76
+ nameEdges,
77
+ rewriteName,
78
+ styleBags,
79
+ ...uniqueLeaves ? { uniqueLeaves } : {},
80
+ ...invariants ? { invariants } : {}
81
+ };
82
+ }
83
+ /** Every operation a kind exposes — its merged `schemas` map, flattened to `{ kind, verb, ... }`.
84
+ * The single derivation the Operation entity maps over; nothing hardcodes a CRUD list. Reads the
85
+ * kind def a `Config` holds (`config.entityOf(kind)`); `undefined` → no ops. */
86
+ function opsForKind(entry, config) {
87
+ if (!entry) return [];
88
+ return Object.entries(entry.schemas).map(([verb, schema]) => ({
89
+ kind: entry.name,
90
+ verb,
91
+ input: resolveInputSchema(schema.input, { config }),
92
+ readOnly: schema.readOnly,
93
+ handler: schema.handler,
94
+ label: schema.label,
95
+ description: schema.description,
96
+ scope: schema.scope,
97
+ creates: schema.creates,
98
+ approval: schema.approval,
99
+ title: schema.title,
100
+ example: schema.example
101
+ }));
102
+ }
103
+ //#endregion
104
+ export { buildKind, kindBorrowable, opsForKind, titleCase };
@@ -0,0 +1,58 @@
1
+ import { z } from "zod";
2
+
3
+ //#region src/framework/rejection.d.ts
4
+ /**
5
+ * Why a write was refused. Four, because these are the four things a config can distinguish — three
6
+ * about the target (missing, taken, not offered) and one about the data. A finer code would be a
7
+ * finer distinction than `apply` actually makes.
8
+ */
9
+ type ConfigIssueCode = /** Nothing at that path / no such member — an update, delete or rename with no target. */'NOT_FOUND' /** A create over an existing path, or a rename onto a taken one. */ | 'ALREADY_EXISTS'
10
+ /**
11
+ * The address cannot be an identity — a path carrying `@` other than as a leading npm scope, which
12
+ * `isEntityPath` refuses because it cannot be told apart from a borrowed address.
13
+ *
14
+ * A distinct code rather than `INVALID_DATA`: nothing about the data is wrong, and the surface that
15
+ * reports it is a name field rather than a form. This is a distinction `apply` genuinely makes.
16
+ */
17
+ | 'INVALID_PATH' /** The data failed the entity's own schema. Carries the zod issue's `path`. */ | 'INVALID_DATA'
18
+ /** The kind or the operation isn't offered here — an unknown kind, a kind with no create op, a
19
+ * field that isn't a sub-entity collection, a derived kind asked for anything but an override. */
20
+ | 'UNSUPPORTED'
21
+ /** A delete that something still points at. Carries the referrers, because "42 things break" is
22
+ * only actionable as a list of which ones. */
23
+ | 'REFERRERS_BLOCK';
24
+ interface ConfigIssue {
25
+ readonly code: ConfigIssueCode;
26
+ readonly message: string;
27
+ /** Where in the written data the problem is (`['layers','icon','bg']`) — zod's own path, for the
28
+ * `INVALID_DATA` issues that have one. Absent for the target-shaped codes, which are about the
29
+ * patch's address rather than its body. */
30
+ readonly path?: (string | number)[];
31
+ }
32
+ /**
33
+ * A write this config refused. `issues` is never empty; `message` joins them so an uncaught one still
34
+ * reads well in a log.
35
+ */
36
+ declare class ConfigRejection extends Error {
37
+ readonly issues: readonly ConfigIssue[];
38
+ /** Which op of an `edit` batch was refused, by position. Absent for a refusal outside a batch. */
39
+ readonly opIndex?: number;
40
+ constructor(issues: readonly ConfigIssue[], {
41
+ opIndex
42
+ }?: {
43
+ opIndex?: number;
44
+ });
45
+ }
46
+ declare function isConfigRejection(value: unknown): value is ConfigRejection;
47
+ /**
48
+ * A serialized config this build cannot read: not a config-v2 artifact at all, one whose `options`
49
+ * slot holds a value no migration placed, or one stamped newer than this build reads
50
+ * (`SchemaVersionTooNew`). Distinct from {@link ConfigRejection}, which refuses a write to a config
51
+ * that loaded. The message names the fix (migrate, rebuild, or upgrade).
52
+ */
53
+ declare class ConfigFormatError extends Error {
54
+ constructor(message: string);
55
+ }
56
+ declare function isConfigFormatError(value: unknown): value is ConfigFormatError;
57
+ //#endregion
58
+ export { ConfigFormatError, ConfigIssue, ConfigIssueCode, ConfigRejection, isConfigFormatError, isConfigRejection };
@@ -0,0 +1,111 @@
1
+ //#region src/framework/rejection.ts
2
+ /**
3
+ * A write this config refused. `issues` is never empty; `message` joins them so an uncaught one still
4
+ * reads well in a log.
5
+ */
6
+ var ConfigRejection = class extends Error {
7
+ issues;
8
+ /** Which op of an `edit` batch was refused, by position. Absent for a refusal outside a batch. */
9
+ opIndex;
10
+ constructor(issues, { opIndex } = {}) {
11
+ super(issues.map((issue) => issue.message).join("; "));
12
+ this.name = "ConfigRejection";
13
+ this.issues = issues;
14
+ if (opIndex !== void 0) this.opIndex = opIndex;
15
+ }
16
+ };
17
+ function isConfigRejection(value) {
18
+ if (value instanceof ConfigRejection) return true;
19
+ return value instanceof Error && value.name === "ConfigRejection" && Array.isArray(value.issues);
20
+ }
21
+ /** Refuse a write for a reason about its target — one issue, no path. */
22
+ function reject(code, message) {
23
+ throw new ConfigRejection([{
24
+ code,
25
+ message
26
+ }]);
27
+ }
28
+ /**
29
+ * Refuse a write because the data isn't the shape the op takes, where no zod issue says so — the value
30
+ * never reached a schema. A merge's delta is the case: it is applied and the result validated, so a
31
+ * delta that isn't an object has to be refused before the merge walks it as one.
32
+ */
33
+ function rejectData(message, path) {
34
+ throw new ConfigRejection([{
35
+ code: "INVALID_DATA",
36
+ message,
37
+ ...path ? { path } : {}
38
+ }]);
39
+ }
40
+ /**
41
+ * Refuse a write because the data failed a schema — one issue per zod issue, each keeping its path.
42
+ *
43
+ * The path appears twice on purpose: as `path`, for a surface that wants to point at the field, and
44
+ * inside `message`, because a message has to stand alone. Every consumer shows the message, and a
45
+ * caller that reads only `path` is the exception — so dropping it from the prose turned
46
+ * "layers.icon.bg — Invalid input" into "Invalid input", which is the one thing a rejection must not do.
47
+ *
48
+ * `context` says what was being written (`Invalid component styles create`), so the whole line reads
49
+ * the way the single-string throw it replaced did.
50
+ */
51
+ function rejectInvalid(context, error) {
52
+ throw new ConfigRejection(refusalIssues(error).map((issue) => {
53
+ const path = issuePath(issue);
54
+ return {
55
+ code: "INVALID_DATA",
56
+ message: `${context}: ${path.join(".") || "(root)"} — ${issue.message}`,
57
+ ...path.length > 0 ? { path } : {}
58
+ };
59
+ }));
60
+ }
61
+ /**
62
+ * The issues a refusal reports. A union no member matched is one issue. A union that failed because a
63
+ * member's own check refused the value reports that member's issues instead, at the union's path: the
64
+ * check's sentence is the one a writer can act on, and "Invalid input" is not.
65
+ */
66
+ function refusalIssues(error) {
67
+ const out = [];
68
+ for (const issue of error.issues) {
69
+ if (issue.code !== "invalid_union") {
70
+ out.push(issue);
71
+ continue;
72
+ }
73
+ const refused = issue.errors.flat().filter((inner) => inner.code === "custom").map((inner) => ({
74
+ ...inner,
75
+ path: [...issue.path, ...inner.path]
76
+ }));
77
+ out.push(...refused.length > 0 ? refused : [issue]);
78
+ }
79
+ return out;
80
+ }
81
+ /**
82
+ * One zod issue's path, with the offending key appended when zod reports it separately.
83
+ *
84
+ * A strict object rejecting an unknown key paths at the object (`layers.icon`) and names the key in
85
+ * `keys` — so the naive read gives a caller the bag rather than the field, which for the case this
86
+ * exists to serve (a style rule setting a prop its layer's element can't take) is the one thing worth
87
+ * knowing. Only the first key: the path addresses a single field, and an issue listing several is a
88
+ * bag with several unknown keys, which the message already spells out in full.
89
+ */
90
+ function issuePath(issue) {
91
+ const path = [...issue.path];
92
+ if (issue.code === "unrecognized_keys" && issue.keys.length > 0) return [...path, issue.keys[0]];
93
+ return path;
94
+ }
95
+ /**
96
+ * A serialized config this build cannot read: not a config-v2 artifact at all, one whose `options`
97
+ * slot holds a value no migration placed, or one stamped newer than this build reads
98
+ * (`SchemaVersionTooNew`). Distinct from {@link ConfigRejection}, which refuses a write to a config
99
+ * that loaded. The message names the fix (migrate, rebuild, or upgrade).
100
+ */
101
+ var ConfigFormatError = class extends Error {
102
+ constructor(message) {
103
+ super(message);
104
+ this.name = "ConfigFormatError";
105
+ }
106
+ };
107
+ function isConfigFormatError(value) {
108
+ return value instanceof ConfigFormatError;
109
+ }
110
+ //#endregion
111
+ export { ConfigFormatError, ConfigRejection, isConfigFormatError, isConfigRejection, issuePath, refusalIssues, reject, rejectData, rejectInvalid };
@@ -0,0 +1,26 @@
1
+ import { Config } from "./Config.js";
2
+
3
+ //#region src/framework/rename-inference.d.ts
4
+ /** One name that moved. `bodyMatches` separates "certainly" from "probably" — see {@link inferredRenames}. */
5
+ interface InferredRename {
6
+ readonly kind: string;
7
+ readonly from: string;
8
+ readonly to: string;
9
+ /** Whether the arrived entity's body is byte-identical to the one that left. False means the author
10
+ * changed the value in the same edit, which is ordinary — it just isn't corroboration. */
11
+ readonly bodyMatches: boolean;
12
+ }
13
+ /**
14
+ * The renames that explain the difference between `previous` and `current`.
15
+ *
16
+ * Per kind: pair what LEFT against what ARRIVED, by body first and by count second.
17
+ *
18
+ * - a body that appears once on each side pairs those two, whatever their paths — which is what
19
+ * catches a move between groups, and what keeps two renames in one edit from crossing over
20
+ * - one leaving and one arriving with nothing else to confuse them pairs on the count alone, since a
21
+ * rename may perfectly well change the value too
22
+ * - anything else is ambiguous and yields nothing
23
+ */
24
+ declare function inferredRenames(previous: Config, current: Config): InferredRename[];
25
+ //#endregion
26
+ export { InferredRename, inferredRenames };
@@ -0,0 +1,50 @@
1
+ //#region src/framework/rename-inference.ts
2
+ const bodyOf = (config, kind, path) => JSON.stringify(config.resolve(kind, path)?.toJSON() ?? null);
3
+ /**
4
+ * The renames that explain the difference between `previous` and `current`.
5
+ *
6
+ * Per kind: pair what LEFT against what ARRIVED, by body first and by count second.
7
+ *
8
+ * - a body that appears once on each side pairs those two, whatever their paths — which is what
9
+ * catches a move between groups, and what keeps two renames in one edit from crossing over
10
+ * - one leaving and one arriving with nothing else to confuse them pairs on the count alone, since a
11
+ * rename may perfectly well change the value too
12
+ * - anything else is ambiguous and yields nothing
13
+ */
14
+ function inferredRenames(previous, current) {
15
+ const found = [];
16
+ for (const kind of current.ownedKinds()) {
17
+ if (!previous.ownedKinds().includes(kind)) continue;
18
+ const before = previous.list(kind).map((item) => item.path);
19
+ const after = new Set(current.list(kind).map((item) => item.path));
20
+ const gone = before.filter((path) => !after.has(path));
21
+ const arrived = [...after].filter((path) => !before.includes(path));
22
+ if (gone.length === 0 || arrived.length === 0) continue;
23
+ const unpairedGone = new Set(gone);
24
+ const unpairedArrived = new Set(arrived);
25
+ for (const from of gone) {
26
+ const body = bodyOf(previous, kind, from);
27
+ if (gone.filter((path) => bodyOf(previous, kind, path) === body).length !== 1) continue;
28
+ const matches = arrived.filter((path) => bodyOf(current, kind, path) === body);
29
+ if (matches.length !== 1) continue;
30
+ const to = matches[0];
31
+ found.push({
32
+ kind,
33
+ from,
34
+ to,
35
+ bodyMatches: true
36
+ });
37
+ unpairedGone.delete(from);
38
+ unpairedArrived.delete(to);
39
+ }
40
+ if (unpairedGone.size === 1 && unpairedArrived.size === 1) found.push({
41
+ kind,
42
+ from: [...unpairedGone][0],
43
+ to: [...unpairedArrived][0],
44
+ bodyMatches: false
45
+ });
46
+ }
47
+ return found;
48
+ }
49
+ //#endregion
50
+ export { inferredRenames };