@topogram/cli 0.3.63 → 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 (344) hide show
  1. package/package.json +1 -1
  2. package/src/adoption/plan/index.js +703 -0
  3. package/src/adoption/plan.d.ts +6 -0
  4. package/src/adoption/plan.js +12 -703
  5. package/src/adoption/reporting.d.ts +10 -0
  6. package/src/adoption/review-groups.d.ts +6 -0
  7. package/src/agent-brief.d.ts +3 -0
  8. package/src/agent-brief.js +495 -0
  9. package/src/agent-ops/query-builders/auth.js +375 -0
  10. package/src/agent-ops/query-builders/change-risk/change-plan.js +123 -0
  11. package/src/agent-ops/query-builders/change-risk/import-plan.js +49 -0
  12. package/src/agent-ops/query-builders/change-risk/maintained.js +286 -0
  13. package/src/agent-ops/query-builders/change-risk/review-packets.js +123 -0
  14. package/src/agent-ops/query-builders/change-risk/risk.js +189 -0
  15. package/src/agent-ops/query-builders/change-risk.js +25 -0
  16. package/src/agent-ops/query-builders/common.js +149 -0
  17. package/src/agent-ops/query-builders/maintained-risk.js +539 -0
  18. package/src/agent-ops/query-builders/maintained-shared.js +120 -0
  19. package/src/agent-ops/query-builders/multi-agent.js +547 -0
  20. package/src/agent-ops/query-builders/projection-impacts.js +514 -0
  21. package/src/agent-ops/query-builders/work-packets.js +417 -0
  22. package/src/agent-ops/query-builders/workflow-context-shared.js +300 -0
  23. package/src/agent-ops/query-builders/workflow-context.js +398 -0
  24. package/src/agent-ops/query-builders/workflow-presets-core.js +676 -0
  25. package/src/agent-ops/query-builders/workflow-presets.js +341 -0
  26. package/src/agent-ops/query-builders.d.ts +26 -0
  27. package/src/agent-ops/query-builders.js +42 -5021
  28. package/src/archive/archive.d.ts +2 -0
  29. package/src/archive/compact.d.ts +1 -0
  30. package/src/archive/unarchive.d.ts +1 -0
  31. package/src/catalog/constants.js +10 -0
  32. package/src/catalog/copy.js +60 -0
  33. package/src/catalog/diagnostics.js +15 -0
  34. package/src/catalog/entries.js +42 -0
  35. package/src/catalog/files.js +67 -0
  36. package/src/catalog/provenance.js +122 -0
  37. package/src/catalog/source.js +150 -0
  38. package/src/catalog/validation.js +252 -0
  39. package/src/catalog.d.ts +12 -0
  40. package/src/catalog.js +18 -750
  41. package/src/cli/catalog-alias.d.ts +1 -0
  42. package/src/cli/command-parser.js +38 -0
  43. package/src/cli/command-parsers/core.js +102 -0
  44. package/src/cli/command-parsers/generator.js +39 -0
  45. package/src/cli/command-parsers/import.js +44 -0
  46. package/src/cli/command-parsers/legacy-workflow.js +21 -0
  47. package/src/cli/command-parsers/project.js +47 -0
  48. package/src/cli/command-parsers/sdlc.js +47 -0
  49. package/src/cli/command-parsers/shared.js +51 -0
  50. package/src/cli/command-parsers/template.js +48 -0
  51. package/src/cli/commands/agent.js +47 -0
  52. package/src/cli/commands/catalog/check.js +31 -0
  53. package/src/cli/commands/catalog/copy.js +59 -0
  54. package/src/cli/commands/catalog/doctor.js +248 -0
  55. package/src/cli/commands/catalog/help.js +21 -0
  56. package/src/cli/commands/catalog/list.js +52 -0
  57. package/src/cli/commands/catalog/runner.js +92 -0
  58. package/src/cli/commands/catalog/shared.js +17 -0
  59. package/src/cli/commands/catalog/show.js +134 -0
  60. package/src/cli/commands/catalog.js +32 -0
  61. package/src/cli/commands/check.js +268 -0
  62. package/src/cli/commands/doctor.js +268 -0
  63. package/src/cli/commands/emit.js +149 -0
  64. package/src/cli/commands/generate.js +96 -0
  65. package/src/cli/commands/generator-policy/package-info.js +162 -0
  66. package/src/cli/commands/generator-policy/payloads.js +372 -0
  67. package/src/cli/commands/generator-policy/printers.js +159 -0
  68. package/src/cli/commands/generator-policy/runner.js +81 -0
  69. package/src/cli/commands/generator-policy/shared.js +39 -0
  70. package/src/cli/commands/generator-policy.js +17 -0
  71. package/src/cli/commands/generator.js +443 -0
  72. package/src/cli/commands/import/adopt.js +170 -0
  73. package/src/cli/commands/import/check.js +91 -0
  74. package/src/cli/commands/import/diff.js +84 -0
  75. package/src/cli/commands/import/help.js +47 -0
  76. package/src/cli/commands/import/paths.js +277 -0
  77. package/src/cli/commands/import/plan.js +284 -0
  78. package/src/cli/commands/import/refresh.js +470 -0
  79. package/src/cli/commands/import/status-history.js +196 -0
  80. package/src/cli/commands/import/workspace.js +230 -0
  81. package/src/cli/commands/import-runner.js +157 -0
  82. package/src/cli/commands/import.js +35 -0
  83. package/src/cli/commands/inspect.js +55 -0
  84. package/src/cli/commands/new.js +94 -0
  85. package/src/cli/commands/package/constants.js +17 -0
  86. package/src/cli/commands/package/doctor.js +240 -0
  87. package/src/cli/commands/package/help.js +27 -0
  88. package/src/cli/commands/package/lockfile.js +135 -0
  89. package/src/cli/commands/package/npm.js +97 -0
  90. package/src/cli/commands/package/reporting.js +35 -0
  91. package/src/cli/commands/package/runner.js +33 -0
  92. package/src/cli/commands/package/shared.js +9 -0
  93. package/src/cli/commands/package/update-cli.js +252 -0
  94. package/src/cli/commands/package/versions.js +35 -0
  95. package/src/cli/commands/package.js +31 -0
  96. package/src/cli/commands/query/change-plan.js +68 -0
  97. package/src/cli/commands/query/definitions.js +202 -0
  98. package/src/cli/commands/query/import-adopt.js +121 -0
  99. package/src/cli/commands/query/runner/artifacts.js +102 -0
  100. package/src/cli/commands/query/runner/boundaries.js +211 -0
  101. package/src/cli/commands/query/runner/change.js +182 -0
  102. package/src/cli/commands/query/runner/import-adopt.js +111 -0
  103. package/src/cli/commands/query/runner/index.js +31 -0
  104. package/src/cli/commands/query/runner/output.js +12 -0
  105. package/src/cli/commands/query/runner/workflow.js +241 -0
  106. package/src/cli/commands/query/runner.js +3 -0
  107. package/src/cli/commands/query/workflow-context.js +5 -0
  108. package/src/cli/commands/query/workspace.js +274 -0
  109. package/src/cli/commands/query.js +11 -0
  110. package/src/cli/commands/release-rollout.js +257 -0
  111. package/src/cli/commands/release-shared.js +528 -0
  112. package/src/cli/commands/release-status.js +429 -0
  113. package/src/cli/commands/release.js +107 -0
  114. package/src/cli/commands/sdlc.js +168 -0
  115. package/src/cli/commands/setup.js +76 -0
  116. package/src/cli/commands/source.js +291 -0
  117. package/src/cli/commands/template/baseline.js +100 -0
  118. package/src/cli/commands/template/check.js +466 -0
  119. package/src/cli/commands/template/constants.js +8 -0
  120. package/src/cli/commands/template/diagnostics.js +26 -0
  121. package/src/cli/commands/template/help.js +28 -0
  122. package/src/cli/commands/template/lifecycle.js +404 -0
  123. package/src/cli/commands/template/list-show.js +287 -0
  124. package/src/cli/commands/template/policy.js +422 -0
  125. package/src/cli/commands/template/shared.js +127 -0
  126. package/src/cli/commands/template/updates.js +352 -0
  127. package/src/cli/commands/template-runner.js +198 -0
  128. package/src/cli/commands/template.js +43 -0
  129. package/src/cli/commands/trust.js +219 -0
  130. package/src/cli/commands/version.js +40 -0
  131. package/src/cli/commands/widget.js +168 -0
  132. package/src/cli/commands/workflow.js +63 -0
  133. package/src/cli/dispatcher.js +392 -0
  134. package/src/cli/help-dispatch.js +188 -0
  135. package/src/cli/help.js +296 -0
  136. package/src/cli/migration-guidance.js +59 -0
  137. package/src/cli/options.js +96 -0
  138. package/src/cli/output-safety.js +107 -0
  139. package/src/cli/path-normalization.js +29 -0
  140. package/src/cli.js +47 -11711
  141. package/src/example-implementation.d.ts +2 -0
  142. package/src/format.d.ts +1 -0
  143. package/src/generator/api/contracts.js +497 -0
  144. package/src/generator/api/metadata.js +221 -0
  145. package/src/generator/api/openapi.js +559 -0
  146. package/src/generator/api/schema.js +124 -0
  147. package/src/generator/api/types.d.ts +98 -0
  148. package/src/generator/api.js +3 -1195
  149. package/src/generator/check.d.ts +1 -0
  150. package/src/generator/context/bundle.d.ts +1 -0
  151. package/src/generator/context/shared/domain-sdlc.js +282 -0
  152. package/src/generator/context/shared/maintained-boundary.js +665 -0
  153. package/src/generator/context/shared/metrics.js +85 -0
  154. package/src/generator/context/shared/primitives.js +64 -0
  155. package/src/generator/context/shared/relationships.js +453 -0
  156. package/src/generator/context/shared/summaries.js +263 -0
  157. package/src/generator/context/shared/types.d.ts +207 -0
  158. package/src/generator/context/shared.d.ts +44 -0
  159. package/src/generator/context/shared.js +80 -1390
  160. package/src/generator/context/slice/core.js +397 -0
  161. package/src/generator/context/slice/sdlc.js +417 -0
  162. package/src/generator/context/slice/ui-packets.js +183 -0
  163. package/src/generator/context/slice.js +2 -859
  164. package/src/generator/native/parity-bundle.js +2 -1
  165. package/src/generator/registry/index.js +507 -0
  166. package/src/generator/registry.js +18 -504
  167. package/src/generator/runtime/environment/index.js +666 -0
  168. package/src/generator/runtime/environment.js +4 -666
  169. package/src/generator/runtime/runtime-check/index.js +554 -0
  170. package/src/generator/runtime/runtime-check.js +4 -554
  171. package/src/generator/runtime/shared/index.js +572 -0
  172. package/src/generator/runtime/shared.js +19 -570
  173. package/src/generator/shared.d.ts +2 -0
  174. package/src/generator/surfaces/shared.d.ts +3 -0
  175. package/src/generator/surfaces/web/html-escape.js +22 -0
  176. package/src/generator/surfaces/web/react.js +10 -8
  177. package/src/generator/surfaces/web/sveltekit.js +7 -5
  178. package/src/generator/surfaces/web/vanilla.js +8 -4
  179. package/src/generator/widget-conformance/behavior-report.js +258 -0
  180. package/src/generator/widget-conformance/checks.js +371 -0
  181. package/src/generator/widget-conformance/projection-context.js +200 -0
  182. package/src/generator/widget-conformance/report.js +166 -0
  183. package/src/generator/widget-conformance/types.d.ts +121 -0
  184. package/src/generator/widget-conformance.js +3 -824
  185. package/src/generator.d.ts +2 -0
  186. package/src/github-client.js +520 -0
  187. package/src/import/core/context.d.ts +3 -0
  188. package/src/import/core/contracts.d.ts +1 -0
  189. package/src/import/core/registry.d.ts +4 -0
  190. package/src/import/core/runner/candidates.js +217 -0
  191. package/src/import/core/runner/options.js +22 -0
  192. package/src/import/core/runner/reports.js +50 -0
  193. package/src/import/core/runner/run.js +79 -0
  194. package/src/import/core/runner/tracks.js +150 -0
  195. package/src/import/core/runner/ui-drafts.js +337 -0
  196. package/src/import/core/runner.js +3 -698
  197. package/src/import/core/shared/api-routes.js +221 -0
  198. package/src/import/core/shared/candidates.js +97 -0
  199. package/src/import/core/shared/files.js +177 -0
  200. package/src/import/core/shared/next-app.js +389 -0
  201. package/src/import/core/shared/types.d.ts +51 -0
  202. package/src/import/core/shared/ui-routes.js +230 -0
  203. package/src/import/core/shared.js +67 -910
  204. package/src/import/extractors/api/flutter-dio.js +4 -8
  205. package/src/import/extractors/api/react-native-repository.js +4 -8
  206. package/src/import/index.d.ts +4 -0
  207. package/src/import/provenance.d.ts +4 -0
  208. package/src/new-project/constants.js +128 -0
  209. package/src/new-project/create.js +83 -0
  210. package/src/new-project/json.js +28 -0
  211. package/src/new-project/metadata.js +96 -0
  212. package/src/new-project/package-spec.js +161 -0
  213. package/src/new-project/project-files.js +348 -0
  214. package/src/new-project/template-policy.js +269 -0
  215. package/src/new-project/template-resolution.js +368 -0
  216. package/src/new-project/template-snapshots.js +430 -0
  217. package/src/new-project/template-updates.js +512 -0
  218. package/src/new-project/types.d.ts +83 -0
  219. package/src/new-project.js +6 -2188
  220. package/src/npm-safety.js +79 -0
  221. package/src/parser.d.ts +87 -0
  222. package/src/parser.js +118 -0
  223. package/src/path-helpers.d.ts +1 -0
  224. package/src/path-helpers.js +20 -0
  225. package/src/policy/review-boundaries.d.ts +15 -0
  226. package/src/project-config/index.js +564 -0
  227. package/src/project-config.js +19 -560
  228. package/src/reconcile/docs.d.ts +8 -0
  229. package/src/reconcile/journeys.d.ts +1 -0
  230. package/src/resolver/enrich/acceptance-criterion.js +2 -0
  231. package/src/resolver/enrich/bug.js +2 -0
  232. package/src/resolver/enrich/pitch.js +2 -0
  233. package/src/resolver/enrich/requirement.js +2 -0
  234. package/src/resolver/enrich/task.js +2 -0
  235. package/src/resolver/index.js +19 -2089
  236. package/src/resolver/normalize.js +384 -1
  237. package/src/resolver/plans.js +168 -0
  238. package/src/resolver/projections-api.js +494 -0
  239. package/src/resolver/projections-db.js +133 -0
  240. package/src/resolver/projections-ui.js +317 -0
  241. package/src/resolver/shapes.js +251 -0
  242. package/src/resolver/shared.js +278 -0
  243. package/src/resolver/widgets.js +132 -0
  244. package/src/resolver.d.ts +1 -0
  245. package/src/runtime-support.js +29 -0
  246. package/src/sdlc/adopt.d.ts +1 -0
  247. package/src/sdlc/check.d.ts +1 -0
  248. package/src/sdlc/explain.d.ts +1 -0
  249. package/src/sdlc/release.d.ts +1 -0
  250. package/src/sdlc/scaffold.d.ts +1 -0
  251. package/src/sdlc/transition.d.ts +1 -0
  252. package/src/template-trust/constants.js +62 -0
  253. package/src/template-trust/content.js +258 -0
  254. package/src/template-trust/diff.js +92 -0
  255. package/src/template-trust/policy.js +61 -0
  256. package/src/template-trust/record.js +90 -0
  257. package/src/template-trust/status.js +182 -0
  258. package/src/template-trust.js +24 -687
  259. package/src/text-helpers.d.ts +7 -0
  260. package/src/text-helpers.js +245 -0
  261. package/src/topogram-config.js +306 -0
  262. package/src/topogram-types.d.ts +69 -0
  263. package/src/validator/common.js +488 -0
  264. package/src/validator/data-model.js +237 -0
  265. package/src/validator/docs.js +167 -0
  266. package/src/validator/expressions.js +146 -1
  267. package/src/validator/index.d.ts +23 -0
  268. package/src/validator/index.js +32 -3585
  269. package/src/validator/kinds.d.ts +41 -0
  270. package/src/validator/kinds.js +2 -0
  271. package/src/validator/model-helpers.js +46 -0
  272. package/src/validator/per-kind/acceptance-criterion.js +5 -0
  273. package/src/validator/per-kind/bug.js +6 -0
  274. package/src/validator/per-kind/domain.js +15 -2
  275. package/src/validator/per-kind/pitch.js +7 -0
  276. package/src/validator/per-kind/requirement.js +5 -0
  277. package/src/validator/per-kind/task.js +7 -0
  278. package/src/validator/per-kind/widget.js +14 -0
  279. package/src/validator/projections/api-http-async.js +410 -0
  280. package/src/validator/projections/api-http-authz.js +88 -0
  281. package/src/validator/projections/api-http-core.js +205 -0
  282. package/src/validator/projections/api-http-policies.js +339 -0
  283. package/src/validator/projections/api-http-responses.js +233 -0
  284. package/src/validator/projections/api-http.js +44 -0
  285. package/src/validator/projections/db.js +353 -0
  286. package/src/validator/projections/generator-defaults.js +45 -0
  287. package/src/validator/projections/helpers.js +87 -0
  288. package/src/validator/projections/ui-helpers.js +214 -0
  289. package/src/validator/projections/ui-navigation.js +344 -0
  290. package/src/validator/projections/ui-structure.js +364 -0
  291. package/src/validator/projections/ui-widgets.js +493 -0
  292. package/src/validator/projections/ui.js +46 -0
  293. package/src/validator/registry.js +48 -1
  294. package/src/validator/utils.d.ts +20 -0
  295. package/src/validator/utils.js +115 -12
  296. package/src/validator.d.ts +2 -0
  297. package/src/widget-behavior.d.ts +1 -0
  298. package/src/workflows/adoption/index.js +26 -0
  299. package/src/workflows/docs-generate.js +262 -0
  300. package/src/workflows/docs-scan.js +703 -0
  301. package/src/workflows/docs.js +15 -0
  302. package/src/workflows/import-app/api/collect.js +221 -0
  303. package/src/workflows/import-app/api/openapi.js +257 -0
  304. package/src/workflows/import-app/api/routes.js +327 -0
  305. package/src/workflows/import-app/api/sources.js +22 -0
  306. package/src/workflows/import-app/api.js +4 -0
  307. package/src/workflows/import-app/db.js +538 -0
  308. package/src/workflows/import-app/index.js +30 -0
  309. package/src/workflows/import-app/shared.js +218 -0
  310. package/src/workflows/import-app/ui.js +443 -0
  311. package/src/workflows/import-app/workflow.js +159 -0
  312. package/src/workflows/reconcile/adoption-plan/build.js +208 -0
  313. package/src/workflows/reconcile/adoption-plan/dependencies.js +75 -0
  314. package/src/workflows/reconcile/adoption-plan/outputs.js +143 -0
  315. package/src/workflows/reconcile/adoption-plan/paths.js +58 -0
  316. package/src/workflows/reconcile/adoption-plan/projection-patches.js +177 -0
  317. package/src/workflows/reconcile/adoption-plan/reasons.js +107 -0
  318. package/src/workflows/reconcile/adoption-plan.js +32 -0
  319. package/src/workflows/reconcile/auth/closures.js +115 -0
  320. package/src/workflows/reconcile/auth/formatters.js +142 -0
  321. package/src/workflows/reconcile/auth/inference.js +330 -0
  322. package/src/workflows/reconcile/auth/roles.js +122 -0
  323. package/src/workflows/reconcile/auth.js +37 -0
  324. package/src/workflows/reconcile/bundle-core/index.js +600 -0
  325. package/src/workflows/reconcile/bundle-core.js +14 -0
  326. package/src/workflows/reconcile/bundle-shared.js +75 -0
  327. package/src/workflows/reconcile/candidate-model.js +477 -0
  328. package/src/workflows/reconcile/canonical-surface.js +264 -0
  329. package/src/workflows/reconcile/gap-report.js +333 -0
  330. package/src/workflows/reconcile/ids.js +6 -0
  331. package/src/workflows/reconcile/impacts/adoption-plan.js +192 -0
  332. package/src/workflows/reconcile/impacts/indexes.js +101 -0
  333. package/src/workflows/reconcile/impacts/patches.js +252 -0
  334. package/src/workflows/reconcile/impacts/reports.js +80 -0
  335. package/src/workflows/reconcile/impacts.js +16 -0
  336. package/src/workflows/reconcile/index.js +7 -0
  337. package/src/workflows/reconcile/renderers.js +461 -0
  338. package/src/workflows/reconcile/summary.js +90 -0
  339. package/src/workflows/reconcile/workflow.js +309 -0
  340. package/src/workflows/shared.js +189 -0
  341. package/src/workflows/types.d.ts +93 -0
  342. package/src/workflows.d.ts +1 -0
  343. package/src/workflows.js +10 -7652
  344. package/src/workspace-docs.d.ts +29 -0
@@ -0,0 +1,7 @@
1
+ export const canonicalCandidateTerm: (value: unknown, options?: { technicalStopwords?: boolean }) => string;
2
+ export const ensureTrailingNewline: (value: string) => string;
3
+ export const extractRankedTerms: (markdown: string, options?: { technicalStopwords?: boolean }) => string[];
4
+ export const idHintify: (value: unknown) => string;
5
+ export const pluralizeCandidateTerm: (value: unknown) => string;
6
+ export const slugify: (value: unknown) => string;
7
+ export const titleCase: (value: unknown) => string;
@@ -0,0 +1,245 @@
1
+ // @ts-check
2
+
3
+ export const GENERIC_STOPWORDS = new Set([
4
+ "the",
5
+ "and",
6
+ "for",
7
+ "with",
8
+ "that",
9
+ "this",
10
+ "from",
11
+ "into",
12
+ "your",
13
+ "their",
14
+ "have",
15
+ "will",
16
+ "when",
17
+ "where",
18
+ "what",
19
+ "which",
20
+ "then",
21
+ "than",
22
+ "been",
23
+ "being",
24
+ "does",
25
+ "each",
26
+ "just",
27
+ "also",
28
+ "through",
29
+ "about",
30
+ "because",
31
+ "after",
32
+ "before",
33
+ "under",
34
+ "over",
35
+ "still",
36
+ "they",
37
+ "them",
38
+ "there",
39
+ "these",
40
+ "those",
41
+ "more",
42
+ "most",
43
+ "some",
44
+ "only",
45
+ "very",
46
+ "same",
47
+ "much",
48
+ "many",
49
+ "other",
50
+ "used",
51
+ "using"
52
+ ]);
53
+
54
+ export const TECHNICAL_STOPWORDS = new Set([
55
+ "readme",
56
+ "docs",
57
+ "topogram",
58
+ "generated",
59
+ "example",
60
+ "examples",
61
+ "app",
62
+ "apps",
63
+ "agreement",
64
+ "api",
65
+ "artifacts",
66
+ "bash",
67
+ "bundle",
68
+ "bundles",
69
+ "commands",
70
+ "compile",
71
+ "deployment",
72
+ "deploy",
73
+ "engine",
74
+ "environment",
75
+ "fixtures",
76
+ "files",
77
+ "fly",
78
+ "getting",
79
+ "implementation",
80
+ "include",
81
+ "layout",
82
+ "local",
83
+ "migrations",
84
+ "model",
85
+ "notes",
86
+ "npm",
87
+ "package",
88
+ "proof",
89
+ "react",
90
+ "recommended",
91
+ "report",
92
+ "reports",
93
+ "runnable",
94
+ "run",
95
+ "runtime",
96
+ "scripts",
97
+ "server",
98
+ "smoke",
99
+ "snapshot",
100
+ "sqlite",
101
+ "stack",
102
+ "stages",
103
+ "started",
104
+ "state",
105
+ "sveltekit",
106
+ "current",
107
+ "check",
108
+ "checks",
109
+ "env",
110
+ "usage",
111
+ "web",
112
+ "workspace"
113
+ ]);
114
+
115
+ /**
116
+ * @param {string} value
117
+ * @returns {string}
118
+ */
119
+ export function ensureTrailingNewline(value) {
120
+ return value.endsWith("\n") ? value : `${value}\n`;
121
+ }
122
+
123
+ /**
124
+ * @param {unknown} value
125
+ * @returns {string}
126
+ */
127
+ export function slugify(value) {
128
+ return String(value || "")
129
+ .trim()
130
+ .toLowerCase()
131
+ .replace(/[^a-z0-9]+/g, "-")
132
+ .replace(/^-+|-+$/g, "") || "untitled";
133
+ }
134
+
135
+ /**
136
+ * @param {unknown} value
137
+ * @returns {string}
138
+ */
139
+ export function idHintify(value) {
140
+ return String(value || "")
141
+ .trim()
142
+ .toLowerCase()
143
+ .replace(/[^a-z0-9]+/g, "_")
144
+ .replace(/^_+|_+$/g, "") || "untitled";
145
+ }
146
+
147
+ /**
148
+ * @param {unknown} value
149
+ * @returns {string}
150
+ */
151
+ export function canonicalCandidateTerm(value) {
152
+ const normalized = slugify(value);
153
+ if (normalized.endsWith("ies")) {
154
+ return `${normalized.slice(0, -3)}y`;
155
+ }
156
+ if (normalized === "status" || normalized === "stats") {
157
+ return normalized;
158
+ }
159
+ if (normalized.endsWith("s") && !normalized.endsWith("ss") && !normalized.endsWith("us") && !normalized.endsWith("is")) {
160
+ return normalized.slice(0, -1);
161
+ }
162
+ return normalized;
163
+ }
164
+
165
+ /**
166
+ * @param {unknown} value
167
+ * @returns {string}
168
+ */
169
+ export function pluralizeCandidateTerm(value) {
170
+ const normalized = String(value || "");
171
+ if (!normalized) return "items";
172
+ const parts = normalized.split("_");
173
+ const last = parts.pop() || "item";
174
+ let plural = last;
175
+ if (last === "stats") {
176
+ plural = "stats";
177
+ } else if (last.endsWith("sis")) {
178
+ plural = `${last.slice(0, -2)}es`;
179
+ } else if (last.endsWith("y") && !/[aeiou]y$/.test(last)) {
180
+ plural = `${last.slice(0, -1)}ies`;
181
+ } else if (/(s|x|z|ch|sh)$/.test(last)) {
182
+ plural = `${last}es`;
183
+ } else {
184
+ plural = `${last}s`;
185
+ }
186
+ return [...parts, plural].join("_");
187
+ }
188
+
189
+ /**
190
+ * @param {unknown} value
191
+ * @returns {string}
192
+ */
193
+ export function titleCase(value) {
194
+ return String(value || "")
195
+ .split(/[_\-\s]+/)
196
+ .filter(Boolean)
197
+ .map((part) => part.charAt(0).toUpperCase() + part.slice(1))
198
+ .join(" ");
199
+ }
200
+
201
+ /**
202
+ * @param {{ technicalStopwords?: boolean }} [options]
203
+ * @returns {Set<string>}
204
+ */
205
+ export function stopwordSet(options = {}) {
206
+ const includeTechnical = options.technicalStopwords !== false;
207
+ return new Set([
208
+ ...GENERIC_STOPWORDS,
209
+ ...(includeTechnical ? TECHNICAL_STOPWORDS : [])
210
+ ]);
211
+ }
212
+
213
+ /**
214
+ * @param {string} markdown
215
+ * @param {{ technicalStopwords?: boolean }} [options]
216
+ * @returns {string[]}
217
+ */
218
+ export function extractRankedTerms(markdown, options = {}) {
219
+ const stopwords = stopwordSet(options);
220
+ const normalized = markdown
221
+ .replace(/\[[^\]]+\]\([^)]+\)/g, " ")
222
+ .replace(/\/Users\/[^\s)]+/g, " ")
223
+ .replace(/https?:\/\/[^\s)]+/g, " ")
224
+ .replace(/`([^`]+)`/g, " $1 ")
225
+ .replace(/[_/]/g, " ");
226
+ const frequency = new Map();
227
+ const headings = normalized.match(/^#+\s+(.+)$/gm) || [];
228
+ for (const heading of headings) {
229
+ for (const word of heading.toLowerCase().match(/\b[a-z][a-z0-9-]{2,}\b/g) || []) {
230
+ if (stopwords.has(word)) {
231
+ continue;
232
+ }
233
+ frequency.set(word, (frequency.get(word) || 0) + 3);
234
+ }
235
+ }
236
+ for (const word of normalized.toLowerCase().match(/\b[a-z][a-z0-9-]{2,}\b/g) || []) {
237
+ if (stopwords.has(word)) {
238
+ continue;
239
+ }
240
+ frequency.set(word, (frequency.get(word) || 0) + 1);
241
+ }
242
+ return [...frequency.entries()]
243
+ .sort((a, b) => (b[1] - a[1]) || a[0].localeCompare(b[0]))
244
+ .map(([term]) => term);
245
+ }
@@ -0,0 +1,306 @@
1
+ // @ts-check
2
+
3
+ import fs from "node:fs";
4
+ import path from "node:path";
5
+
6
+ export const TOPOGRAM_CONFIG_FILE = "topogram.config.json";
7
+
8
+ export const DEFAULT_FIRST_PARTY_GENERATOR_REPOS = [
9
+ "topogram-generator-express-api",
10
+ "topogram-generator-hono-api",
11
+ "topogram-generator-postgres-db",
12
+ "topogram-generator-react-web",
13
+ "topogram-generator-sqlite-db",
14
+ "topogram-generator-sveltekit-web",
15
+ "topogram-generator-swiftui-native",
16
+ "topogram-generator-vanilla-web"
17
+ ];
18
+
19
+ export const DEFAULT_RELEASE_CONSUMER_REPOS = [
20
+ ...DEFAULT_FIRST_PARTY_GENERATOR_REPOS,
21
+ "topogram-starters",
22
+ "topogram-template-todo",
23
+ "topogram-demo-todo",
24
+ "topogram-hello",
25
+ "topograms"
26
+ ];
27
+
28
+ export const DEFAULT_RELEASE_CONSUMER_WORKFLOWS = {
29
+ "topogram-generator-express-api": "Generator Verification",
30
+ "topogram-generator-hono-api": "Generator Verification",
31
+ "topogram-generator-postgres-db": "Generator Verification",
32
+ "topogram-generator-react-web": "Generator Verification",
33
+ "topogram-generator-sqlite-db": "Generator Verification",
34
+ "topogram-generator-sveltekit-web": "Generator Verification",
35
+ "topogram-generator-swiftui-native": "Generator Verification",
36
+ "topogram-generator-vanilla-web": "Generator Verification",
37
+ "topogram-starters": "Starter Verification",
38
+ "topogram-template-todo": "Template Verification",
39
+ "topogram-demo-todo": "Demo Verification",
40
+ "topogram-hello": "Topogram Package Verification",
41
+ "topograms": "Catalog Verification"
42
+ };
43
+
44
+ export const DEFAULT_RELEASE_CONSUMER_WORKFLOW_JOBS = {
45
+ topograms: [
46
+ "Validate catalog",
47
+ "Smoke native starter",
48
+ "Smoke starter alias (hello-web)",
49
+ "Smoke starter alias (hello-api)",
50
+ "Smoke starter alias (hello-db)",
51
+ "Smoke starter alias (web-api)",
52
+ "Smoke starter alias (web-api-db)"
53
+ ]
54
+ };
55
+
56
+ export const DEFAULT_TOPOGRAM_CONFIG = {
57
+ github: {
58
+ owner: "attebury",
59
+ repo: "topogram"
60
+ },
61
+ catalog: {
62
+ owner: "attebury",
63
+ repo: "topograms",
64
+ ref: "main",
65
+ path: "topograms.catalog.json",
66
+ source: null
67
+ },
68
+ release: {
69
+ consumers: DEFAULT_RELEASE_CONSUMER_REPOS,
70
+ workflows: DEFAULT_RELEASE_CONSUMER_WORKFLOWS,
71
+ workflowJobs: DEFAULT_RELEASE_CONSUMER_WORKFLOW_JOBS
72
+ }
73
+ };
74
+
75
+ export const DEFAULT_CATALOG_SOURCE = `https://raw.githubusercontent.com/${DEFAULT_TOPOGRAM_CONFIG.catalog.owner}/${DEFAULT_TOPOGRAM_CONFIG.catalog.repo}/${DEFAULT_TOPOGRAM_CONFIG.catalog.ref}/${DEFAULT_TOPOGRAM_CONFIG.catalog.path}`;
76
+
77
+ /**
78
+ * @typedef {Object} TopogramRuntimeConfig
79
+ * @property {{ owner: string, repo: string }} github
80
+ * @property {{ owner: string, repo: string, ref: string, path: string, source: string|null }} catalog
81
+ * @property {{ consumers: string[], workflows: Record<string, string>, workflowJobs: Record<string, string[]> }} release
82
+ */
83
+
84
+ /**
85
+ * @param {string} cwd
86
+ * @returns {string|null}
87
+ */
88
+ export function findTopogramConfigFile(cwd = process.cwd()) {
89
+ if (process.env.TOPOGRAM_CONFIG_PATH) {
90
+ return path.resolve(process.env.TOPOGRAM_CONFIG_PATH);
91
+ }
92
+ let current = path.resolve(cwd);
93
+ while (true) {
94
+ const candidate = path.join(current, TOPOGRAM_CONFIG_FILE);
95
+ if (fs.existsSync(candidate)) {
96
+ return candidate;
97
+ }
98
+ const parent = path.dirname(current);
99
+ if (parent === current) {
100
+ return null;
101
+ }
102
+ current = parent;
103
+ }
104
+ }
105
+
106
+ /**
107
+ * @param {string} cwd
108
+ * @returns {Record<string, any>}
109
+ */
110
+ export function readTopogramConfigFile(cwd = process.cwd()) {
111
+ const filePath = findTopogramConfigFile(cwd);
112
+ if (!filePath) {
113
+ return {};
114
+ }
115
+ return JSON.parse(fs.readFileSync(filePath, "utf8"));
116
+ }
117
+
118
+ /**
119
+ * @param {string|null|undefined} value
120
+ * @returns {string[]|null}
121
+ */
122
+ function parseListEnv(value) {
123
+ if (!value) {
124
+ return null;
125
+ }
126
+ return String(value)
127
+ .split(",")
128
+ .map((item) => item.trim())
129
+ .filter(Boolean);
130
+ }
131
+
132
+ /**
133
+ * @param {string|null|undefined} value
134
+ * @returns {Record<string, any>|null}
135
+ */
136
+ function parseJsonEnv(value) {
137
+ if (!value) {
138
+ return null;
139
+ }
140
+ return JSON.parse(value);
141
+ }
142
+
143
+ /**
144
+ * @param {Record<string, any>} fileConfig
145
+ * @returns {Record<string, any>}
146
+ */
147
+ function envConfig(fileConfig = {}) {
148
+ const consumers = parseListEnv(process.env.TOPOGRAM_RELEASE_CONSUMERS);
149
+ const workflows = parseJsonEnv(process.env.TOPOGRAM_RELEASE_WORKFLOWS || process.env.TOPOGRAM_RELEASE_CONSUMER_WORKFLOWS_JSON);
150
+ const workflowJobs = parseJsonEnv(process.env.TOPOGRAM_RELEASE_WORKFLOW_JOBS || process.env.TOPOGRAM_RELEASE_CONSUMER_WORKFLOW_JOBS_JSON);
151
+ return {
152
+ github: {
153
+ owner: process.env.TOPOGRAM_GITHUB_OWNER || fileConfig.github?.owner,
154
+ repo: process.env.TOPOGRAM_GITHUB_REPO || process.env.TOPOGRAM_REPO_NAME || fileConfig.github?.repo
155
+ },
156
+ catalog: {
157
+ owner: process.env.TOPOGRAM_CATALOG_OWNER || fileConfig.catalog?.owner,
158
+ repo: process.env.TOPOGRAM_CATALOG_REPO || fileConfig.catalog?.repo,
159
+ ref: process.env.TOPOGRAM_CATALOG_REF || fileConfig.catalog?.ref,
160
+ path: process.env.TOPOGRAM_CATALOG_PATH || fileConfig.catalog?.path,
161
+ source: fileConfig.catalog?.source
162
+ },
163
+ release: {
164
+ consumers: consumers || fileConfig.release?.consumers,
165
+ workflows: workflows || fileConfig.release?.workflows,
166
+ workflowJobs: workflowJobs || fileConfig.release?.workflowJobs
167
+ }
168
+ };
169
+ }
170
+
171
+ /**
172
+ * @param {unknown} value
173
+ * @param {string[]} fallback
174
+ * @returns {string[]}
175
+ */
176
+ function normalizeStringList(value, fallback) {
177
+ if (!Array.isArray(value)) {
178
+ return [...fallback];
179
+ }
180
+ const items = value.map((item) => String(item || "").trim()).filter(Boolean);
181
+ return [...new Set(items)];
182
+ }
183
+
184
+ /**
185
+ * @param {unknown} value
186
+ * @param {Record<string, string>} fallback
187
+ * @returns {Record<string, string>}
188
+ */
189
+ function normalizeStringMap(value, fallback) {
190
+ const output = { ...fallback };
191
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
192
+ return output;
193
+ }
194
+ for (const [key, item] of Object.entries(value)) {
195
+ const name = String(key || "").trim();
196
+ const text = String(item || "").trim();
197
+ if (name && text) {
198
+ output[name] = text;
199
+ }
200
+ }
201
+ return output;
202
+ }
203
+
204
+ /**
205
+ * @param {unknown} value
206
+ * @param {Record<string, string[]>} fallback
207
+ * @returns {Record<string, string[]>}
208
+ */
209
+ function normalizeStringListMap(value, fallback) {
210
+ const output = Object.fromEntries(Object.entries(fallback).map(([key, items]) => [key, [...items]]));
211
+ if (!value || typeof value !== "object" || Array.isArray(value)) {
212
+ return output;
213
+ }
214
+ for (const [key, item] of Object.entries(value)) {
215
+ const name = String(key || "").trim();
216
+ if (!name) {
217
+ continue;
218
+ }
219
+ output[name] = normalizeStringList(item, []);
220
+ }
221
+ return output;
222
+ }
223
+
224
+ /**
225
+ * @param {string} cwd
226
+ * @returns {TopogramRuntimeConfig}
227
+ */
228
+ export function topogramRuntimeConfig(cwd = process.cwd()) {
229
+ const fileConfig = readTopogramConfigFile(cwd);
230
+ const overrides = envConfig(fileConfig);
231
+ return {
232
+ github: {
233
+ owner: overrides.github.owner || DEFAULT_TOPOGRAM_CONFIG.github.owner,
234
+ repo: overrides.github.repo || DEFAULT_TOPOGRAM_CONFIG.github.repo
235
+ },
236
+ catalog: {
237
+ owner: overrides.catalog.owner || DEFAULT_TOPOGRAM_CONFIG.catalog.owner,
238
+ repo: overrides.catalog.repo || DEFAULT_TOPOGRAM_CONFIG.catalog.repo,
239
+ ref: overrides.catalog.ref || DEFAULT_TOPOGRAM_CONFIG.catalog.ref,
240
+ path: overrides.catalog.path || DEFAULT_TOPOGRAM_CONFIG.catalog.path,
241
+ source: overrides.catalog.source || DEFAULT_TOPOGRAM_CONFIG.catalog.source
242
+ },
243
+ release: {
244
+ consumers: normalizeStringList(overrides.release.consumers, DEFAULT_TOPOGRAM_CONFIG.release.consumers),
245
+ workflows: normalizeStringMap(overrides.release.workflows, DEFAULT_TOPOGRAM_CONFIG.release.workflows),
246
+ workflowJobs: normalizeStringListMap(overrides.release.workflowJobs, DEFAULT_TOPOGRAM_CONFIG.release.workflowJobs)
247
+ }
248
+ };
249
+ }
250
+
251
+ /**
252
+ * @param {TopogramRuntimeConfig} [config]
253
+ * @returns {string}
254
+ */
255
+ export function defaultCatalogSource(config = topogramRuntimeConfig()) {
256
+ if (config.catalog.source) {
257
+ return config.catalog.source;
258
+ }
259
+ return `https://raw.githubusercontent.com/${config.catalog.owner}/${config.catalog.repo}/${config.catalog.ref}/${config.catalog.path}`;
260
+ }
261
+
262
+ /**
263
+ * @param {string|null|undefined} repo
264
+ * @param {string} [cwd]
265
+ * @param {string|null|undefined} owner
266
+ * @returns {string}
267
+ */
268
+ export function githubRepoSlug(repo, cwd = process.cwd(), owner = null) {
269
+ const config = topogramRuntimeConfig(cwd);
270
+ return `${owner || config.github.owner}/${repo || config.github.repo}`;
271
+ }
272
+
273
+ /**
274
+ * @param {string} [cwd]
275
+ * @returns {string}
276
+ */
277
+ export function catalogRepoSlug(cwd = process.cwd()) {
278
+ const config = topogramRuntimeConfig(cwd);
279
+ return githubRepoSlug(config.catalog.repo, cwd, config.catalog.owner);
280
+ }
281
+
282
+ /**
283
+ * @param {string} [cwd]
284
+ * @returns {string[]}
285
+ */
286
+ export function releaseConsumerRepos(cwd = process.cwd()) {
287
+ return [...topogramRuntimeConfig(cwd).release.consumers];
288
+ }
289
+
290
+ /**
291
+ * @param {string} name
292
+ * @param {string} [cwd]
293
+ * @returns {string|null}
294
+ */
295
+ export function releaseConsumerWorkflowName(name, cwd = process.cwd()) {
296
+ return topogramRuntimeConfig(cwd).release.workflows[name] || null;
297
+ }
298
+
299
+ /**
300
+ * @param {string} name
301
+ * @param {string} [cwd]
302
+ * @returns {string[]}
303
+ */
304
+ export function releaseConsumerWorkflowJobs(name, cwd = process.cwd()) {
305
+ return [...(topogramRuntimeConfig(cwd).release.workflowJobs[name] || [])];
306
+ }
@@ -0,0 +1,69 @@
1
+ export interface TopogramLocation {
2
+ file?: string;
3
+ start?: {
4
+ line?: number;
5
+ column?: number;
6
+ offset?: number;
7
+ };
8
+ end?: {
9
+ line?: number;
10
+ column?: number;
11
+ offset?: number;
12
+ };
13
+ }
14
+
15
+ export interface TopogramToken {
16
+ type: string;
17
+ value: any;
18
+ items: TopogramToken[];
19
+ entries: TopogramBlockEntry[];
20
+ loc: TopogramLocation;
21
+ [key: string]: any;
22
+ }
23
+
24
+ export interface TopogramBlockEntry {
25
+ items: TopogramToken[];
26
+ loc: TopogramLocation;
27
+ [key: string]: any;
28
+ }
29
+
30
+ export interface TopogramField {
31
+ key: string;
32
+ value: TopogramToken;
33
+ loc: TopogramLocation;
34
+ [key: string]: any;
35
+ }
36
+
37
+ export interface TopogramStatement {
38
+ id: string;
39
+ kind: string;
40
+ fields: TopogramField[];
41
+ loc: TopogramLocation;
42
+ [key: string]: any;
43
+ }
44
+
45
+ export interface ValidationError {
46
+ message: string;
47
+ loc?: TopogramLocation | null;
48
+ }
49
+
50
+ export type ValidationErrors = ValidationError[];
51
+
52
+ export type TopogramFieldMap = Map<string, TopogramField[]>;
53
+
54
+ export type TopogramRegistry = Map<string, TopogramStatement>;
55
+
56
+ export type ResolverBacklinkIndex = Record<string, Map<string, string[]>>;
57
+
58
+ declare global {
59
+ type TopogramLocation = import("./topogram-types.js").TopogramLocation;
60
+ type TopogramToken = import("./topogram-types.js").TopogramToken;
61
+ type TopogramBlockEntry = import("./topogram-types.js").TopogramBlockEntry;
62
+ type TopogramField = import("./topogram-types.js").TopogramField;
63
+ type TopogramStatement = import("./topogram-types.js").TopogramStatement;
64
+ type ValidationError = import("./topogram-types.js").ValidationError;
65
+ type ValidationErrors = import("./topogram-types.js").ValidationErrors;
66
+ type TopogramFieldMap = import("./topogram-types.js").TopogramFieldMap;
67
+ type TopogramRegistry = import("./topogram-types.js").TopogramRegistry;
68
+ type ResolverBacklinkIndex = import("./topogram-types.js").ResolverBacklinkIndex;
69
+ }