@topogram/cli 0.3.64 → 0.3.65

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 (245) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.js +12 -703
  4. package/src/agent-ops/query-builders/auth.js +375 -0
  5. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  6. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  7. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  8. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  9. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  10. package/src/agent-ops/query-builders/change-risk.js +25 -0
  11. package/src/agent-ops/query-builders/common.js +149 -0
  12. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  13. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  14. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  15. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  16. package/src/agent-ops/query-builders/work-packets.js +417 -0
  17. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  18. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  19. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  20. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  21. package/src/agent-ops/query-builders.d.ts +26 -26
  22. package/src/agent-ops/query-builders.js +42 -5021
  23. package/src/catalog/constants.js +10 -0
  24. package/src/catalog/copy.js +60 -0
  25. package/src/catalog/diagnostics.js +15 -0
  26. package/src/catalog/entries.js +42 -0
  27. package/src/catalog/files.js +67 -0
  28. package/src/catalog/provenance.js +122 -0
  29. package/src/catalog/source.js +150 -0
  30. package/src/catalog/validation.js +252 -0
  31. package/src/catalog.d.ts +2 -0
  32. package/src/catalog.js +18 -746
  33. package/src/cli/commands/catalog/check.js +31 -0
  34. package/src/cli/commands/catalog/copy.js +59 -0
  35. package/src/cli/commands/catalog/doctor.js +248 -0
  36. package/src/cli/commands/catalog/help.js +21 -0
  37. package/src/cli/commands/catalog/list.js +52 -0
  38. package/src/cli/commands/catalog/runner.js +92 -0
  39. package/src/cli/commands/catalog/shared.js +17 -0
  40. package/src/cli/commands/catalog/show.js +134 -0
  41. package/src/cli/commands/catalog.js +30 -615
  42. package/src/cli/commands/generator-policy/package-info.js +162 -0
  43. package/src/cli/commands/generator-policy/payloads.js +372 -0
  44. package/src/cli/commands/generator-policy/printers.js +159 -0
  45. package/src/cli/commands/generator-policy/runner.js +81 -0
  46. package/src/cli/commands/generator-policy/shared.js +39 -0
  47. package/src/cli/commands/generator-policy.js +15 -783
  48. package/src/cli/commands/import/adopt.js +170 -0
  49. package/src/cli/commands/import/check.js +91 -0
  50. package/src/cli/commands/import/diff.js +84 -0
  51. package/src/cli/commands/import/help.js +47 -0
  52. package/src/cli/commands/import/paths.js +277 -0
  53. package/src/cli/commands/import/plan.js +284 -0
  54. package/src/cli/commands/import/refresh.js +470 -0
  55. package/src/cli/commands/import/status-history.js +196 -0
  56. package/src/cli/commands/import/workspace.js +230 -0
  57. package/src/cli/commands/import.js +33 -1732
  58. package/src/cli/commands/package/constants.js +17 -0
  59. package/src/cli/commands/package/doctor.js +240 -0
  60. package/src/cli/commands/package/help.js +27 -0
  61. package/src/cli/commands/package/lockfile.js +135 -0
  62. package/src/cli/commands/package/npm.js +97 -0
  63. package/src/cli/commands/package/reporting.js +35 -0
  64. package/src/cli/commands/package/runner.js +33 -0
  65. package/src/cli/commands/package/shared.js +9 -0
  66. package/src/cli/commands/package/update-cli.js +252 -0
  67. package/src/cli/commands/package/versions.js +35 -0
  68. package/src/cli/commands/package.js +29 -813
  69. package/src/cli/commands/query/change-plan.js +68 -0
  70. package/src/cli/commands/query/definitions.js +202 -0
  71. package/src/cli/commands/query/import-adopt.js +121 -0
  72. package/src/cli/commands/query/runner/artifacts.js +102 -0
  73. package/src/cli/commands/query/runner/boundaries.js +211 -0
  74. package/src/cli/commands/query/runner/change.js +182 -0
  75. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  76. package/src/cli/commands/query/runner/index.js +31 -0
  77. package/src/cli/commands/query/runner/output.js +12 -0
  78. package/src/cli/commands/query/runner/workflow.js +241 -0
  79. package/src/cli/commands/query/runner.js +3 -0
  80. package/src/cli/commands/query/workflow-context.js +5 -0
  81. package/src/cli/commands/query/workspace.js +274 -0
  82. package/src/cli/commands/query.js +9 -1300
  83. package/src/cli/commands/template/baseline.js +100 -0
  84. package/src/cli/commands/template/check.js +466 -0
  85. package/src/cli/commands/template/constants.js +8 -0
  86. package/src/cli/commands/template/diagnostics.js +26 -0
  87. package/src/cli/commands/template/help.js +28 -0
  88. package/src/cli/commands/template/lifecycle.js +404 -0
  89. package/src/cli/commands/template/list-show.js +287 -0
  90. package/src/cli/commands/template/policy.js +422 -0
  91. package/src/cli/commands/template/shared.js +127 -0
  92. package/src/cli/commands/template/updates.js +352 -0
  93. package/src/cli/commands/template.js +41 -2143
  94. package/src/generator/api/contracts.js +497 -0
  95. package/src/generator/api/metadata.js +221 -0
  96. package/src/generator/api/openapi.js +559 -0
  97. package/src/generator/api/schema.js +124 -0
  98. package/src/generator/api/types.d.ts +98 -0
  99. package/src/generator/api.js +3 -1195
  100. package/src/generator/context/shared/domain-sdlc.js +282 -0
  101. package/src/generator/context/shared/maintained-boundary.js +665 -0
  102. package/src/generator/context/shared/metrics.js +85 -0
  103. package/src/generator/context/shared/primitives.js +64 -0
  104. package/src/generator/context/shared/relationships.js +453 -0
  105. package/src/generator/context/shared/summaries.js +263 -0
  106. package/src/generator/context/shared/types.d.ts +207 -0
  107. package/src/generator/context/shared.d.ts +42 -0
  108. package/src/generator/context/shared.js +80 -1390
  109. package/src/generator/context/slice/core.js +397 -0
  110. package/src/generator/context/slice/sdlc.js +417 -0
  111. package/src/generator/context/slice/ui-packets.js +183 -0
  112. package/src/generator/context/slice.js +2 -859
  113. package/src/generator/registry/index.js +507 -0
  114. package/src/generator/registry.js +18 -504
  115. package/src/generator/runtime/environment/index.js +666 -0
  116. package/src/generator/runtime/environment.js +4 -666
  117. package/src/generator/runtime/runtime-check/index.js +554 -0
  118. package/src/generator/runtime/runtime-check.js +4 -554
  119. package/src/generator/runtime/shared/index.js +572 -0
  120. package/src/generator/runtime/shared.js +19 -570
  121. package/src/generator/shared.d.ts +2 -0
  122. package/src/generator/surfaces/shared.d.ts +3 -0
  123. package/src/generator/widget-conformance/behavior-report.js +258 -0
  124. package/src/generator/widget-conformance/checks.js +371 -0
  125. package/src/generator/widget-conformance/projection-context.js +200 -0
  126. package/src/generator/widget-conformance/report.js +166 -0
  127. package/src/generator/widget-conformance/types.d.ts +121 -0
  128. package/src/generator/widget-conformance.js +3 -824
  129. package/src/import/core/context.d.ts +3 -0
  130. package/src/import/core/contracts.d.ts +1 -0
  131. package/src/import/core/registry.d.ts +4 -0
  132. package/src/import/core/runner/candidates.js +217 -0
  133. package/src/import/core/runner/options.js +22 -0
  134. package/src/import/core/runner/reports.js +50 -0
  135. package/src/import/core/runner/run.js +79 -0
  136. package/src/import/core/runner/tracks.js +150 -0
  137. package/src/import/core/runner/ui-drafts.js +337 -0
  138. package/src/import/core/runner.js +3 -698
  139. package/src/import/core/shared/api-routes.js +221 -0
  140. package/src/import/core/shared/candidates.js +97 -0
  141. package/src/import/core/shared/files.js +177 -0
  142. package/src/import/core/shared/next-app.js +389 -0
  143. package/src/import/core/shared/types.d.ts +51 -0
  144. package/src/import/core/shared/ui-routes.js +230 -0
  145. package/src/import/core/shared.js +60 -861
  146. package/src/new-project/constants.js +128 -0
  147. package/src/new-project/create.js +83 -0
  148. package/src/new-project/json.js +28 -0
  149. package/src/new-project/metadata.js +96 -0
  150. package/src/new-project/package-spec.js +161 -0
  151. package/src/new-project/project-files.js +348 -0
  152. package/src/new-project/template-policy.js +269 -0
  153. package/src/new-project/template-resolution.js +368 -0
  154. package/src/new-project/template-snapshots.js +430 -0
  155. package/src/new-project/template-updates.js +512 -0
  156. package/src/new-project/types.d.ts +83 -0
  157. package/src/new-project.js +6 -2277
  158. package/src/parser.d.ts +87 -1
  159. package/src/parser.js +118 -0
  160. package/src/policy/review-boundaries.d.ts +15 -0
  161. package/src/project-config/index.js +564 -0
  162. package/src/project-config.js +19 -561
  163. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  164. package/src/resolver/enrich/bug.js +2 -0
  165. package/src/resolver/enrich/pitch.js +2 -0
  166. package/src/resolver/enrich/requirement.js +2 -0
  167. package/src/resolver/enrich/task.js +2 -0
  168. package/src/resolver/index.js +19 -2089
  169. package/src/resolver/normalize.js +384 -1
  170. package/src/resolver/plans.js +168 -0
  171. package/src/resolver/projections-api.js +494 -0
  172. package/src/resolver/projections-db.js +133 -0
  173. package/src/resolver/projections-ui.js +317 -0
  174. package/src/resolver/shapes.js +251 -0
  175. package/src/resolver/shared.js +278 -0
  176. package/src/resolver/widgets.js +132 -0
  177. package/src/template-trust/constants.js +62 -0
  178. package/src/template-trust/content.js +258 -0
  179. package/src/template-trust/diff.js +92 -0
  180. package/src/template-trust/policy.js +61 -0
  181. package/src/template-trust/record.js +90 -0
  182. package/src/template-trust/status.js +182 -0
  183. package/src/template-trust.js +24 -687
  184. package/src/text-helpers.d.ts +1 -0
  185. package/src/topogram-types.d.ts +69 -0
  186. package/src/validator/common.js +488 -0
  187. package/src/validator/data-model.js +237 -0
  188. package/src/validator/docs.js +167 -0
  189. package/src/validator/expressions.js +146 -1
  190. package/src/validator/index.d.ts +23 -0
  191. package/src/validator/index.js +32 -3585
  192. package/src/validator/kinds.d.ts +41 -0
  193. package/src/validator/kinds.js +2 -0
  194. package/src/validator/model-helpers.js +46 -0
  195. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  196. package/src/validator/per-kind/bug.js +6 -0
  197. package/src/validator/per-kind/domain.js +15 -2
  198. package/src/validator/per-kind/pitch.js +7 -0
  199. package/src/validator/per-kind/requirement.js +5 -0
  200. package/src/validator/per-kind/task.js +7 -0
  201. package/src/validator/per-kind/widget.js +14 -0
  202. package/src/validator/projections/api-http-async.js +410 -0
  203. package/src/validator/projections/api-http-authz.js +88 -0
  204. package/src/validator/projections/api-http-core.js +205 -0
  205. package/src/validator/projections/api-http-policies.js +339 -0
  206. package/src/validator/projections/api-http-responses.js +233 -0
  207. package/src/validator/projections/api-http.js +44 -0
  208. package/src/validator/projections/db.js +353 -0
  209. package/src/validator/projections/generator-defaults.js +45 -0
  210. package/src/validator/projections/helpers.js +87 -0
  211. package/src/validator/projections/ui-helpers.js +214 -0
  212. package/src/validator/projections/ui-navigation.js +344 -0
  213. package/src/validator/projections/ui-structure.js +364 -0
  214. package/src/validator/projections/ui-widgets.js +493 -0
  215. package/src/validator/projections/ui.js +46 -0
  216. package/src/validator/registry.js +48 -1
  217. package/src/validator/utils.d.ts +20 -0
  218. package/src/validator/utils.js +115 -12
  219. package/src/widget-behavior.d.ts +1 -0
  220. package/src/workflows/import-app/api/collect.js +221 -0
  221. package/src/workflows/import-app/api/openapi.js +257 -0
  222. package/src/workflows/import-app/api/routes.js +327 -0
  223. package/src/workflows/import-app/api/sources.js +22 -0
  224. package/src/workflows/import-app/api.js +2 -797
  225. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  226. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  227. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  228. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  229. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  230. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  231. package/src/workflows/reconcile/adoption-plan.js +30 -740
  232. package/src/workflows/reconcile/auth/closures.js +115 -0
  233. package/src/workflows/reconcile/auth/formatters.js +142 -0
  234. package/src/workflows/reconcile/auth/inference.js +330 -0
  235. package/src/workflows/reconcile/auth/roles.js +122 -0
  236. package/src/workflows/reconcile/auth.js +35 -690
  237. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  238. package/src/workflows/reconcile/bundle-core.js +12 -598
  239. package/src/workflows/reconcile/canonical-surface.js +1 -1
  240. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  241. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  242. package/src/workflows/reconcile/impacts/patches.js +252 -0
  243. package/src/workflows/reconcile/impacts/reports.js +80 -0
  244. package/src/workflows/reconcile/impacts.js +14 -623
  245. package/src/workspace-docs.d.ts +29 -0
@@ -0,0 +1,317 @@
1
+ import { blockEntries, getFieldValue } from "../validator.js";
2
+ import { normalizeSequence, tokenValue } from "./shared.js";
3
+
4
+ export function parseProjectionUiScreensBlock(statement, registry) {
5
+ return blockEntries(getFieldValue(statement, "screens")).map((entry) => {
6
+ const directives = {};
7
+
8
+ for (let i = 2; i < entry.items.length; i += 2) {
9
+ const key = tokenValue(entry.items[i]);
10
+ const value = tokenValue(entry.items[i + 1]);
11
+ if (key && value != null) {
12
+ directives[key] = value;
13
+ }
14
+ }
15
+
16
+ return {
17
+ type: "ui_screen",
18
+ id: tokenValue(entry.items[1]),
19
+ kind: directives.kind || null,
20
+ title: directives.title || null,
21
+ load: directives.load ? { id: directives.load, kind: registry.get(directives.load)?.kind || null } : null,
22
+ itemShape: directives.item_shape ? { id: directives.item_shape, kind: registry.get(directives.item_shape)?.kind || null } : null,
23
+ viewShape: directives.view_shape ? { id: directives.view_shape, kind: registry.get(directives.view_shape)?.kind || null } : null,
24
+ inputShape: directives.input_shape ? { id: directives.input_shape, kind: registry.get(directives.input_shape)?.kind || null } : null,
25
+ submit: directives.submit ? { id: directives.submit, kind: registry.get(directives.submit)?.kind || null } : null,
26
+ detailCapability: directives.detail_capability
27
+ ? { id: directives.detail_capability, kind: registry.get(directives.detail_capability)?.kind || null }
28
+ : null,
29
+ primaryAction: directives.primary_action
30
+ ? { id: directives.primary_action, kind: registry.get(directives.primary_action)?.kind || null }
31
+ : null,
32
+ secondaryAction: directives.secondary_action
33
+ ? { id: directives.secondary_action, kind: registry.get(directives.secondary_action)?.kind || null }
34
+ : null,
35
+ destructiveAction: directives.destructive_action
36
+ ? { id: directives.destructive_action, kind: registry.get(directives.destructive_action)?.kind || null }
37
+ : null,
38
+ terminalAction: directives.terminal_action
39
+ ? { id: directives.terminal_action, kind: registry.get(directives.terminal_action)?.kind || null }
40
+ : null,
41
+ successNavigate: directives.success_navigate || null,
42
+ successRefresh: directives.success_refresh || null,
43
+ emptyTitle: directives.empty_title || null,
44
+ emptyBody: directives.empty_body || null,
45
+ loadingState: directives.loading_state || null,
46
+ errorState: directives.error_state || null,
47
+ unauthorizedState: directives.unauthorized_state || null,
48
+ notFoundState: directives.not_found_state || null,
49
+ successState: directives.success_state || null,
50
+ raw: normalizeSequence(entry.items),
51
+ loc: entry.loc
52
+ };
53
+ });
54
+ }
55
+
56
+ export function parseProjectionUiCollectionsBlock(statement) {
57
+ return blockEntries(getFieldValue(statement, "collection_views")).map((entry) => {
58
+ const operation = tokenValue(entry.items[2]);
59
+ const primaryValue = tokenValue(entry.items[3]) || null;
60
+ const secondaryValue = tokenValue(entry.items[4]) || null;
61
+
62
+ return {
63
+ type: "ui_collection_binding",
64
+ screenId: tokenValue(entry.items[1]),
65
+ operation,
66
+ field: ["filter", "search", "sort", "group"].includes(operation) ? primaryValue : null,
67
+ direction: operation === "sort" ? secondaryValue : null,
68
+ value: primaryValue,
69
+ extra: secondaryValue,
70
+ raw: normalizeSequence(entry.items),
71
+ loc: entry.loc
72
+ };
73
+ });
74
+ }
75
+
76
+ export function parseProjectionUiActionsBlock(statement, registry) {
77
+ return blockEntries(getFieldValue(statement, "screen_actions")).map((entry) => ({
78
+ type: "ui_action_binding",
79
+ screenId: tokenValue(entry.items[1]),
80
+ capability: tokenValue(entry.items[3])
81
+ ? {
82
+ id: tokenValue(entry.items[3]),
83
+ kind: registry.get(tokenValue(entry.items[3]))?.kind || null
84
+ }
85
+ : null,
86
+ prominence: tokenValue(entry.items[5]) || null,
87
+ placement: tokenValue(entry.items[6]) === "placement" ? tokenValue(entry.items[7]) || null : null,
88
+ raw: normalizeSequence(entry.items),
89
+ loc: entry.loc
90
+ }));
91
+ }
92
+
93
+ export function parseProjectionUiVisibilityBlock(statement, registry) {
94
+ return blockEntries(getFieldValue(statement, "visibility_rules")).map((entry) => {
95
+ const directives = {};
96
+ for (let i = 5; i < entry.items.length; i += 2) {
97
+ const key = tokenValue(entry.items[i]);
98
+ const value = tokenValue(entry.items[i + 1]);
99
+ if (key && value != null) {
100
+ directives[key] = value;
101
+ }
102
+ }
103
+
104
+ return {
105
+ type: "visibility_rules_rule",
106
+ capability: tokenValue(entry.items[1])
107
+ ? {
108
+ id: tokenValue(entry.items[1]),
109
+ kind: registry.get(tokenValue(entry.items[1]))?.kind || null
110
+ }
111
+ : null,
112
+ predicate: tokenValue(entry.items[3]) || null,
113
+ value: tokenValue(entry.items[4]) || null,
114
+ claimValue: directives.claim_value || null,
115
+ raw: normalizeSequence(entry.items),
116
+ loc: entry.loc
117
+ };
118
+ });
119
+ }
120
+
121
+ export function parseProjectionUiLookupsBlock(statement, registry) {
122
+ return blockEntries(getFieldValue(statement, "field_lookups")).map((entry) => ({
123
+ type: "ui_lookup_binding",
124
+ screenId: tokenValue(entry.items[1]),
125
+ field: tokenValue(entry.items[3]) || null,
126
+ entity: tokenValue(entry.items[5])
127
+ ? {
128
+ id: tokenValue(entry.items[5]),
129
+ kind: registry.get(tokenValue(entry.items[5]))?.kind || null
130
+ }
131
+ : null,
132
+ labelField: tokenValue(entry.items[7]) || null,
133
+ emptyLabel: tokenValue(entry.items[9]) || null,
134
+ raw: normalizeSequence(entry.items),
135
+ loc: entry.loc
136
+ }));
137
+ }
138
+
139
+ export function parseProjectionUiRoutesBlock(statement) {
140
+ return blockEntries(getFieldValue(statement, "screen_routes")).map((entry) => ({
141
+ type: "ui_route",
142
+ screenId: tokenValue(entry.items[1]),
143
+ path: tokenValue(entry.items[3]) || null,
144
+ raw: normalizeSequence(entry.items),
145
+ loc: entry.loc
146
+ }));
147
+ }
148
+
149
+ export function parseProjectionUiIosBlock(statement, registry) {
150
+ return blockEntries(getFieldValue(statement, "ios_hints")).map((entry) => ({
151
+ type: "ios_hint_binding",
152
+ targetKind: tokenValue(entry.items[0]),
153
+ targetId: tokenValue(entry.items[1]),
154
+ capability:
155
+ tokenValue(entry.items[0]) === "action" && tokenValue(entry.items[1])
156
+ ? {
157
+ id: tokenValue(entry.items[1]),
158
+ kind: registry.get(tokenValue(entry.items[1]))?.kind || null
159
+ }
160
+ : null,
161
+ directive: tokenValue(entry.items[2]) || null,
162
+ value: tokenValue(entry.items[3]) || null,
163
+ raw: normalizeSequence(entry.items),
164
+ loc: entry.loc
165
+ }));
166
+ }
167
+
168
+ export function parseProjectionUiWebBlock(statement, registry) {
169
+ return blockEntries(getFieldValue(statement, "web_hints")).map((entry) => ({
170
+ type: "web_hint_binding",
171
+ targetKind: tokenValue(entry.items[0]),
172
+ targetId: tokenValue(entry.items[1]),
173
+ capability:
174
+ tokenValue(entry.items[0]) === "action" && tokenValue(entry.items[1])
175
+ ? {
176
+ id: tokenValue(entry.items[1]),
177
+ kind: registry.get(tokenValue(entry.items[1]))?.kind || null
178
+ }
179
+ : null,
180
+ directive: tokenValue(entry.items[2]) || null,
181
+ value: tokenValue(entry.items[3]) || null,
182
+ raw: normalizeSequence(entry.items),
183
+ loc: entry.loc
184
+ }));
185
+ }
186
+
187
+ export function parseProjectionUiAppShellBlock(statement) {
188
+ return blockEntries(getFieldValue(statement, "app_shell")).map((entry) => ({
189
+ type: "app_shell_binding",
190
+ key: tokenValue(entry.items[0]) || null,
191
+ value: tokenValue(entry.items[1]) || null,
192
+ raw: normalizeSequence(entry.items),
193
+ loc: entry.loc
194
+ }));
195
+ }
196
+
197
+ export function parseProjectionUiDesignBlock(statement) {
198
+ return blockEntries(getFieldValue(statement, "design_tokens")).map((entry) => ({
199
+ type: "design_tokens_token",
200
+ key: tokenValue(entry.items[0]) || null,
201
+ role: tokenValue(entry.items[1]) || null,
202
+ value: tokenValue(entry.items[2]) || null,
203
+ raw: normalizeSequence(entry.items),
204
+ loc: entry.loc
205
+ }));
206
+ }
207
+
208
+ export function parseProjectionUiNavigationBlock(statement) {
209
+ return blockEntries(getFieldValue(statement, "navigation")).map((entry) => {
210
+ const directives = {};
211
+ for (let i = 2; i < entry.items.length; i += 2) {
212
+ const key = tokenValue(entry.items[i]);
213
+ const value = tokenValue(entry.items[i + 1]);
214
+ if (key && value != null) {
215
+ directives[key] = value;
216
+ }
217
+ }
218
+
219
+ return {
220
+ type: "navigation_binding",
221
+ targetKind: tokenValue(entry.items[0]) || null,
222
+ targetId: tokenValue(entry.items[1]) || null,
223
+ directives,
224
+ raw: normalizeSequence(entry.items),
225
+ loc: entry.loc
226
+ };
227
+ });
228
+ }
229
+
230
+ export function parseProjectionUiScreenRegionsBlock(statement) {
231
+ return blockEntries(getFieldValue(statement, "screen_regions")).map((entry) => {
232
+ const directives = {};
233
+ for (let i = 4; i < entry.items.length; i += 2) {
234
+ const key = tokenValue(entry.items[i]);
235
+ const value = tokenValue(entry.items[i + 1]);
236
+ if (key && value != null) {
237
+ directives[key] = value;
238
+ }
239
+ }
240
+
241
+ return {
242
+ type: "ui_screen_region_binding",
243
+ screenId: tokenValue(entry.items[1]) || null,
244
+ region: tokenValue(entry.items[3]) || null,
245
+ pattern: directives.pattern || null,
246
+ placement: directives.placement || null,
247
+ title: directives.title || null,
248
+ state: directives.state || null,
249
+ variant: directives.variant || null,
250
+ raw: normalizeSequence(entry.items),
251
+ loc: entry.loc
252
+ };
253
+ });
254
+ }
255
+
256
+ export function parseProjectionWidgetBindingsBlock(statement, registry) {
257
+ return blockEntries(getFieldValue(statement, "widget_bindings")).map((entry) => {
258
+ const dataBindings = [];
259
+ const eventBindings = [];
260
+
261
+ for (let i = 6; i < entry.items.length;) {
262
+ const directive = tokenValue(entry.items[i]);
263
+ if (directive === "data") {
264
+ const prop = tokenValue(entry.items[i + 1]);
265
+ const sourceId = tokenValue(entry.items[i + 3]);
266
+ dataBindings.push({
267
+ prop,
268
+ source: sourceId
269
+ ? {
270
+ id: sourceId,
271
+ kind: registry.get(sourceId)?.kind || null
272
+ }
273
+ : null
274
+ });
275
+ i += 4;
276
+ continue;
277
+ }
278
+ if (directive === "event") {
279
+ const event = tokenValue(entry.items[i + 1]);
280
+ const action = tokenValue(entry.items[i + 2]);
281
+ const targetId = tokenValue(entry.items[i + 3]);
282
+ eventBindings.push({
283
+ event,
284
+ action,
285
+ target: targetId
286
+ ? {
287
+ id: targetId,
288
+ kind: action === "navigate" ? "screen" : registry.get(targetId)?.kind || null
289
+ }
290
+ : null
291
+ });
292
+ i += 4;
293
+ continue;
294
+ }
295
+ i += 1;
296
+ }
297
+
298
+ const widgetId = tokenValue(entry.items[5]);
299
+ const widgetRef = widgetId
300
+ ? {
301
+ id: widgetId,
302
+ kind: registry.get(widgetId)?.kind || null
303
+ }
304
+ : null;
305
+ const binding = {
306
+ type: "widget_binding",
307
+ screenId: tokenValue(entry.items[1]) || null,
308
+ region: tokenValue(entry.items[3]) || null,
309
+ widget: widgetRef,
310
+ dataBindings,
311
+ eventBindings,
312
+ raw: normalizeSequence(entry.items),
313
+ loc: entry.loc
314
+ };
315
+ return binding;
316
+ });
317
+ }
@@ -0,0 +1,251 @@
1
+ import { blockEntries, getFieldValue } from "../validator.js";
2
+ import { normalizeSequence, parseInvariantEntry, parseSymbolNodes, tokenValue } from "./shared.js";
3
+
4
+ export function parseKeyBlock(statement) {
5
+ return blockEntries(getFieldValue(statement, "keys")).map((entry) => ({
6
+ type: tokenValue(entry.items[0]),
7
+ fields:
8
+ entry.items[1]?.type === "list"
9
+ ? entry.items[1].items.map((item) => item.value)
10
+ : [],
11
+ raw: normalizeSequence(entry.items),
12
+ loc: entry.loc
13
+ }));
14
+ }
15
+
16
+ export function parseRelationBlock(statement, registry) {
17
+ return blockEntries(getFieldValue(statement, "relations")).map((entry) => {
18
+ const sourceField = tokenValue(entry.items[0]);
19
+ const targetRef = tokenValue(entry.items[2]);
20
+ const [entityId, fieldName] = (targetRef || "").split(".");
21
+ const targetStatement = entityId ? registry.get(entityId) : null;
22
+
23
+ return {
24
+ type: "reference",
25
+ sourceField,
26
+ target: entityId
27
+ ? {
28
+ id: entityId,
29
+ kind: targetStatement?.kind || null,
30
+ field: fieldName || null
31
+ }
32
+ : null,
33
+ raw: normalizeSequence(entry.items),
34
+ loc: entry.loc
35
+ };
36
+ });
37
+ }
38
+
39
+ export function parseInvariantBlock(statement) {
40
+ return blockEntries(getFieldValue(statement, "invariants")).map((entry) => parseInvariantEntry(entry));
41
+ }
42
+
43
+ export function parseRenameBlock(statement) {
44
+ return blockEntries(getFieldValue(statement, "rename")).map((entry) => ({
45
+ from: entry.items[0]?.value ?? null,
46
+ to: entry.items[1]?.value ?? null,
47
+ loc: entry.loc
48
+ }));
49
+ }
50
+
51
+ export function parseOverridesBlock(statement) {
52
+ return blockEntries(getFieldValue(statement, "overrides")).map((entry) => {
53
+ const [fieldName, ...rest] = entry.items;
54
+ const override = {
55
+ field: fieldName?.value ?? null,
56
+ requiredness: null,
57
+ fieldType: null,
58
+ defaultValue: undefined,
59
+ loc: entry.loc
60
+ };
61
+
62
+ for (let i = 0; i < rest.length; i += 1) {
63
+ const token = rest[i];
64
+ if (!token || token.type !== "symbol") {
65
+ continue;
66
+ }
67
+
68
+ if (token.value === "required" || token.value === "optional") {
69
+ override.requiredness = token.value;
70
+ continue;
71
+ }
72
+
73
+ if (token.value === "type") {
74
+ override.fieldType = rest[i + 1]?.value ?? null;
75
+ i += 1;
76
+ continue;
77
+ }
78
+
79
+ if (token.value === "default") {
80
+ override.defaultValue = rest[i + 1]?.value ?? null;
81
+ i += 1;
82
+ }
83
+ }
84
+
85
+ return override;
86
+ });
87
+ }
88
+
89
+ export function cloneField(field) {
90
+ return {
91
+ ...field,
92
+ sourceName: field.sourceName ?? field.name
93
+ };
94
+ }
95
+
96
+ export function fieldRef(field) {
97
+ return {
98
+ name: field.name,
99
+ sourceName: field.sourceName ?? field.name,
100
+ fieldType: field.fieldType,
101
+ requiredness: field.requiredness,
102
+ defaultValue: field.defaultValue ?? null
103
+ };
104
+ }
105
+
106
+ export function applyRename(fields, renameRules) {
107
+ const renameBySource = new Map(renameRules.map((rule) => [rule.from, rule.to]));
108
+ return fields.map((field) => {
109
+ const renamed = cloneField(field);
110
+ const nextName = renameBySource.get(field.name);
111
+ if (nextName) {
112
+ renamed.name = nextName;
113
+ }
114
+ return renamed;
115
+ });
116
+ }
117
+
118
+ export function applyOverrides(fields, overrideRules) {
119
+ const byCurrentName = new Map(fields.map((field) => [field.name, field]));
120
+ const bySourceName = new Map(fields.map((field) => [field.sourceName, field]));
121
+
122
+ for (const rule of overrideRules) {
123
+ const target = byCurrentName.get(rule.field) || bySourceName.get(rule.field);
124
+ if (!target) {
125
+ continue;
126
+ }
127
+
128
+ if (rule.requiredness) {
129
+ target.requiredness = rule.requiredness;
130
+ }
131
+ if (rule.fieldType) {
132
+ target.fieldType = rule.fieldType;
133
+ }
134
+ if (rule.defaultValue !== undefined) {
135
+ target.defaultValue = rule.defaultValue;
136
+ }
137
+ }
138
+
139
+ return fields;
140
+ }
141
+
142
+ export function buildShapeSelection(shape, byId) {
143
+ const explicitFields = shape.fields.length > 0;
144
+ const selectedFields =
145
+ explicitFields
146
+ ? shape.fields.map((field) => ({
147
+ ...cloneField(field),
148
+ sourceName: field.name
149
+ }))
150
+ : deriveShapeFields(shape, byId).map((field) => ({
151
+ ...cloneField(field),
152
+ sourceName: field.name
153
+ }));
154
+
155
+ return {
156
+ type: "shape_selection",
157
+ mode: explicitFields ? "explicit_fields" : shape.from?.id ? "derived_from_entity" : "empty",
158
+ source: shape.from?.target || null,
159
+ include: parseSymbolNodes(shape.include),
160
+ exclude: parseSymbolNodes(shape.exclude),
161
+ selectedFields: selectedFields.map((field) => fieldRef(field))
162
+ };
163
+ }
164
+
165
+ export function buildRenameTransforms(renameRules) {
166
+ return renameRules.map((rule, index) => ({
167
+ type: "rename_field",
168
+ order: index,
169
+ from: rule.from,
170
+ to: rule.to,
171
+ loc: rule.loc
172
+ }));
173
+ }
174
+
175
+ export function buildOverrideTransforms(overrideRules) {
176
+ return overrideRules.map((rule, index) => ({
177
+ type: "override_field",
178
+ order: index,
179
+ field: rule.field,
180
+ changes: {
181
+ requiredness: rule.requiredness,
182
+ fieldType: rule.fieldType,
183
+ defaultValue: rule.defaultValue ?? null
184
+ },
185
+ loc: rule.loc
186
+ }));
187
+ }
188
+
189
+ export function buildShapeTransformGraph(shape, byId) {
190
+ const selection = buildShapeSelection(shape, byId);
191
+ return {
192
+ type: "shape_transform_graph",
193
+ selection,
194
+ transforms: [
195
+ ...buildRenameTransforms(shape.rename),
196
+ ...buildOverrideTransforms(shape.overrides)
197
+ ],
198
+ resultFields: (shape.projectedFields || []).map((field) => fieldRef(field))
199
+ };
200
+ }
201
+
202
+ export function projectShapeFields(shape, byId) {
203
+ const baseFields =
204
+ shape.fields.length > 0
205
+ ? shape.fields.map((field) => ({
206
+ ...cloneField(field),
207
+ sourceName: field.name
208
+ }))
209
+ : deriveShapeFields(shape, byId).map((field) => ({
210
+ ...cloneField(field),
211
+ sourceName: field.name
212
+ }));
213
+
214
+ const renamedFields = applyRename(baseFields, shape.rename);
215
+ const overriddenFields = applyOverrides(renamedFields, shape.overrides);
216
+
217
+ return overriddenFields.map((field) => ({
218
+ name: field.name,
219
+ sourceName: field.sourceName,
220
+ fieldType: field.fieldType,
221
+ requiredness: field.requiredness,
222
+ defaultValue: field.defaultValue ?? null,
223
+ raw: field.raw,
224
+ loc: field.loc
225
+ }));
226
+ }
227
+
228
+ export function deriveShapeFields(shape, byId) {
229
+ if (shape.fields.length > 0) {
230
+ return shape.fields;
231
+ }
232
+
233
+ if (!shape.from?.target?.id) {
234
+ return [];
235
+ }
236
+
237
+ const entity = byId.get(shape.from.target.id);
238
+ if (!entity || entity.kind !== "entity") {
239
+ return [];
240
+ }
241
+
242
+ const sourceFields = new Map(entity.fields.map((field) => [field.name, field]));
243
+ const includes = shape.include.length > 0 ? shape.include : [...sourceFields.keys()];
244
+ const excludes = new Set(shape.exclude);
245
+
246
+ return includes
247
+ .filter((fieldName) => !excludes.has(fieldName))
248
+ .map((fieldName) => sourceFields.get(fieldName))
249
+ .filter(Boolean)
250
+ .map((field) => cloneField(field));
251
+ }