@transitrix/diagrams 1.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 (541) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +47 -0
  3. package/dist/__tests__/edge-path.test.d.ts +1 -0
  4. package/dist/__tests__/edge-path.test.js +39 -0
  5. package/dist/__tests__/scope.test.d.ts +1 -0
  6. package/dist/__tests__/scope.test.js +23 -0
  7. package/dist/__tests__/yaml-normalize.test.d.ts +1 -0
  8. package/dist/__tests__/yaml-normalize.test.js +148 -0
  9. package/dist/activities/__tests__/cpm.test.d.ts +1 -0
  10. package/dist/activities/__tests__/cpm.test.js +146 -0
  11. package/dist/activities/__tests__/gantt.test.d.ts +1 -0
  12. package/dist/activities/__tests__/gantt.test.js +224 -0
  13. package/dist/activities/__tests__/layout.test.d.ts +1 -0
  14. package/dist/activities/__tests__/layout.test.js +98 -0
  15. package/dist/activities/__tests__/validate.test.d.ts +1 -0
  16. package/dist/activities/__tests__/validate.test.js +363 -0
  17. package/dist/activities/cpm.d.ts +2 -0
  18. package/dist/activities/cpm.js +86 -0
  19. package/dist/activities/gantt.d.ts +6 -0
  20. package/dist/activities/gantt.js +250 -0
  21. package/dist/activities/index.d.ts +5 -0
  22. package/dist/activities/index.js +4 -0
  23. package/dist/activities/layout.d.ts +2 -0
  24. package/dist/activities/layout.js +103 -0
  25. package/dist/activities/types.d.ts +125 -0
  26. package/dist/activities/types.js +1 -0
  27. package/dist/activities/validate.d.ts +2 -0
  28. package/dist/activities/validate.js +326 -0
  29. package/dist/activity-card/__tests__/example.test.d.ts +1 -0
  30. package/dist/activity-card/__tests__/example.test.js +56 -0
  31. package/dist/activity-card/__tests__/layout.test.d.ts +1 -0
  32. package/dist/activity-card/__tests__/layout.test.js +57 -0
  33. package/dist/activity-card/__tests__/resolver.test.d.ts +1 -0
  34. package/dist/activity-card/__tests__/resolver.test.js +146 -0
  35. package/dist/activity-card/__tests__/validate.test.d.ts +1 -0
  36. package/dist/activity-card/__tests__/validate.test.js +116 -0
  37. package/dist/activity-card/index.d.ts +5 -0
  38. package/dist/activity-card/index.js +3 -0
  39. package/dist/activity-card/layout.d.ts +7 -0
  40. package/dist/activity-card/layout.js +167 -0
  41. package/dist/activity-card/resolver.d.ts +7 -0
  42. package/dist/activity-card/resolver.js +310 -0
  43. package/dist/activity-card/types.d.ts +175 -0
  44. package/dist/activity-card/types.js +20 -0
  45. package/dist/activity-card/validate.d.ts +3 -0
  46. package/dist/activity-card/validate.js +145 -0
  47. package/dist/actor/__tests__/validate.test.d.ts +1 -0
  48. package/dist/actor/__tests__/validate.test.js +57 -0
  49. package/dist/actor/index.d.ts +3 -0
  50. package/dist/actor/index.js +2 -0
  51. package/dist/actor/types.d.ts +20 -0
  52. package/dist/actor/types.js +4 -0
  53. package/dist/actor/validate.d.ts +2 -0
  54. package/dist/actor/validate.js +34 -0
  55. package/dist/applications/__tests__/validate.test.d.ts +1 -0
  56. package/dist/applications/__tests__/validate.test.js +223 -0
  57. package/dist/applications/index.d.ts +2 -0
  58. package/dist/applications/index.js +1 -0
  59. package/dist/applications/types.d.ts +39 -0
  60. package/dist/applications/types.js +1 -0
  61. package/dist/applications/validate.d.ts +3 -0
  62. package/dist/applications/validate.js +109 -0
  63. package/dist/assertion/__tests__/example.test.d.ts +1 -0
  64. package/dist/assertion/__tests__/example.test.js +32 -0
  65. package/dist/assertion/__tests__/validate.test.d.ts +1 -0
  66. package/dist/assertion/__tests__/validate.test.js +130 -0
  67. package/dist/assertion/index.d.ts +4 -0
  68. package/dist/assertion/index.js +2 -0
  69. package/dist/assertion/types.d.ts +43 -0
  70. package/dist/assertion/types.js +7 -0
  71. package/dist/assertion/validate.d.ts +9 -0
  72. package/dist/assertion/validate.js +137 -0
  73. package/dist/blocks/__tests__/layout.test.d.ts +1 -0
  74. package/dist/blocks/__tests__/layout.test.js +153 -0
  75. package/dist/blocks/__tests__/validate.test.d.ts +1 -0
  76. package/dist/blocks/__tests__/validate.test.js +235 -0
  77. package/dist/blocks/index.d.ts +4 -0
  78. package/dist/blocks/index.js +2 -0
  79. package/dist/blocks/layout.d.ts +4 -0
  80. package/dist/blocks/layout.js +145 -0
  81. package/dist/blocks/types.d.ts +56 -0
  82. package/dist/blocks/types.js +1 -0
  83. package/dist/blocks/validate.d.ts +9 -0
  84. package/dist/blocks/validate.js +186 -0
  85. package/dist/capability-map/__tests__/validate.test.d.ts +1 -0
  86. package/dist/capability-map/__tests__/validate.test.js +212 -0
  87. package/dist/capability-map/index.d.ts +2 -0
  88. package/dist/capability-map/index.js +1 -0
  89. package/dist/capability-map/types.d.ts +26 -0
  90. package/dist/capability-map/types.js +1 -0
  91. package/dist/capability-map/validate.d.ts +3 -0
  92. package/dist/capability-map/validate.js +103 -0
  93. package/dist/change/__tests__/validate.test.d.ts +1 -0
  94. package/dist/change/__tests__/validate.test.js +73 -0
  95. package/dist/change/index.d.ts +2 -0
  96. package/dist/change/index.js +1 -0
  97. package/dist/change/types.d.ts +17 -0
  98. package/dist/change/types.js +3 -0
  99. package/dist/change/validate.d.ts +2 -0
  100. package/dist/change/validate.js +57 -0
  101. package/dist/compliance/__tests__/classify.test.d.ts +1 -0
  102. package/dist/compliance/__tests__/classify.test.js +24 -0
  103. package/dist/compliance/__tests__/confidence.test.d.ts +1 -0
  104. package/dist/compliance/__tests__/confidence.test.js +78 -0
  105. package/dist/compliance/__tests__/coverage-metric.test.d.ts +1 -0
  106. package/dist/compliance/__tests__/coverage-metric.test.js +164 -0
  107. package/dist/compliance/__tests__/demo-scenario.test.d.ts +1 -0
  108. package/dist/compliance/__tests__/demo-scenario.test.js +226 -0
  109. package/dist/compliance/__tests__/example.test.d.ts +1 -0
  110. package/dist/compliance/__tests__/example.test.js +51 -0
  111. package/dist/compliance/__tests__/gap-report.test.d.ts +1 -0
  112. package/dist/compliance/__tests__/gap-report.test.js +113 -0
  113. package/dist/compliance/__tests__/html.test.d.ts +1 -0
  114. package/dist/compliance/__tests__/html.test.js +122 -0
  115. package/dist/compliance/__tests__/impact.test.d.ts +1 -0
  116. package/dist/compliance/__tests__/impact.test.js +410 -0
  117. package/dist/compliance/__tests__/markdown.test.d.ts +1 -0
  118. package/dist/compliance/__tests__/markdown.test.js +85 -0
  119. package/dist/compliance/__tests__/views.test.d.ts +1 -0
  120. package/dist/compliance/__tests__/views.test.js +59 -0
  121. package/dist/compliance/classify.d.ts +27 -0
  122. package/dist/compliance/classify.js +60 -0
  123. package/dist/compliance/confidence.d.ts +27 -0
  124. package/dist/compliance/confidence.js +43 -0
  125. package/dist/compliance/coverage-metric.d.ts +74 -0
  126. package/dist/compliance/coverage-metric.js +181 -0
  127. package/dist/compliance/gap-report.d.ts +20 -0
  128. package/dist/compliance/gap-report.js +64 -0
  129. package/dist/compliance/html.d.ts +22 -0
  130. package/dist/compliance/html.js +256 -0
  131. package/dist/compliance/impact.d.ts +251 -0
  132. package/dist/compliance/impact.js +464 -0
  133. package/dist/compliance/index.d.ts +16 -0
  134. package/dist/compliance/index.js +9 -0
  135. package/dist/compliance/markdown.d.ts +18 -0
  136. package/dist/compliance/markdown.js +129 -0
  137. package/dist/compliance/reverse-index.d.ts +8 -0
  138. package/dist/compliance/reverse-index.js +30 -0
  139. package/dist/compliance/types.d.ts +98 -0
  140. package/dist/compliance/types.js +5 -0
  141. package/dist/compliance/views.d.ts +14 -0
  142. package/dist/compliance/views.js +35 -0
  143. package/dist/compliance-matrix/__tests__/build.test.d.ts +1 -0
  144. package/dist/compliance-matrix/__tests__/build.test.js +183 -0
  145. package/dist/compliance-matrix/__tests__/example.test.d.ts +1 -0
  146. package/dist/compliance-matrix/__tests__/example.test.js +49 -0
  147. package/dist/compliance-matrix/build.d.ts +18 -0
  148. package/dist/compliance-matrix/build.js +0 -0
  149. package/dist/compliance-matrix/index.d.ts +2 -0
  150. package/dist/compliance-matrix/index.js +1 -0
  151. package/dist/compliance-matrix/types.d.ts +86 -0
  152. package/dist/compliance-matrix/types.js +8 -0
  153. package/dist/confidence/__tests__/score.test.d.ts +1 -0
  154. package/dist/confidence/__tests__/score.test.js +188 -0
  155. package/dist/confidence/index.d.ts +2 -0
  156. package/dist/confidence/index.js +1 -0
  157. package/dist/confidence/score.d.ts +62 -0
  158. package/dist/confidence/score.js +215 -0
  159. package/dist/confidence/types.d.ts +79 -0
  160. package/dist/confidence/types.js +6 -0
  161. package/dist/edge-path.d.ts +18 -0
  162. package/dist/edge-path.js +35 -0
  163. package/dist/element-envelope.d.ts +15 -0
  164. package/dist/element-envelope.js +55 -0
  165. package/dist/factor/__tests__/validate.test.d.ts +1 -0
  166. package/dist/factor/__tests__/validate.test.js +83 -0
  167. package/dist/factor/index.d.ts +3 -0
  168. package/dist/factor/index.js +2 -0
  169. package/dist/factor/types.d.ts +23 -0
  170. package/dist/factor/types.js +6 -0
  171. package/dist/factor/validate.d.ts +2 -0
  172. package/dist/factor/validate.js +69 -0
  173. package/dist/fgca/__tests__/chain-table.test.d.ts +1 -0
  174. package/dist/fgca/__tests__/chain-table.test.js +158 -0
  175. package/dist/fgca/__tests__/layout.test.d.ts +1 -0
  176. package/dist/fgca/__tests__/layout.test.js +140 -0
  177. package/dist/fgca/__tests__/parse-canonical.test.d.ts +1 -0
  178. package/dist/fgca/__tests__/parse-canonical.test.js +224 -0
  179. package/dist/fgca/__tests__/preview-layout.test.d.ts +1 -0
  180. package/dist/fgca/__tests__/preview-layout.test.js +106 -0
  181. package/dist/fgca/__tests__/validate.test.d.ts +1 -0
  182. package/dist/fgca/__tests__/validate.test.js +125 -0
  183. package/dist/fgca/chain-table.d.ts +36 -0
  184. package/dist/fgca/chain-table.js +177 -0
  185. package/dist/fgca/index.d.ts +16 -0
  186. package/dist/fgca/index.js +11 -0
  187. package/dist/fgca/layout.d.ts +27 -0
  188. package/dist/fgca/layout.js +156 -0
  189. package/dist/fgca/nodeTypes.d.ts +6 -0
  190. package/dist/fgca/nodeTypes.js +10 -0
  191. package/dist/fgca/nodes/FGCAActivityNode.d.ts +13 -0
  192. package/dist/fgca/nodes/FGCAActivityNode.js +35 -0
  193. package/dist/fgca/nodes/FGCAChangeNode.d.ts +12 -0
  194. package/dist/fgca/nodes/FGCAChangeNode.js +35 -0
  195. package/dist/fgca/nodes/FGCAFactorNode.d.ts +12 -0
  196. package/dist/fgca/nodes/FGCAFactorNode.js +35 -0
  197. package/dist/fgca/nodes/FGCAGoalNode.d.ts +14 -0
  198. package/dist/fgca/nodes/FGCAGoalNode.js +40 -0
  199. package/dist/fgca/parse-canonical.d.ts +58 -0
  200. package/dist/fgca/parse-canonical.js +339 -0
  201. package/dist/fgca/preview-layout.d.ts +87 -0
  202. package/dist/fgca/preview-layout.js +122 -0
  203. package/dist/fgca/types.d.ts +39 -0
  204. package/dist/fgca/types.js +7 -0
  205. package/dist/fgca/validate.d.ts +14 -0
  206. package/dist/fgca/validate.js +108 -0
  207. package/dist/geometry.d.ts +7 -0
  208. package/dist/geometry.js +2 -0
  209. package/dist/goals/__tests__/layout.test.d.ts +1 -0
  210. package/dist/goals/__tests__/layout.test.js +153 -0
  211. package/dist/goals/__tests__/mutations.test.d.ts +1 -0
  212. package/dist/goals/__tests__/mutations.test.js +95 -0
  213. package/dist/goals/__tests__/parse-canonical.test.d.ts +1 -0
  214. package/dist/goals/__tests__/parse-canonical.test.js +129 -0
  215. package/dist/goals/__tests__/validate.test.d.ts +1 -0
  216. package/dist/goals/__tests__/validate.test.js +183 -0
  217. package/dist/goals/index.d.ts +6 -0
  218. package/dist/goals/index.js +4 -0
  219. package/dist/goals/layout.d.ts +11 -0
  220. package/dist/goals/layout.js +147 -0
  221. package/dist/goals/mutations.d.ts +6 -0
  222. package/dist/goals/mutations.js +116 -0
  223. package/dist/goals/parse-canonical.d.ts +29 -0
  224. package/dist/goals/parse-canonical.js +257 -0
  225. package/dist/goals/types.d.ts +71 -0
  226. package/dist/goals/types.js +1 -0
  227. package/dist/goals/validate.d.ts +2 -0
  228. package/dist/goals/validate.js +122 -0
  229. package/dist/index.d.ts +23 -0
  230. package/dist/index.js +23 -0
  231. package/dist/issues/__tests__/layout.test.d.ts +1 -0
  232. package/dist/issues/__tests__/layout.test.js +62 -0
  233. package/dist/issues/__tests__/validate.test.d.ts +1 -0
  234. package/dist/issues/__tests__/validate.test.js +82 -0
  235. package/dist/issues/index.d.ts +4 -0
  236. package/dist/issues/index.js +2 -0
  237. package/dist/issues/layout.d.ts +10 -0
  238. package/dist/issues/layout.js +82 -0
  239. package/dist/issues/types.d.ts +61 -0
  240. package/dist/issues/types.js +6 -0
  241. package/dist/issues/validate.d.ts +3 -0
  242. package/dist/issues/validate.js +143 -0
  243. package/dist/process-blueprint/__tests__/compliance-lane.test.d.ts +1 -0
  244. package/dist/process-blueprint/__tests__/compliance-lane.test.js +272 -0
  245. package/dist/process-blueprint/__tests__/layout.test.d.ts +1 -0
  246. package/dist/process-blueprint/__tests__/layout.test.js +159 -0
  247. package/dist/process-blueprint/__tests__/validate.test.d.ts +1 -0
  248. package/dist/process-blueprint/__tests__/validate.test.js +280 -0
  249. package/dist/process-blueprint/index.d.ts +4 -0
  250. package/dist/process-blueprint/index.js +2 -0
  251. package/dist/process-blueprint/layout.d.ts +2 -0
  252. package/dist/process-blueprint/layout.js +416 -0
  253. package/dist/process-blueprint/types.d.ts +220 -0
  254. package/dist/process-blueprint/types.js +1 -0
  255. package/dist/process-blueprint/validate.d.ts +3 -0
  256. package/dist/process-blueprint/validate.js +165 -0
  257. package/dist/process-map/__tests__/validate.test.d.ts +1 -0
  258. package/dist/process-map/__tests__/validate.test.js +199 -0
  259. package/dist/process-map/index.d.ts +2 -0
  260. package/dist/process-map/index.js +1 -0
  261. package/dist/process-map/types.d.ts +32 -0
  262. package/dist/process-map/types.js +1 -0
  263. package/dist/process-map/validate.d.ts +3 -0
  264. package/dist/process-map/validate.js +115 -0
  265. package/dist/products/__tests__/validate.test.d.ts +1 -0
  266. package/dist/products/__tests__/validate.test.js +210 -0
  267. package/dist/products/index.d.ts +2 -0
  268. package/dist/products/index.js +1 -0
  269. package/dist/products/types.d.ts +28 -0
  270. package/dist/products/types.js +1 -0
  271. package/dist/products/validate.d.ts +3 -0
  272. package/dist/products/validate.js +93 -0
  273. package/dist/repo-validate/__tests__/validate-repo.test.d.ts +1 -0
  274. package/dist/repo-validate/__tests__/validate-repo.test.js +132 -0
  275. package/dist/repo-validate/index.d.ts +2 -0
  276. package/dist/repo-validate/index.js +1 -0
  277. package/dist/repo-validate/types.d.ts +34 -0
  278. package/dist/repo-validate/types.js +14 -0
  279. package/dist/repo-validate/validate-repo.d.ts +8 -0
  280. package/dist/repo-validate/validate-repo.js +189 -0
  281. package/dist/requirement/__tests__/example.test.d.ts +1 -0
  282. package/dist/requirement/__tests__/example.test.js +21 -0
  283. package/dist/requirement/__tests__/validate.test.d.ts +1 -0
  284. package/dist/requirement/__tests__/validate.test.js +80 -0
  285. package/dist/requirement/index.d.ts +4 -0
  286. package/dist/requirement/index.js +2 -0
  287. package/dist/requirement/types.d.ts +25 -0
  288. package/dist/requirement/types.js +4 -0
  289. package/dist/requirement/validate.d.ts +7 -0
  290. package/dist/requirement/validate.js +81 -0
  291. package/dist/scenarios/__tests__/validate.test.d.ts +1 -0
  292. package/dist/scenarios/__tests__/validate.test.js +183 -0
  293. package/dist/scenarios/index.d.ts +2 -0
  294. package/dist/scenarios/index.js +1 -0
  295. package/dist/scenarios/types.d.ts +45 -0
  296. package/dist/scenarios/types.js +1 -0
  297. package/dist/scenarios/validate.d.ts +3 -0
  298. package/dist/scenarios/validate.js +110 -0
  299. package/dist/schema-version.d.ts +16 -0
  300. package/dist/schema-version.js +16 -0
  301. package/dist/scope.d.ts +23 -0
  302. package/dist/scope.js +38 -0
  303. package/dist/stakeholder/__tests__/validate.test.d.ts +1 -0
  304. package/dist/stakeholder/__tests__/validate.test.js +86 -0
  305. package/dist/stakeholder/index.d.ts +3 -0
  306. package/dist/stakeholder/index.js +2 -0
  307. package/dist/stakeholder/types.d.ts +24 -0
  308. package/dist/stakeholder/types.js +5 -0
  309. package/dist/stakeholder/validate.d.ts +2 -0
  310. package/dist/stakeholder/validate.js +58 -0
  311. package/dist/target-state/__tests__/validate.test.d.ts +1 -0
  312. package/dist/target-state/__tests__/validate.test.js +62 -0
  313. package/dist/target-state/index.d.ts +2 -0
  314. package/dist/target-state/index.js +1 -0
  315. package/dist/target-state/types.d.ts +18 -0
  316. package/dist/target-state/types.js +7 -0
  317. package/dist/target-state/validate.d.ts +2 -0
  318. package/dist/target-state/validate.js +61 -0
  319. package/dist/theme/index.d.ts +4 -0
  320. package/dist/theme/index.js +2 -0
  321. package/dist/theme/themes.d.ts +16 -0
  322. package/dist/theme/themes.js +213 -0
  323. package/dist/theme/tokens.d.ts +158 -0
  324. package/dist/theme/tokens.js +105 -0
  325. package/dist/typed-id.d.ts +20 -0
  326. package/dist/typed-id.js +38 -0
  327. package/dist/validation-types.d.ts +34 -0
  328. package/dist/validation-types.js +1 -0
  329. package/dist/webview/__tests__/entry-notations.test.d.ts +1 -0
  330. package/dist/webview/__tests__/entry-notations.test.js +62 -0
  331. package/dist/webview/__tests__/entry.test.d.ts +1 -0
  332. package/dist/webview/__tests__/entry.test.js +56 -0
  333. package/dist/webview/__tests__/render-goals.test.d.ts +1 -0
  334. package/dist/webview/__tests__/render-goals.test.js +65 -0
  335. package/dist/webview/entry.d.ts +38 -0
  336. package/dist/webview/entry.js +182 -0
  337. package/dist/webview/render-activities.d.ts +24 -0
  338. package/dist/webview/render-activities.js +127 -0
  339. package/dist/webview/render-activity-card.d.ts +5 -0
  340. package/dist/webview/render-activity-card.js +168 -0
  341. package/dist/webview/render-applications.d.ts +11 -0
  342. package/dist/webview/render-applications.js +105 -0
  343. package/dist/webview/render-blocks.d.ts +5 -0
  344. package/dist/webview/render-blocks.js +71 -0
  345. package/dist/webview/render-capability-map.d.ts +7 -0
  346. package/dist/webview/render-capability-map.js +88 -0
  347. package/dist/webview/render-fgca.d.ts +8 -0
  348. package/dist/webview/render-fgca.js +94 -0
  349. package/dist/webview/render-goals.d.ts +6 -0
  350. package/dist/webview/render-goals.js +92 -0
  351. package/dist/webview/render-process-blueprint.d.ts +5 -0
  352. package/dist/webview/render-process-blueprint.js +135 -0
  353. package/dist/webview/render-process-map.d.ts +7 -0
  354. package/dist/webview/render-process-map.js +82 -0
  355. package/dist/webview/render-products.d.ts +7 -0
  356. package/dist/webview/render-products.js +81 -0
  357. package/dist/webview/render-scenarios.d.ts +7 -0
  358. package/dist/webview/render-scenarios.js +75 -0
  359. package/dist/webview/render-util.d.ts +16 -0
  360. package/dist/webview/render-util.js +31 -0
  361. package/dist/webview/transitrix-render.css +323 -0
  362. package/dist/webview/transitrix-render.js +6452 -0
  363. package/dist/webview/transitrix-render.js.map +7 -0
  364. package/dist/yaml-normalize.d.ts +20 -0
  365. package/dist/yaml-normalize.js +57 -0
  366. package/package.json +40 -0
  367. package/src/__tests__/edge-path.test.ts +46 -0
  368. package/src/__tests__/scope.test.ts +27 -0
  369. package/src/__tests__/yaml-normalize.test.ts +158 -0
  370. package/src/activities/__tests__/cpm.test.ts +164 -0
  371. package/src/activities/__tests__/gantt.test.ts +245 -0
  372. package/src/activities/__tests__/layout.test.ts +112 -0
  373. package/src/activities/__tests__/validate.test.ts +409 -0
  374. package/src/activities/cpm.ts +95 -0
  375. package/src/activities/gantt.ts +276 -0
  376. package/src/activities/index.ts +28 -0
  377. package/src/activities/layout.ts +112 -0
  378. package/src/activities/types.ts +148 -0
  379. package/src/activities/validate.ts +357 -0
  380. package/src/activity-card/__tests__/example.test.ts +66 -0
  381. package/src/activity-card/__tests__/layout.test.ts +63 -0
  382. package/src/activity-card/__tests__/resolver.test.ts +161 -0
  383. package/src/activity-card/__tests__/validate.test.ts +131 -0
  384. package/src/activity-card/index.ts +32 -0
  385. package/src/activity-card/layout.ts +194 -0
  386. package/src/activity-card/resolver.ts +337 -0
  387. package/src/activity-card/types.ts +237 -0
  388. package/src/activity-card/validate.ts +158 -0
  389. package/src/actor/__tests__/validate.test.ts +67 -0
  390. package/src/actor/index.ts +3 -0
  391. package/src/actor/types.ts +29 -0
  392. package/src/actor/validate.ts +38 -0
  393. package/src/applications/__tests__/validate.test.ts +256 -0
  394. package/src/applications/index.ts +11 -0
  395. package/src/applications/types.ts +43 -0
  396. package/src/applications/validate.ts +131 -0
  397. package/src/assertion/__tests__/example.test.ts +37 -0
  398. package/src/assertion/__tests__/validate.test.ts +142 -0
  399. package/src/assertion/index.ts +12 -0
  400. package/src/assertion/types.ts +58 -0
  401. package/src/assertion/validate.ts +145 -0
  402. package/src/blocks/__tests__/layout.test.ts +169 -0
  403. package/src/blocks/__tests__/validate.test.ts +260 -0
  404. package/src/blocks/index.ts +17 -0
  405. package/src/blocks/layout.ts +186 -0
  406. package/src/blocks/types.ts +62 -0
  407. package/src/blocks/validate.ts +206 -0
  408. package/src/capability-map/__tests__/validate.test.ts +238 -0
  409. package/src/capability-map/index.ts +8 -0
  410. package/src/capability-map/types.ts +29 -0
  411. package/src/capability-map/validate.ts +127 -0
  412. package/src/change/__tests__/validate.test.ts +88 -0
  413. package/src/change/index.ts +2 -0
  414. package/src/change/types.ts +23 -0
  415. package/src/change/validate.ts +61 -0
  416. package/src/compliance/__tests__/classify.test.ts +27 -0
  417. package/src/compliance/__tests__/confidence.test.ts +98 -0
  418. package/src/compliance/__tests__/coverage-metric.test.ts +188 -0
  419. package/src/compliance/__tests__/demo-scenario.test.ts +273 -0
  420. package/src/compliance/__tests__/example.test.ts +57 -0
  421. package/src/compliance/__tests__/gap-report.test.ts +129 -0
  422. package/src/compliance/__tests__/html.test.ts +142 -0
  423. package/src/compliance/__tests__/impact.test.ts +482 -0
  424. package/src/compliance/__tests__/markdown.test.ts +95 -0
  425. package/src/compliance/__tests__/views.test.ts +64 -0
  426. package/src/compliance/classify.ts +84 -0
  427. package/src/compliance/confidence.ts +69 -0
  428. package/src/compliance/coverage-metric.ts +263 -0
  429. package/src/compliance/gap-report.ts +94 -0
  430. package/src/compliance/html.ts +295 -0
  431. package/src/compliance/impact.ts +677 -0
  432. package/src/compliance/index.ts +56 -0
  433. package/src/compliance/markdown.ts +135 -0
  434. package/src/compliance/reverse-index.ts +33 -0
  435. package/src/compliance/types.ts +120 -0
  436. package/src/compliance/views.ts +46 -0
  437. package/src/compliance-matrix/__tests__/build.test.ts +200 -0
  438. package/src/compliance-matrix/__tests__/example.test.ts +57 -0
  439. package/src/compliance-matrix/build.ts +0 -0
  440. package/src/compliance-matrix/index.ts +11 -0
  441. package/src/compliance-matrix/types.ts +102 -0
  442. package/src/confidence/__tests__/score.test.ts +254 -0
  443. package/src/confidence/index.ts +21 -0
  444. package/src/confidence/score.ts +243 -0
  445. package/src/confidence/types.ts +96 -0
  446. package/src/edge-path.ts +44 -0
  447. package/src/element-envelope.ts +76 -0
  448. package/src/factor/__tests__/validate.test.ts +98 -0
  449. package/src/factor/index.ts +8 -0
  450. package/src/factor/types.ts +41 -0
  451. package/src/factor/validate.ts +74 -0
  452. package/src/fgca/__tests__/chain-table.test.ts +172 -0
  453. package/src/fgca/__tests__/layout.test.ts +179 -0
  454. package/src/fgca/__tests__/parse-canonical.test.ts +248 -0
  455. package/src/fgca/__tests__/preview-layout.test.ts +124 -0
  456. package/src/fgca/__tests__/validate.test.ts +142 -0
  457. package/src/fgca/chain-table.ts +225 -0
  458. package/src/fgca/index.ts +45 -0
  459. package/src/fgca/layout.ts +204 -0
  460. package/src/fgca/nodeTypes.ts +11 -0
  461. package/src/fgca/nodes/FGCAActivityNode.tsx +65 -0
  462. package/src/fgca/nodes/FGCAChangeNode.tsx +64 -0
  463. package/src/fgca/nodes/FGCAFactorNode.tsx +64 -0
  464. package/src/fgca/nodes/FGCAGoalNode.tsx +72 -0
  465. package/src/fgca/parse-canonical.ts +400 -0
  466. package/src/fgca/preview-layout.ts +217 -0
  467. package/src/fgca/types.ts +50 -0
  468. package/src/fgca/validate.ts +126 -0
  469. package/src/geometry.ts +9 -0
  470. package/src/goals/__tests__/layout.test.ts +175 -0
  471. package/src/goals/__tests__/mutations.test.ts +111 -0
  472. package/src/goals/__tests__/parse-canonical.test.ts +145 -0
  473. package/src/goals/__tests__/validate.test.ts +202 -0
  474. package/src/goals/index.ts +21 -0
  475. package/src/goals/layout.ts +172 -0
  476. package/src/goals/mutations.ts +123 -0
  477. package/src/goals/parse-canonical.ts +286 -0
  478. package/src/goals/types.ts +85 -0
  479. package/src/goals/validate.ts +136 -0
  480. package/src/index.ts +23 -0
  481. package/src/process-blueprint/__tests__/compliance-lane.test.ts +320 -0
  482. package/src/process-blueprint/__tests__/layout.test.ts +195 -0
  483. package/src/process-blueprint/__tests__/validate.test.ts +310 -0
  484. package/src/process-blueprint/index.ts +31 -0
  485. package/src/process-blueprint/layout.ts +531 -0
  486. package/src/process-blueprint/types.ts +242 -0
  487. package/src/process-blueprint/validate.ts +181 -0
  488. package/src/process-map/__tests__/validate.test.ts +223 -0
  489. package/src/process-map/index.ts +10 -0
  490. package/src/process-map/types.ts +36 -0
  491. package/src/process-map/validate.ts +135 -0
  492. package/src/products/__tests__/validate.test.ts +239 -0
  493. package/src/products/index.ts +9 -0
  494. package/src/products/types.ts +31 -0
  495. package/src/products/validate.ts +112 -0
  496. package/src/repo-validate/__tests__/validate-repo.test.ts +149 -0
  497. package/src/repo-validate/index.ts +2 -0
  498. package/src/repo-validate/types.ts +50 -0
  499. package/src/repo-validate/validate-repo.ts +196 -0
  500. package/src/requirement/__tests__/example.test.ts +24 -0
  501. package/src/requirement/__tests__/validate.test.ts +96 -0
  502. package/src/requirement/index.ts +4 -0
  503. package/src/requirement/types.ts +35 -0
  504. package/src/requirement/validate.ts +92 -0
  505. package/src/scenarios/__tests__/validate.test.ts +209 -0
  506. package/src/scenarios/index.ts +15 -0
  507. package/src/scenarios/types.ts +37 -0
  508. package/src/scenarios/validate.ts +122 -0
  509. package/src/schema-version.ts +16 -0
  510. package/src/scope.ts +46 -0
  511. package/src/stakeholder/__tests__/validate.test.ts +101 -0
  512. package/src/stakeholder/index.ts +3 -0
  513. package/src/stakeholder/types.ts +33 -0
  514. package/src/stakeholder/validate.ts +63 -0
  515. package/src/target-state/__tests__/validate.test.ts +74 -0
  516. package/src/target-state/index.ts +2 -0
  517. package/src/target-state/types.ts +28 -0
  518. package/src/target-state/validate.ts +67 -0
  519. package/src/theme/index.ts +4 -0
  520. package/src/theme/themes.ts +237 -0
  521. package/src/theme/tokens.ts +133 -0
  522. package/src/typed-id.ts +56 -0
  523. package/src/validation-types.ts +36 -0
  524. package/src/webview/__tests__/entry-notations.test.ts +77 -0
  525. package/src/webview/__tests__/entry.test.ts +64 -0
  526. package/src/webview/__tests__/render-goals.test.ts +72 -0
  527. package/src/webview/entry.ts +292 -0
  528. package/src/webview/render-activities.ts +156 -0
  529. package/src/webview/render-activity-card.ts +234 -0
  530. package/src/webview/render-applications.ts +123 -0
  531. package/src/webview/render-blocks.ts +91 -0
  532. package/src/webview/render-capability-map.ts +98 -0
  533. package/src/webview/render-fgca.ts +122 -0
  534. package/src/webview/render-goals.ts +110 -0
  535. package/src/webview/render-process-blueprint.ts +207 -0
  536. package/src/webview/render-process-map.ts +93 -0
  537. package/src/webview/render-products.ts +91 -0
  538. package/src/webview/render-scenarios.ts +90 -0
  539. package/src/webview/render-util.ts +34 -0
  540. package/src/webview/styles.css +323 -0
  541. package/src/yaml-normalize.ts +56 -0
@@ -0,0 +1,131 @@
1
+ import { describe, it, expect } from 'vitest';
2
+ import { validateActivityCard } from '../validate.js';
3
+
4
+ const VALID = {
5
+ notation: 'activity-card',
6
+ spec_version: '0.1',
7
+ activity_card: {
8
+ id: 'ACTIVITY_CARD-EU-PROGRAMME-1',
9
+ project: 'ACTIVITY-EU-PROGRAMME-1',
10
+ description: 'Executive summary.',
11
+ milestones: [
12
+ {
13
+ id: 'MILESTONE-EU-CONFORMITY-CERT-1',
14
+ name: 'Certification obtained',
15
+ date: '2027-01-31',
16
+ delivers_changes: ['CHANGE-EU-COMPLIANCE-1'],
17
+ },
18
+ ],
19
+ },
20
+ };
21
+
22
+ describe('validateActivityCard', () => {
23
+ it('accepts a well-formed card', () => {
24
+ const r = validateActivityCard(VALID);
25
+ expect(r.valid).toBe(true);
26
+ expect(r.errors).toHaveLength(0);
27
+ });
28
+
29
+ it('rejects non-object input', () => {
30
+ expect(validateActivityCard('x').valid).toBe(false);
31
+ expect(validateActivityCard(null).valid).toBe(false);
32
+ });
33
+
34
+ it('HDR-001 on missing notation', () => {
35
+ const { notation: _drop, ...rest } = VALID;
36
+ const r = validateActivityCard(rest);
37
+ expect(r.valid).toBe(false);
38
+ expect(r.errors.some((e) => e.code === 'HDR-001')).toBe(true);
39
+ });
40
+
41
+ it('HDR-002 on wrong notation', () => {
42
+ const r = validateActivityCard({ ...VALID, notation: 'activities' });
43
+ expect(r.errors.some((e) => e.code === 'HDR-002')).toBe(true);
44
+ });
45
+
46
+ it('AC-001 on missing activity_card block', () => {
47
+ const r = validateActivityCard({ notation: 'activity-card' });
48
+ expect(r.valid).toBe(false);
49
+ expect(r.errors.some((e) => e.code === 'AC-001')).toBe(true);
50
+ });
51
+
52
+ it('AC-002 on malformed card id', () => {
53
+ const r = validateActivityCard({ ...VALID, activity_card: { ...VALID.activity_card, id: 'CARD-1' } });
54
+ expect(r.errors.some((e) => e.code === 'AC-002')).toBe(true);
55
+ });
56
+
57
+ it('PC-001 on missing project', () => {
58
+ const r = validateActivityCard({
59
+ ...VALID,
60
+ activity_card: { ...VALID.activity_card, project: undefined },
61
+ });
62
+ expect(r.errors.some((e) => e.code === 'PC-001')).toBe(true);
63
+ });
64
+
65
+ it('PC-001 on malformed project id', () => {
66
+ const r = validateActivityCard({
67
+ ...VALID,
68
+ activity_card: { ...VALID.activity_card, project: 'GOAL-1' },
69
+ });
70
+ expect(r.errors.some((e) => e.code === 'PC-001')).toBe(true);
71
+ });
72
+
73
+ it('AC-003 on milestone missing required fields', () => {
74
+ const r = validateActivityCard({
75
+ ...VALID,
76
+ activity_card: { ...VALID.activity_card, milestones: [{ id: 'MILESTONE-X-1' }] },
77
+ });
78
+ expect(r.valid).toBe(false);
79
+ expect(r.errors.some((e) => e.code === 'AC-003')).toBe(true);
80
+ });
81
+
82
+ it('AC-004 on malformed milestone id', () => {
83
+ const r = validateActivityCard({
84
+ ...VALID,
85
+ activity_card: {
86
+ ...VALID.activity_card,
87
+ milestones: [{ id: 'MS-1', name: 'x', date: '2027-01-01' }],
88
+ },
89
+ });
90
+ expect(r.errors.some((e) => e.code === 'AC-004')).toBe(true);
91
+ });
92
+
93
+ it('AC-004 on duplicate milestone id', () => {
94
+ const m = { id: 'MILESTONE-X-1', name: 'x', date: '2027-01-01' };
95
+ const r = validateActivityCard({
96
+ ...VALID,
97
+ activity_card: { ...VALID.activity_card, milestones: [m, { ...m }] },
98
+ });
99
+ expect(r.errors.some((e) => e.code === 'AC-004' && /Duplicate/.test(e.message))).toBe(true);
100
+ });
101
+
102
+ it('AC-005 on bad milestone date format', () => {
103
+ const r = validateActivityCard({
104
+ ...VALID,
105
+ activity_card: {
106
+ ...VALID.activity_card,
107
+ milestones: [{ id: 'MILESTONE-X-1', name: 'x', date: '31/01/2027' }],
108
+ },
109
+ });
110
+ expect(r.errors.some((e) => e.code === 'AC-005')).toBe(true);
111
+ });
112
+
113
+ it('AC-006 on malformed delivers_changes entry', () => {
114
+ const r = validateActivityCard({
115
+ ...VALID,
116
+ activity_card: {
117
+ ...VALID.activity_card,
118
+ milestones: [{ id: 'MILESTONE-X-1', name: 'x', date: '2027-01-01', delivers_changes: ['GOAL-1'] }],
119
+ },
120
+ });
121
+ expect(r.errors.some((e) => e.code === 'AC-006')).toBe(true);
122
+ });
123
+
124
+ it('accepts a card with no milestones', () => {
125
+ const r = validateActivityCard({
126
+ ...VALID,
127
+ activity_card: { id: 'ACTIVITY_CARD-X-1', project: 'ACTIVITY-X-1' },
128
+ });
129
+ expect(r.valid).toBe(true);
130
+ });
131
+ });
@@ -0,0 +1,32 @@
1
+ export type {
2
+ RawMilestone,
3
+ ActivityCardBlock,
4
+ ActivityCardDoc,
5
+ ActivityCardSources,
6
+ ResolvedProject,
7
+ ResolvedMilestone,
8
+ ResolvedFactor,
9
+ ResolvedGoal,
10
+ ResolvedChange,
11
+ ResolvedMotivation,
12
+ ResolvedChildActivity,
13
+ ResolvedActivityCard,
14
+ DateField,
15
+ MilestoneMarker,
16
+ ChainNode,
17
+ ChainEdge,
18
+ ChildActivityRow,
19
+ SectionHeader,
20
+ ActivityCardLayoutOptions,
21
+ ActivityCardLayout,
22
+ ActivityCardValidationError,
23
+ ActivityCardValidationWarning,
24
+ ActivityCardValidationResult,
25
+ } from './types.js';
26
+
27
+ export { validateActivityCard } from './validate.js';
28
+
29
+ export { resolveActivityCard } from './resolver.js';
30
+ export type { ActivityCardResolution } from './resolver.js';
31
+
32
+ export { layoutActivityCard, ARCHIMATE_CLASS } from './layout.js';
@@ -0,0 +1,194 @@
1
+ // Activity Card — single-page layout (pure geometry; the preview paints SVG).
2
+ //
3
+ // Top-to-bottom card sections (spec §4 / §5):
4
+ // 1. Title — project name
5
+ // 2. Dates band — Initiation (valid_from) · Planned start · Planned end
6
+ // 3. Milestones — narrative timeline, markers left→right by date
7
+ // 4. Motivation — Factors → Goals → Changes columns with F→G→C edges
8
+ // 5. Child activities — activities whose parent = the project
9
+ //
10
+ // The §5.1 ArchiMate-class convention ("(Work Package)", "(Implementation
11
+ // Event)") is applied HERE, derived from element TYPE — there is no
12
+ // archimate_class data field.
13
+
14
+ import type {
15
+ ActivityCardLayout,
16
+ ActivityCardLayoutOptions,
17
+ ChainEdge,
18
+ ChainNode,
19
+ ChildActivityRow,
20
+ DateField,
21
+ MilestoneMarker,
22
+ ResolvedActivityCard,
23
+ SectionHeader,
24
+ } from './types.js';
25
+
26
+ const DEFAULTS = {
27
+ cardWidth: 780,
28
+ columnGap: 28,
29
+ rowGap: 12,
30
+ } as const;
31
+
32
+ // Fixed metrics (px). Kept local — the card has no user-tunable spacing yet.
33
+ const PAD = 20;
34
+ const TITLE_H = 38;
35
+ const DATES_H = 56;
36
+ const SECTION_HEADER_H = 26;
37
+ const SECTION_GAP = 16;
38
+ const MILESTONE_W = 168;
39
+ const MILESTONE_H = 64;
40
+ const MILESTONE_GAP = 16;
41
+ const CHAIN_NODE_H = 46;
42
+ const CHILD_ROW_H = 42;
43
+
44
+ /** ArchiMate class per §5.1 — derived from element TYPE, never stored. */
45
+ export const ARCHIMATE_CLASS = {
46
+ ACTIVITY: 'Work Package',
47
+ MILESTONE: 'Implementation Event',
48
+ } as const;
49
+
50
+ export function layoutActivityCard(
51
+ card: ResolvedActivityCard,
52
+ options?: ActivityCardLayoutOptions,
53
+ ): ActivityCardLayout {
54
+ const opts = { ...DEFAULTS, ...(options ?? {}) };
55
+ const contentX = PAD;
56
+ const contentW = opts.cardWidth - PAD * 2;
57
+
58
+ let cursorY = PAD;
59
+
60
+ // 1. Title
61
+ const title = { name: card.project.name, x: contentX, y: cursorY + TITLE_H / 2 };
62
+ cursorY += TITLE_H;
63
+
64
+ // 2. Dates band — three equal cells.
65
+ const dateDefs: Array<{ label: string; value: string }> = [
66
+ { label: 'Initiation', value: card.project.valid_from ?? '—' },
67
+ { label: 'Planned start', value: card.project.start_date ?? '—' },
68
+ { label: 'Planned end', value: card.project.end_date ?? '—' },
69
+ ];
70
+ const dateGap = 12;
71
+ const dateCellW = (contentW - dateGap * (dateDefs.length - 1)) / dateDefs.length;
72
+ const dateFields: DateField[] = dateDefs.map((d, i) => ({
73
+ label: d.label,
74
+ value: d.value,
75
+ x: contentX + i * (dateCellW + dateGap),
76
+ y: cursorY,
77
+ width: dateCellW,
78
+ height: DATES_H,
79
+ }));
80
+ cursorY += DATES_H + SECTION_GAP;
81
+
82
+ const sectionHeaders: SectionHeader[] = [];
83
+ const pushHeader = (label: string): void => {
84
+ sectionHeaders.push({ label, x: contentX, y: cursorY, width: contentW, height: SECTION_HEADER_H });
85
+ cursorY += SECTION_HEADER_H + 8;
86
+ };
87
+
88
+ // 3. Milestones — timeline markers, wrapped left→right.
89
+ const milestones: MilestoneMarker[] = [];
90
+ if (card.milestones.length > 0) {
91
+ pushHeader('Milestones');
92
+ const perRow = Math.max(1, Math.floor((contentW + MILESTONE_GAP) / (MILESTONE_W + MILESTONE_GAP)));
93
+ const rowStartY = cursorY;
94
+ card.milestones.forEach((m, i) => {
95
+ const col = i % perRow;
96
+ const row = Math.floor(i / perRow);
97
+ milestones.push({
98
+ id: m.id,
99
+ name: m.name,
100
+ date: m.date,
101
+ archimateClass: ARCHIMATE_CLASS.MILESTONE,
102
+ x: contentX + col * (MILESTONE_W + MILESTONE_GAP),
103
+ y: rowStartY + row * (MILESTONE_H + opts.rowGap),
104
+ width: MILESTONE_W,
105
+ height: MILESTONE_H,
106
+ });
107
+ });
108
+ const rows = Math.ceil(card.milestones.length / perRow);
109
+ cursorY = rowStartY + rows * (MILESTONE_H + opts.rowGap) - opts.rowGap + SECTION_GAP;
110
+ }
111
+
112
+ // 4. Motivation chain — Factors | Goals | Changes columns.
113
+ const chainEdges: ChainEdge[] = [];
114
+ const factorsCol: ChainNode[] = [];
115
+ const goalsCol: ChainNode[] = [];
116
+ const changesCol: ChainNode[] = [];
117
+ const { factors, goals, changes } = card.motivation;
118
+ if (factors.length + goals.length + changes.length > 0) {
119
+ pushHeader('Motivation — Factors → Goals → Changes');
120
+ const colW = (contentW - opts.columnGap * 2) / 3;
121
+ const colX = [contentX, contentX + colW + opts.columnGap, contentX + (colW + opts.columnGap) * 2];
122
+ const colStartY = cursorY;
123
+
124
+ const stack = (items: { id: string; name: string }[], colIndex: number, into: ChainNode[]) => {
125
+ items.forEach((it, i) => {
126
+ into.push({
127
+ id: it.id,
128
+ name: it.name,
129
+ x: colX[colIndex],
130
+ y: colStartY + i * (CHAIN_NODE_H + opts.rowGap),
131
+ width: colW,
132
+ height: CHAIN_NODE_H,
133
+ });
134
+ });
135
+ };
136
+ stack(factors, 0, factorsCol);
137
+ stack(goals, 1, goalsCol);
138
+ stack(changes, 2, changesCol);
139
+
140
+ // Edges: factor→goal (goal.factorIds), goal→change (change.goalIds).
141
+ const factorIds = new Set(factorsCol.map((n) => n.id));
142
+ const goalIds = new Set(goalsCol.map((n) => n.id));
143
+ for (const g of goals) {
144
+ for (const fid of g.factorIds) {
145
+ if (factorIds.has(fid)) chainEdges.push({ sourceId: fid, targetId: g.id });
146
+ }
147
+ }
148
+ for (const c of changes) {
149
+ for (const gid of c.goalIds) {
150
+ if (goalIds.has(gid)) chainEdges.push({ sourceId: gid, targetId: c.id });
151
+ }
152
+ }
153
+
154
+ const tallest = Math.max(factorsCol.length, goalsCol.length, changesCol.length);
155
+ cursorY = colStartY + tallest * (CHAIN_NODE_H + opts.rowGap) - opts.rowGap + SECTION_GAP;
156
+ }
157
+
158
+ // 5. Child activities — full-width rows.
159
+ const childActivities: ChildActivityRow[] = [];
160
+ if (card.childActivities.length > 0) {
161
+ pushHeader('Child activities');
162
+ const rowStartY = cursorY;
163
+ card.childActivities.forEach((a, i) => {
164
+ const metaBits: string[] = [];
165
+ if (a.start_date || a.end_date) metaBits.push(`${a.start_date ?? '?'} → ${a.end_date ?? '?'}`);
166
+ if (a.owner) metaBits.push(a.owner);
167
+ childActivities.push({
168
+ id: a.id,
169
+ name: a.name,
170
+ archimateClass: ARCHIMATE_CLASS.ACTIVITY,
171
+ meta: metaBits.join(' · '),
172
+ x: contentX,
173
+ y: rowStartY + i * (CHILD_ROW_H + opts.rowGap),
174
+ width: contentW,
175
+ height: CHILD_ROW_H,
176
+ });
177
+ });
178
+ cursorY =
179
+ rowStartY + card.childActivities.length * (CHILD_ROW_H + opts.rowGap) - opts.rowGap + SECTION_GAP;
180
+ }
181
+
182
+ const totalHeight = cursorY - SECTION_GAP + PAD;
183
+
184
+ return {
185
+ bounds: { x: 0, y: 0, width: opts.cardWidth, height: Math.max(totalHeight, PAD * 2 + TITLE_H) },
186
+ title,
187
+ dateFields,
188
+ sectionHeaders,
189
+ milestones,
190
+ chainColumns: { factors: factorsCol, goals: goalsCol, changes: changesCol },
191
+ chainEdges,
192
+ childActivities,
193
+ };
194
+ }
@@ -0,0 +1,337 @@
1
+ // Activity Card — cross-document resolver (the novel piece of this notation).
2
+ //
3
+ // Unlike every other Studio preview, the Activity Card is assembled from
4
+ // MULTIPLE documents. The card YAML names a project Activity; the resolver
5
+ // pulls the rest of the card's content BY REFERENCE from the canonical
6
+ // ELEMENT and RELATION store — never from other view documents (view-purity:
7
+ // a view is a projection over elements + relations, methodology
8
+ // ELEMENT_PRIMITIVES.md §1):
9
+ //
10
+ // canon/elements/** → one element per file. The project ACTIVITY (name,
11
+ // lifecycle + schedule dates, delivers_changes[],
12
+ // parent) and its child ACTIVITY elements (parent =
13
+ // project id); the FACTOR / GOAL / CHANGE elements that
14
+ // the motivation chain expands (goal.factors,
15
+ // change.goals carried inline on the elements).
16
+ // canon/relations/** → `notation: relation` files. The project's goals come
17
+ // from the first-class `activity_goal` REL (from =
18
+ // project id), preferred over the activity element's
19
+ // transitional inline `goals[]` when present
20
+ // (07-activities.md §"Time-aware relations").
21
+ //
22
+ // The extension reads + parses the element and relation files (walking the
23
+ // org's `canon/elements` and `canon/relations` trees) and hands the parsed
24
+ // docs in. This resolver is filesystem-free and pure so it stays unit-testable.
25
+ //
26
+ // Cross-document validation lives here (the rules that need the sibling docs):
27
+ // PC-001 project does not resolve to an admitted Activity
28
+ // PC-002 resolved Activity has activity_type other than "Project"
29
+ // PC-003 milestone.delivers_changes[] entry not in the project's own
30
+ // delivers_changes[]
31
+ // PC-004 (warning) milestone.date outside [valid_from, valid_to]
32
+ // LIFECYCLE-001 project valid_from missing / not a parseable ISO date
33
+ // LIFECYCLE-002 project valid_to present, not null, not a parseable date
34
+ // LIFECYCLE-003 project valid_to earlier than valid_from
35
+ //
36
+ // LIFECYCLE-* are scoped to the RESOLVED PROJECT Activity only — the card is
37
+ // built around the project's initiation date, so a missing valid_from there is
38
+ // a hard error. Child activities and FGCA elements are not lifecycle-checked
39
+ // here (out of this notation's scope; today's Studio activities docs may
40
+ // legitimately omit lifecycle fields).
41
+
42
+ import type {
43
+ ActivityCardDoc,
44
+ ActivityCardSources,
45
+ ResolvedActivityCard,
46
+ ResolvedChange,
47
+ ResolvedChildActivity,
48
+ ResolvedFactor,
49
+ ResolvedGoal,
50
+ ResolvedMilestone,
51
+ ResolvedProject,
52
+ } from './types.js';
53
+ import type { ValidationError, ValidationWarning, ValidationResult } from '../validation-types.js';
54
+
55
+ const DATE_RE = /^\d{4}-\d{2}-\d{2}$/;
56
+
57
+ export interface ActivityCardResolution extends ValidationResult {
58
+ /** Present only when resolution succeeded (project found + valid_from OK). */
59
+ resolved?: ResolvedActivityCard;
60
+ }
61
+
62
+ function isObject(v: unknown): v is Record<string, unknown> {
63
+ return !!v && typeof v === 'object' && !Array.isArray(v);
64
+ }
65
+
66
+ function str(v: unknown): string | undefined {
67
+ return typeof v === 'string' && v.trim().length > 0 ? v : undefined;
68
+ }
69
+
70
+ function strArray(v: unknown): string[] {
71
+ if (!Array.isArray(v)) return [];
72
+ return v.filter((x): x is string => typeof x === 'string' && x.trim().length > 0);
73
+ }
74
+
75
+ /** A parseable quoted ISO 8601 date, calendar-checked (rejects 2026-13-40). */
76
+ function isIsoDate(v: unknown): v is string {
77
+ if (typeof v !== 'string' || !DATE_RE.test(v)) return false;
78
+ const t = Date.parse(`${v}T00:00:00Z`);
79
+ if (Number.isNaN(t)) return false;
80
+ // Round-trip guard so 2026-02-30 (which Date.parse may roll forward) is rejected.
81
+ return new Date(t).toISOString().slice(0, 10) === v;
82
+ }
83
+
84
+ /**
85
+ * Index canon element documents of one `notation` by their `id`. Each element
86
+ * is its own single-element file (`notation: activity|factor|goal|change|…`
87
+ * with a top-level `id`); first definition wins.
88
+ */
89
+ function collectByNotation(
90
+ docs: unknown[],
91
+ notation: string,
92
+ ): Map<string, Record<string, unknown>> {
93
+ const out = new Map<string, Record<string, unknown>>();
94
+ for (const doc of docs) {
95
+ if (!isObject(doc)) continue;
96
+ if (str(doc['notation']) !== notation) continue;
97
+ const id = str(doc['id']);
98
+ if (!id) continue;
99
+ if (!out.has(id)) out.set(id, doc); // first definition wins
100
+ }
101
+ return out;
102
+ }
103
+
104
+ /**
105
+ * GOAL ids reached by an *active* `activity_goal` relation originating at
106
+ * `fromId`. A relation with a non-null `valid_to` has ended (the activity was
107
+ * re-aimed) and is excluded — the card shows the currently-served goals.
108
+ */
109
+ function activeActivityGoals(relations: unknown[], fromId: string): string[] {
110
+ const out: string[] = [];
111
+ for (const doc of relations) {
112
+ if (!isObject(doc)) continue;
113
+ if (str(doc['notation']) !== 'relation') continue;
114
+ if (str(doc['type']) !== 'activity_goal') continue;
115
+ if (str(doc['from']) !== fromId) continue;
116
+ const to = str(doc['to']);
117
+ if (!to) continue;
118
+ const validTo = doc['valid_to'];
119
+ if (validTo !== undefined && validTo !== null) continue; // ended relation
120
+ if (!out.includes(to)) out.push(to);
121
+ }
122
+ return out;
123
+ }
124
+
125
+ export function resolveActivityCard(
126
+ doc: ActivityCardDoc,
127
+ sources: ActivityCardSources,
128
+ ): ActivityCardResolution {
129
+ const errors: ValidationError[] = [];
130
+ const warnings: ValidationWarning[] = [];
131
+
132
+ const card = doc?.activity_card;
133
+ const projectId = str(card?.project);
134
+ if (!projectId) {
135
+ // Structural validator already flags this; nothing to resolve.
136
+ errors.push({ code: 'PC-001', message: 'activity_card.project is missing' });
137
+ return { valid: false, errors, warnings };
138
+ }
139
+
140
+ const activities = collectByNotation(sources.elements, 'activity');
141
+ const projectRec = activities.get(projectId);
142
+
143
+ // PC-001 — project must resolve to an admitted ACTIVITY element in canon.
144
+ if (!projectRec) {
145
+ errors.push({
146
+ code: 'PC-001',
147
+ message: `activity_card.project "${projectId}" does not resolve to an ACTIVITY element in the canon element store`,
148
+ });
149
+ return { valid: false, errors, warnings };
150
+ }
151
+
152
+ // PC-002 — the resolved Activity should be the project scale. In the element
153
+ // model all activity scales (initiative / programme / project / task) share
154
+ // one ACTIVITY TYPE and `activity_type` references an ActivityType element,
155
+ // so a missing/non-literal value is acceptable; only an explicit, clearly
156
+ // non-project marker is flagged. (Canonical project-identification semantics
157
+ // are tracked as a follow-up internally.)
158
+ const activityType = str(projectRec['activity_type']);
159
+ if (activityType !== undefined && activityType !== 'Project' && activityType !== 'project') {
160
+ errors.push({
161
+ code: 'PC-002',
162
+ message: `Activity "${projectId}" has activity_type "${activityType}", expected the project scale`,
163
+ });
164
+ }
165
+
166
+ // LIFECYCLE-001..003 on the project Activity.
167
+ const validFrom = projectRec['valid_from'];
168
+ const validToRaw = projectRec['valid_to'];
169
+ let validFromOk = false;
170
+ if (validFrom === undefined || validFrom === null) {
171
+ errors.push({ code: 'LIFECYCLE-001', message: `Activity "${projectId}" valid_from is required` });
172
+ } else if (!isIsoDate(validFrom)) {
173
+ errors.push({
174
+ code: 'LIFECYCLE-001',
175
+ message: `Activity "${projectId}" valid_from "${String(validFrom)}" is not a parseable ISO 8601 date`,
176
+ });
177
+ } else {
178
+ validFromOk = true;
179
+ }
180
+
181
+ let validToOk = false;
182
+ const validToPresent = validToRaw !== undefined && validToRaw !== null;
183
+ if (validToPresent) {
184
+ if (!isIsoDate(validToRaw)) {
185
+ errors.push({
186
+ code: 'LIFECYCLE-002',
187
+ message: `Activity "${projectId}" valid_to "${String(validToRaw)}" is not a parseable ISO 8601 date`,
188
+ });
189
+ } else {
190
+ validToOk = true;
191
+ if (validFromOk && (validToRaw as string) < (validFrom as string)) {
192
+ errors.push({
193
+ code: 'LIFECYCLE-003',
194
+ message: `Activity "${projectId}" valid_to "${String(validToRaw)}" is earlier than valid_from "${String(validFrom)}"`,
195
+ });
196
+ }
197
+ }
198
+ }
199
+
200
+ // A failed lifecycle/PC-001 stops us producing a card view-model, but we still
201
+ // return every error collected so the panel lists them all at once.
202
+ const projectChanges = new Set(strArray(projectRec['delivers_changes']));
203
+ // Project goals: prefer the first-class `activity_goal` relations (the
204
+ // canonical, time-aware home for an Activity→Goal link); fall back to the
205
+ // activity element's transitional inline `goals[]` when no relation exists
206
+ // (07-activities.md §"Time-aware relations").
207
+ const relGoalIds = activeActivityGoals(sources.relations, projectId);
208
+ const projectGoalIds = relGoalIds.length > 0 ? relGoalIds : strArray(projectRec['goals']);
209
+
210
+ // PC-003 — each milestone change must be a subset of the project's changes.
211
+ const rawMilestones = Array.isArray(card.milestones) ? card.milestones : [];
212
+ const milestones: ResolvedMilestone[] = [];
213
+ for (const m of rawMilestones) {
214
+ if (!isObject(m)) continue;
215
+ const mid = str(m['id']);
216
+ const mname = str(m['name']);
217
+ const mdate = str(m['date']);
218
+ if (!mid || !mname || !mdate) continue; // structural validator already flagged
219
+ const deliversChanges = strArray(m['delivers_changes']);
220
+ for (const c of deliversChanges) {
221
+ if (!projectChanges.has(c)) {
222
+ errors.push({
223
+ code: 'PC-003',
224
+ message: `Milestone "${mid}" delivers_changes "${c}" is not in project "${projectId}" delivers_changes`,
225
+ });
226
+ }
227
+ }
228
+ // PC-004 — milestone date should fall within the project lifecycle window.
229
+ if (validFromOk && mdate < (validFrom as string)) {
230
+ warnings.push({
231
+ code: 'PC-004',
232
+ message: `Milestone "${mid}" date "${mdate}" is before project valid_from "${String(validFrom)}"`,
233
+ });
234
+ }
235
+ if (validToOk && mdate > (validToRaw as string)) {
236
+ warnings.push({
237
+ code: 'PC-004',
238
+ message: `Milestone "${mid}" date "${mdate}" is after project valid_to "${String(validToRaw)}"`,
239
+ });
240
+ }
241
+ milestones.push({
242
+ id: mid,
243
+ name: mname,
244
+ date: mdate,
245
+ description: str(m['description']),
246
+ deliversChanges,
247
+ });
248
+ }
249
+ milestones.sort((a, b) => (a.date < b.date ? -1 : a.date > b.date ? 1 : 0));
250
+
251
+ // If we have hard errors, surface them without an assembled card.
252
+ if (errors.length > 0) {
253
+ return { valid: false, errors, warnings };
254
+ }
255
+
256
+ // ── Motivation chain — expand against canon FACTOR / GOAL / CHANGE elements ──
257
+ const factorElems = collectByNotation(sources.elements, 'factor');
258
+ const goalElems = collectByNotation(sources.elements, 'goal');
259
+ const changeElems = collectByNotation(sources.elements, 'change');
260
+
261
+ const changes: ResolvedChange[] = [];
262
+ for (const cid of projectChanges) {
263
+ const rec = changeElems.get(cid);
264
+ if (!rec) {
265
+ warnings.push({
266
+ code: 'PC-001',
267
+ message: `Project change "${cid}" not found as a CHANGE element in canon; omitted from the motivation chain`,
268
+ });
269
+ continue;
270
+ }
271
+ changes.push({ id: cid, name: str(rec['name']) ?? cid, goalIds: strArray(rec['goals']) });
272
+ }
273
+
274
+ // Goals shown = the project's declared goals ∪ goals referenced by in-scope
275
+ // changes (so the F→G→C chain stays connected).
276
+ const goalIdSet = new Set<string>(projectGoalIds);
277
+ for (const ch of changes) for (const g of ch.goalIds) goalIdSet.add(g);
278
+
279
+ const goals: ResolvedGoal[] = [];
280
+ for (const gid of goalIdSet) {
281
+ const rec = goalElems.get(gid);
282
+ if (!rec) {
283
+ warnings.push({
284
+ code: 'PC-001',
285
+ message: `Goal "${gid}" not found as a GOAL element in canon; omitted from the motivation chain`,
286
+ });
287
+ continue;
288
+ }
289
+ goals.push({ id: gid, name: str(rec['name']) ?? gid, factorIds: strArray(rec['factors']) });
290
+ }
291
+
292
+ // Factors shown = those referenced by the in-scope goals.
293
+ const factorIdSet = new Set<string>();
294
+ for (const g of goals) for (const f of g.factorIds) factorIdSet.add(f);
295
+
296
+ const factors: ResolvedFactor[] = [];
297
+ for (const fid of factorIdSet) {
298
+ const rec = factorElems.get(fid);
299
+ factors.push({ id: fid, name: rec ? str(rec['name']) ?? fid : fid });
300
+ }
301
+
302
+ // ── Child activities — parent = project id ──────────────────────────────────
303
+ const childActivities: ResolvedChildActivity[] = [];
304
+ for (const [id, rec] of activities) {
305
+ if (str(rec['parent']) !== projectId) continue;
306
+ childActivities.push({
307
+ id,
308
+ name: str(rec['name']) ?? id,
309
+ activity_type: str(rec['activity_type']),
310
+ start_date: str(rec['start_date']),
311
+ end_date: str(rec['end_date']),
312
+ owner: str(rec['owner']),
313
+ });
314
+ }
315
+ childActivities.sort((a, b) => (a.id < b.id ? -1 : a.id > b.id ? 1 : 0));
316
+
317
+ const project: ResolvedProject = {
318
+ id: projectId,
319
+ name: str(projectRec['name']) ?? projectId,
320
+ description: str(projectRec['description']),
321
+ valid_from: validFromOk ? (validFrom as string) : undefined,
322
+ valid_to: validToOk ? (validToRaw as string) : undefined,
323
+ start_date: str(projectRec['start_date']),
324
+ end_date: str(projectRec['end_date']),
325
+ };
326
+
327
+ const resolved: ResolvedActivityCard = {
328
+ cardId: str(card.id) ?? '',
329
+ cardDescription: str(card.description),
330
+ project,
331
+ milestones,
332
+ motivation: { factors, goals, changes },
333
+ childActivities,
334
+ };
335
+
336
+ return { valid: true, errors, warnings, resolved };
337
+ }