@canonical/pragma-cli 0.36.0 → 0.38.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 (312) hide show
  1. package/README.md +3 -2
  2. package/bundled-skills/adoption-a1-styles/SKILL.md +24 -0
  3. package/bundled-skills/adoption-a2-components/SKILL.md +22 -6
  4. package/bundled-skills/anatomy-author/ANATOMY_DSL_SPEC.md +1397 -327
  5. package/bundled-skills/anatomy-author/SKILL.md +840 -137
  6. package/bundled-skills/design-auditor/SKILL.md +133 -9
  7. package/bundled-skills/implement-component/SKILL.md +192 -23
  8. package/bundled-skills/specify-component/SKILL.md +124 -12
  9. package/bundled-skills/specify-pattern/SKILL.md +47 -8
  10. package/dist/package.json +23 -20
  11. package/dist/pragma.conf.js +963 -40
  12. package/dist/pragma.conf.js.map +1 -1
  13. package/dist/src/capabilities/capabilities/catalog.js +14 -5
  14. package/dist/src/capabilities/capabilities/catalog.js.map +1 -1
  15. package/dist/src/capabilities/capabilities/hints.js +33 -5
  16. package/dist/src/capabilities/capabilities/hints.js.map +1 -1
  17. package/dist/src/capabilities/config/show.render.js +30 -2
  18. package/dist/src/capabilities/config/show.render.js.map +1 -1
  19. package/dist/src/capabilities/create/create.verb.js +2 -1
  20. package/dist/src/capabilities/create/create.verb.js.map +1 -1
  21. package/dist/src/capabilities/create/createSurface.generated.js +23 -1
  22. package/dist/src/capabilities/create/createSurface.generated.js.map +1 -1
  23. package/dist/src/capabilities/doctor/checks/checkNodeVersion.js +11 -6
  24. package/dist/src/capabilities/doctor/checks/checkNodeVersion.js.map +1 -1
  25. package/dist/src/capabilities/doctor/checks/harnessInventory.js +1 -1
  26. package/dist/src/capabilities/doctor/checks/harnessInventory.js.map +1 -1
  27. package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js +38 -0
  28. package/dist/src/capabilities/doctor/checks/isSupportedNodeVersion.js.map +1 -0
  29. package/dist/src/capabilities/doctor/checks/targetHealth.js +104 -14
  30. package/dist/src/capabilities/doctor/checks/targetHealth.js.map +1 -1
  31. package/dist/src/capabilities/graph/connect.render.js +101 -0
  32. package/dist/src/capabilities/graph/connect.render.js.map +1 -0
  33. package/dist/src/capabilities/graph/connect.types.js +21 -0
  34. package/dist/src/capabilities/graph/connect.types.js.map +1 -0
  35. package/dist/src/capabilities/graph/connect.verb.js +147 -0
  36. package/dist/src/capabilities/graph/connect.verb.js.map +1 -0
  37. package/dist/src/capabilities/graph/index.js +5 -3
  38. package/dist/src/capabilities/graph/index.js.map +1 -1
  39. package/dist/src/capabilities/graph/queryText.js +206 -0
  40. package/dist/src/capabilities/graph/queryText.js.map +1 -0
  41. package/dist/src/capabilities/graph/relationIndex.js +302 -0
  42. package/dist/src/capabilities/graph/relationIndex.js.map +1 -0
  43. package/dist/src/capabilities/graph/runConnect.js +456 -0
  44. package/dist/src/capabilities/graph/runConnect.js.map +1 -0
  45. package/dist/src/capabilities/graph/runQuery.js +21 -4
  46. package/dist/src/capabilities/graph/runQuery.js.map +1 -1
  47. package/dist/src/capabilities/setup/buildPlan.js +6 -2
  48. package/dist/src/capabilities/setup/buildPlan.js.map +1 -1
  49. package/dist/src/capabilities/setup/operations/index.js +7 -2
  50. package/dist/src/capabilities/setup/operations/index.js.map +1 -1
  51. package/dist/src/capabilities/setup/operations/setupCompletions.js +6 -2
  52. package/dist/src/capabilities/setup/operations/setupCompletions.js.map +1 -1
  53. package/dist/src/capabilities/setup/operations/setupConfig.js +4 -2
  54. package/dist/src/capabilities/setup/operations/setupConfig.js.map +1 -1
  55. package/dist/src/capabilities/setup/operations/setupGenerator.js +72 -14
  56. package/dist/src/capabilities/setup/operations/setupGenerator.js.map +1 -1
  57. package/dist/src/capabilities/setup/operations/setupLsp.js +372 -62
  58. package/dist/src/capabilities/setup/operations/setupLsp.js.map +1 -1
  59. package/dist/src/capabilities/setup/operations/setupMcp.js +150 -5
  60. package/dist/src/capabilities/setup/operations/setupMcp.js.map +1 -1
  61. package/dist/src/capabilities/setup/operations/setupSkills.js +4 -2
  62. package/dist/src/capabilities/setup/operations/setupSkills.js.map +1 -1
  63. package/dist/src/capabilities/setup/operations/writability.js +114 -0
  64. package/dist/src/capabilities/setup/operations/writability.js.map +1 -0
  65. package/dist/src/capabilities/setup/plan.js.map +1 -1
  66. package/dist/src/capabilities/setup/setup.verb.js +80 -31
  67. package/dist/src/capabilities/setup/setup.verb.js.map +1 -1
  68. package/dist/src/capabilities/setup/targets.js +124 -42
  69. package/dist/src/capabilities/setup/targets.js.map +1 -1
  70. package/dist/src/capabilities/shared/index.js +1 -1
  71. package/dist/src/capabilities/shared/index.js.map +1 -1
  72. package/dist/src/constants.js +7 -1
  73. package/dist/src/constants.js.map +1 -1
  74. package/dist/src/kernel/error/renderError.js +3 -2
  75. package/dist/src/kernel/error/renderError.js.map +1 -1
  76. package/dist/src/kernel/error/validOptions.js +41 -0
  77. package/dist/src/kernel/error/validOptions.js.map +1 -0
  78. package/dist/src/kernel/packs/compile.js +90 -6
  79. package/dist/src/kernel/packs/compile.js.map +1 -1
  80. package/dist/src/kernel/packs/cursor.js +135 -0
  81. package/dist/src/kernel/packs/cursor.js.map +1 -0
  82. package/dist/src/kernel/packs/graphql/buildLookupDocument.js +9 -2
  83. package/dist/src/kernel/packs/graphql/buildLookupDocument.js.map +1 -1
  84. package/dist/src/kernel/packs/paging.js +108 -0
  85. package/dist/src/kernel/packs/paging.js.map +1 -0
  86. package/dist/src/kernel/packs/renderPack.js +154 -5
  87. package/dist/src/kernel/packs/renderPack.js.map +1 -1
  88. package/dist/src/kernel/packs/resolveEntity.js +118 -19
  89. package/dist/src/kernel/packs/resolveEntity.js.map +1 -1
  90. package/dist/src/kernel/packs/runBodies.js +156 -18
  91. package/dist/src/kernel/packs/runBodies.js.map +1 -1
  92. package/dist/src/kernel/packs/schema.js +160 -12
  93. package/dist/src/kernel/packs/schema.js.map +1 -1
  94. package/dist/src/kernel/packs/sparql/authorQuery.js +227 -0
  95. package/dist/src/kernel/packs/sparql/authorQuery.js.map +1 -0
  96. package/dist/src/kernel/packs/sparql/buildListQuery.js +251 -0
  97. package/dist/src/kernel/packs/sparql/buildListQuery.js.map +1 -0
  98. package/dist/src/kernel/packs/sparql/buildLookupQuery.js +125 -22
  99. package/dist/src/kernel/packs/sparql/buildLookupQuery.js.map +1 -1
  100. package/dist/src/kernel/packs/sparql/filterValues.js +145 -0
  101. package/dist/src/kernel/packs/sparql/filterValues.js.map +1 -0
  102. package/dist/src/kernel/packs/sparql/index.js +24 -14
  103. package/dist/src/kernel/packs/sparql/index.js.map +1 -1
  104. package/dist/src/kernel/packs/sparql/runSelect.js +10 -4
  105. package/dist/src/kernel/packs/sparql/runSelect.js.map +1 -1
  106. package/dist/src/kernel/packs/sparql/searchTerm.js +25 -0
  107. package/dist/src/kernel/packs/sparql/searchTerm.js.map +1 -0
  108. package/dist/src/kernel/packs/storyRules.js +151 -0
  109. package/dist/src/kernel/packs/storyRules.js.map +1 -0
  110. package/dist/src/kernel/packs/tierScope.js +310 -0
  111. package/dist/src/kernel/packs/tierScope.js.map +1 -0
  112. package/dist/src/kernel/packs/types.js +80 -0
  113. package/dist/src/kernel/packs/types.js.map +1 -1
  114. package/dist/src/kernel/project/cli/buildProgram.js +10 -1
  115. package/dist/src/kernel/project/cli/buildProgram.js.map +1 -1
  116. package/dist/src/kernel/project/cli/dispatch.js +104 -3
  117. package/dist/src/kernel/project/cli/dispatch.js.map +1 -1
  118. package/dist/src/kernel/project/cli/rootHelp.js +8 -5
  119. package/dist/src/kernel/project/cli/rootHelp.js.map +1 -1
  120. package/dist/src/kernel/project/cli/suggestNames.js +31 -7
  121. package/dist/src/kernel/project/cli/suggestNames.js.map +1 -1
  122. package/dist/src/kernel/project/mcp/registerVerb.js +5 -1
  123. package/dist/src/kernel/project/mcp/registerVerb.js.map +1 -1
  124. package/dist/src/kernel/render/renderers.js +34 -2
  125. package/dist/src/kernel/render/renderers.js.map +1 -1
  126. package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js +2 -3
  127. package/dist/src/kernel/runtime/graphpack/embedded/pack.generated.js.map +1 -1
  128. package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js +1 -1
  129. package/dist/src/kernel/runtime/graphpack/embedded/pack.index.generated.js.map +1 -1
  130. package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js +4 -0
  131. package/dist/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.js.map +1 -0
  132. package/dist/src/kernel/runtime/graphpack/embedded.js +13 -6
  133. package/dist/src/kernel/runtime/graphpack/embedded.js.map +1 -1
  134. package/dist/src/kernel/runtime/graphpack/read.js +17 -10
  135. package/dist/src/kernel/runtime/graphpack/read.js.map +1 -1
  136. package/dist/src/kernel/runtime/loadSession.js +3 -1
  137. package/dist/src/kernel/runtime/loadSession.js.map +1 -1
  138. package/dist/src/kernel/runtime/probe.js +1 -1
  139. package/dist/src/kernel/runtime/probe.js.map +1 -1
  140. package/dist/src/kernel/runtime/readEntity.js +19 -4
  141. package/dist/src/kernel/runtime/readEntity.js.map +1 -1
  142. package/dist/src/kernel/runtime/refs/parseRef.js +17 -1
  143. package/dist/src/kernel/runtime/refs/parseRef.js.map +1 -1
  144. package/dist/src/kernel/runtime/refs/resolve.js +38 -5
  145. package/dist/src/kernel/runtime/refs/resolve.js.map +1 -1
  146. package/dist/src/kernel/spec/emitReference.js +1 -1
  147. package/dist/src/kernel/spec/emitReference.js.map +1 -1
  148. package/package.json +23 -20
  149. package/pragma.conf.ts +983 -40
  150. package/src/capabilities/block.parity.test.ts +207 -27
  151. package/src/capabilities/block.shipped.exec.test.ts +156 -14
  152. package/src/capabilities/block.tierRank.exec.test.ts +46 -9
  153. package/src/capabilities/capabilities/catalog.ts +14 -5
  154. package/src/capabilities/capabilities/hints.ts +40 -5
  155. package/src/capabilities/config/collectConfigShow.test.ts +1 -0
  156. package/src/capabilities/config/set.test.ts +24 -25
  157. package/src/capabilities/config/show.render.test.ts +9 -4
  158. package/src/capabilities/config/show.render.ts +30 -2
  159. package/src/capabilities/create/byteEquality.test.ts +28 -1
  160. package/src/capabilities/create/create.test.ts +1 -0
  161. package/src/capabilities/create/create.verb.ts +2 -1
  162. package/src/capabilities/create/createGrammar.test.ts +4 -1
  163. package/src/capabilities/create/createSurface.generated.ts +23 -1
  164. package/src/capabilities/create/crossCli.subprocess.test.ts +10 -3
  165. package/src/capabilities/distribution.parity.test.ts +12 -11
  166. package/src/capabilities/distribution.test.ts +77 -7
  167. package/src/capabilities/doctor/checks/checkNodeVersion.test.ts +49 -0
  168. package/src/capabilities/doctor/checks/checkNodeVersion.ts +11 -7
  169. package/src/capabilities/doctor/checks/harnessInventory.test.ts +13 -6
  170. package/src/capabilities/doctor/checks/harnessInventory.ts +8 -4
  171. package/src/capabilities/doctor/checks/isSupportedNodeVersion.test.ts +111 -0
  172. package/src/capabilities/doctor/checks/isSupportedNodeVersion.ts +34 -0
  173. package/src/capabilities/doctor/checks/mcpCommand.test.ts +7 -1
  174. package/src/capabilities/doctor/checks/targetHealth.ts +114 -13
  175. package/src/capabilities/doctor/doctor.test.ts +327 -36
  176. package/src/capabilities/emptyRecovery.test.ts +84 -28
  177. package/src/capabilities/graph/connect.render.ts +141 -0
  178. package/src/capabilities/graph/connect.shipped.exec.test.ts +370 -0
  179. package/src/capabilities/graph/connect.test.ts +361 -0
  180. package/src/capabilities/graph/connect.types.ts +136 -0
  181. package/src/capabilities/graph/connect.verb.ts +165 -0
  182. package/src/capabilities/graph/index.ts +5 -3
  183. package/src/capabilities/graph/query.shipped.exec.test.ts +66 -0
  184. package/src/capabilities/graph/query.test.ts +17 -0
  185. package/src/capabilities/graph/queryText.test.ts +121 -0
  186. package/src/capabilities/graph/queryText.ts +240 -0
  187. package/src/capabilities/graph/relationIndex.ts +372 -0
  188. package/src/capabilities/graph/runConnect.ts +577 -0
  189. package/src/capabilities/graph/runQuery.ts +21 -6
  190. package/src/capabilities/lazy.test.ts +32 -2
  191. package/src/capabilities/listBudget.shipped.exec.test.ts +239 -0
  192. package/src/capabilities/listLookup.shipped.exec.test.ts +387 -0
  193. package/src/capabilities/listQuery.shipped.exec.test.ts +400 -0
  194. package/src/capabilities/resources/resources.test.ts +38 -2
  195. package/src/capabilities/setup/buildPlan.ts +7 -1
  196. package/src/capabilities/setup/operations/index.ts +14 -0
  197. package/src/capabilities/setup/operations/setupCompletions.ts +9 -2
  198. package/src/capabilities/setup/operations/setupConfig.ts +7 -2
  199. package/src/capabilities/setup/operations/setupGenerator.ts +93 -15
  200. package/src/capabilities/setup/operations/setupLsp.ts +544 -85
  201. package/src/capabilities/setup/operations/setupMcp.ts +212 -4
  202. package/src/capabilities/setup/operations/setupSkills.ts +7 -2
  203. package/src/capabilities/setup/operations/writability.test.ts +151 -0
  204. package/src/capabilities/setup/operations/writability.ts +135 -0
  205. package/src/capabilities/setup/plan.ts +11 -0
  206. package/src/capabilities/setup/setup.test.ts +992 -16
  207. package/src/capabilities/setup/setup.verb.ts +84 -36
  208. package/src/capabilities/setup/targets.ts +152 -48
  209. package/src/capabilities/setup/types.ts +41 -5
  210. package/src/capabilities/shared/index.ts +1 -0
  211. package/src/capabilities/sources/sources.test.ts +55 -0
  212. package/src/capabilities/surface.test.ts +59 -11
  213. package/src/capabilities/tier.parity.test.ts +2 -2
  214. package/src/capabilities/token.parity.test.ts +784 -0
  215. package/src/capabilities/tokenGraph.cli.test.ts +279 -0
  216. package/src/capabilities/tokenGraph.shipped.exec.test.ts +653 -0
  217. package/src/capabilities/variable.parity.test.ts +448 -0
  218. package/src/constants.ts +8 -0
  219. package/src/kernel/completion/shellDrive.test.ts +32 -30
  220. package/src/kernel/config/defaults.test.ts +21 -2
  221. package/src/kernel/config/readConfig.test.ts +1 -1
  222. package/src/kernel/error/renderError.ts +3 -2
  223. package/src/kernel/error/validOptions.test.ts +57 -0
  224. package/src/kernel/error/validOptions.ts +45 -0
  225. package/src/kernel/packs/collect.test.ts +2 -0
  226. package/src/kernel/packs/compile.test.ts +188 -15
  227. package/src/kernel/packs/compile.ts +109 -14
  228. package/src/kernel/packs/cursor.ts +135 -0
  229. package/src/kernel/packs/filteredEmpty.test.ts +213 -0
  230. package/src/kernel/packs/graphql/buildLookupDocument.ts +16 -9
  231. package/src/kernel/packs/graphqlSource.test.ts +152 -0
  232. package/src/kernel/packs/listNotice.test.ts +156 -0
  233. package/src/kernel/packs/paging.ts +110 -0
  234. package/src/kernel/packs/renderPack.ts +186 -13
  235. package/src/kernel/packs/resolveEntity.test.ts +62 -3
  236. package/src/kernel/packs/resolveEntity.ts +186 -26
  237. package/src/kernel/packs/runBodies.ts +196 -26
  238. package/src/kernel/packs/schema.ts +180 -13
  239. package/src/kernel/packs/sparql/authorQuery.test.ts +179 -0
  240. package/src/kernel/packs/sparql/authorQuery.ts +257 -0
  241. package/src/kernel/packs/sparql/buildListQuery.test.ts +344 -0
  242. package/src/kernel/packs/sparql/buildListQuery.ts +344 -0
  243. package/src/kernel/packs/sparql/buildLookupQuery.test.ts +138 -0
  244. package/src/kernel/packs/sparql/buildLookupQuery.ts +140 -20
  245. package/src/kernel/packs/sparql/filterValues.test.ts +86 -0
  246. package/src/kernel/packs/sparql/filterValues.ts +182 -0
  247. package/src/kernel/packs/sparql/index.ts +30 -14
  248. package/src/kernel/packs/sparql/runSelect.test.ts +63 -0
  249. package/src/kernel/packs/sparql/runSelect.ts +42 -2
  250. package/src/kernel/packs/sparql/searchTerm.ts +29 -0
  251. package/src/kernel/packs/storyRules.ts +180 -0
  252. package/src/kernel/packs/tierScope.test.ts +487 -0
  253. package/src/kernel/packs/tierScope.ts +409 -0
  254. package/src/kernel/packs/toolDescription.test.ts +13 -10
  255. package/src/kernel/packs/types.ts +311 -9
  256. package/src/kernel/project/cli/buildProgram.ts +17 -1
  257. package/src/kernel/project/cli/dispatch.test.ts +87 -0
  258. package/src/kernel/project/cli/dispatch.ts +114 -4
  259. package/src/kernel/project/cli/rootHelp.ts +8 -5
  260. package/src/kernel/project/cli/suggest.test.ts +35 -0
  261. package/src/kernel/project/cli/suggestNames.ts +34 -7
  262. package/src/kernel/project/mcp/registerVerb.ts +5 -1
  263. package/src/kernel/render/contracts.ts +2 -0
  264. package/src/kernel/render/prefixes.test.ts +2 -0
  265. package/src/kernel/render/renderers.test.ts +43 -0
  266. package/src/kernel/render/renderers.ts +34 -1
  267. package/src/kernel/runtime/graphpack/embedded/pack.generated.ts +2 -3
  268. package/src/kernel/runtime/graphpack/embedded/pack.index.generated.ts +1 -1
  269. package/src/kernel/runtime/graphpack/embedded/pack.manifest.generated.ts +3 -0
  270. package/src/kernel/runtime/graphpack/embedded.ts +14 -6
  271. package/src/kernel/runtime/graphpack/graphpack.test.ts +31 -5
  272. package/src/kernel/runtime/graphpack/read.ts +17 -13
  273. package/src/kernel/runtime/loadSession.ts +3 -1
  274. package/src/kernel/runtime/probe.ts +1 -1
  275. package/src/kernel/runtime/readEntity.ts +19 -4
  276. package/src/kernel/runtime/refs/parseRef.test.ts +49 -1
  277. package/src/kernel/runtime/refs/parseRef.ts +25 -1
  278. package/src/kernel/runtime/refs/resolve.ts +39 -5
  279. package/src/kernel/runtime/types.ts +30 -0
  280. package/src/kernel/spec/emitReference.ts +1 -1
  281. package/src/kernel/spec/surfaceConformance.test.ts +2 -2
  282. package/src/kernel/spec/types.ts +17 -0
  283. package/src/testing/PARITY_GAPS.ts +4 -4
  284. package/src/testing/behavioral/agentSession.mcp.test.ts +43 -39
  285. package/src/testing/behavioral/completion.test.ts +7 -6
  286. package/src/testing/behavioral/disclosure.test.ts +39 -37
  287. package/src/testing/behavioral/errorMatrix.mcp.test.ts +82 -64
  288. package/src/testing/behavioral/errorMatrix.storeless.test.ts +11 -10
  289. package/src/testing/behavioral/journeys.cli.test.ts +71 -32
  290. package/src/testing/behavioral/journeys.defaultPack.test.ts +6 -4
  291. package/src/testing/behavioral/journeys.firstInstall.test.ts +70 -5
  292. package/src/testing/behavioral/journeys.mcpLifecycle.mcp.test.ts +4 -3
  293. package/src/testing/behavioral/journeys.packageStories.test.ts +2 -1
  294. package/src/testing/behavioral/mcpSurface.test.ts +28 -25
  295. package/src/testing/behavioral/parity.test.ts +25 -23
  296. package/src/testing/eval/__snapshots__/eval.test.ts.snap +20 -0
  297. package/src/testing/eval/cases/effectful.ts +7 -1
  298. package/src/testing/eval/cases/readNouns.ts +100 -11
  299. package/src/testing/fixtures/blockGraph.ts +89 -5
  300. package/src/testing/fixtures/connectGraph.ts +159 -0
  301. package/src/testing/fixtures/graph/canonical.ts +128 -32
  302. package/src/testing/helpers/fsProbe.ts +88 -0
  303. package/src/testing/helpers/runCli.test.ts +44 -0
  304. package/src/testing/helpers/runCli.ts +27 -3
  305. package/src/testing/perf/budgets.test.ts +3 -1
  306. package/src/testing/perf/budgets.ts +138 -54
  307. package/dist/src/kernel/packs/sparql/applyFilters.js +0 -167
  308. package/dist/src/kernel/packs/sparql/applyFilters.js.map +0 -1
  309. package/dist/src/kernel/packs/sparql/applySearch.js +0 -25
  310. package/dist/src/kernel/packs/sparql/applySearch.js.map +0 -1
  311. package/src/kernel/packs/sparql/applyFilters.ts +0 -203
  312. package/src/kernel/packs/sparql/applySearch.ts +0 -33
@@ -0,0 +1,206 @@
1
+ /**
2
+ * Making the graph's OWN names typable in `graph query`, and making the
3
+ * parser's complaint about the user's text.
4
+ *
5
+ * Two defects with one cause: the query a caller writes is not the query the
6
+ * parser reads. `rt.query.sparql` prepends one `PREFIX` line per registered
7
+ * namespace, so a caller's line 1 is the parser's line 16 — and the names the
8
+ * rest of this CLI hands out (`ds:global.component.button` from `graph
9
+ * inspect`, `dt:s4/web/--color-text` from `variable list`) are not spellable as
10
+ * SPARQL `PN_LOCAL` at all. Pasting a name pragma itself printed produced a
11
+ * Unicode-range dump pointing at a line the caller could not see.
12
+ *
13
+ * So this module owns both halves of the seam:
14
+ *
15
+ * - {@link expandPrefixedNames} rewrites a prefixed name whose local part the
16
+ * grammar cannot carry into the `<absolute IRI>` it stands for — the same
17
+ * expansion `graph inspect` has always done for its one argument, applied to
18
+ * every token of a query. It is a pure text transform: same namespaces, same
19
+ * meaning, so a query that already parsed answers exactly as before.
20
+ * - {@link trimQueryError} reports the position in the CALLER's text and cuts
21
+ * the parser's expected-token dump to one line.
22
+ */
23
+ import { isEmbeddableIri } from "../../kernel/packs/iri.js";
24
+ /**
25
+ * The query's own `PREFIX` declarations. Captured (rather than merely detected)
26
+ * because a caller who declares a prefix wins over the prepended one, so an
27
+ * expansion has to use the namespace the parser would have used.
28
+ */
29
+ const PREFIX_DECLARATION = /\bPREFIX\s+([A-Za-z][\w.-]*)?\s*:\s*<([^<>\s]*)>/gi;
30
+ /**
31
+ * One pass over the query, in precedence order: comment, long literal, short
32
+ * literal, IRI, prefixed-name candidate, any other character.
33
+ *
34
+ * The first four alternatives exist to be SKIPPED — a `ds:x/y` inside a string
35
+ * literal is data the caller wrote, and inside `<…>` it is already an IRI.
36
+ * Everything the scanner does not recognise passes through one character at a
37
+ * time, which is what keeps an unparsable query byte-identical apart from the
38
+ * names this module set out to expand.
39
+ */
40
+ const SCANNER = new RegExp([
41
+ "#[^\\n]*", // comment to end of line
42
+ '"""[\\s\\S]*?"""', // long literals
43
+ "'''[\\s\\S]*?'''",
44
+ '"(?:[^"\\\\\\n]|\\\\.)*"', // short literals
45
+ "'(?:[^'\\\\\\n]|\\\\.)*'",
46
+ '<[^<>"{}|^`\\\\\\s]*>', // an absolute IRI, already written out
47
+ // A prefixed-name candidate: a name, a colon, and the longest run of
48
+ // characters that could belong to a local part. `/` is included because
49
+ // the token IRIs contain it (`dt:s4/web/--color-text`); a property path
50
+ // is told apart from a local part in `splitPropertyPath`.
51
+ "[A-Za-z_\\u00C0-\\uFFFF][\\w.\\-\\u00C0-\\uFFFF]*:[^\\s<>\"'`{}()\\[\\],;|^\\\\*+?!=&#@$]*",
52
+ "[\\s\\S]", // anything else, one character at a time
53
+ ].join("|"), "g");
54
+ /** A local part every SPARQL parser carries as written — left alone. */
55
+ const PLAIN_LOCAL = /^[A-Za-z0-9_][A-Za-z0-9_-]*$/;
56
+ /**
57
+ * Expand every prefixed name whose local part the SPARQL grammar cannot carry.
58
+ *
59
+ * Conservative in the direction that matters: a name is rewritten only when its
60
+ * prefix is one the query will be parsed with, its local part is not a plain
61
+ * name (letters, digits, `_`, `-`), and the expansion is a safe `<IRI>` token.
62
+ * A name inside a string literal, a comment or an existing IRI is never
63
+ * touched, and neither is a property path's operator (`ds:a/ds:b` stays two
64
+ * steps, `dt:s4/web/--x` stays one name).
65
+ *
66
+ * @param sparql - The query as the caller wrote it.
67
+ * @param prefixes - The namespaces the query will be parsed with.
68
+ * @returns The query to execute, and whether anything moved.
69
+ */
70
+ export function expandPrefixedNames(sparql, prefixes) {
71
+ const namespaces = { ...prefixes, ...declaredPrefixes(sparql) };
72
+ let rewritten = false;
73
+ const text = sparql.replace(SCANNER, (token) => {
74
+ const expanded = expandToken(token, namespaces);
75
+ if (expanded === undefined)
76
+ return token;
77
+ rewritten = true;
78
+ return expanded;
79
+ });
80
+ return { text, rewritten };
81
+ }
82
+ /** The prefixes the query declares for itself, which outrank the prepended ones. */
83
+ function declaredPrefixes(sparql) {
84
+ const declared = {};
85
+ for (const match of sparql.matchAll(PREFIX_DECLARATION)) {
86
+ declared[match[1] ?? ""] = match[2] ?? "";
87
+ }
88
+ return declared;
89
+ }
90
+ /**
91
+ * One matched token, expanded — or `undefined` when it must be left as it is.
92
+ *
93
+ * The token may be a whole property path (`ds:a/ds:b`), because `/` is both the
94
+ * path operator and a character in this graph's local names. The two are told
95
+ * apart by what follows the slash: a segment that itself opens a KNOWN prefixed
96
+ * name is the next step of a path, anything else (`s4/web/--color-text`) is
97
+ * more of the same name. Each step is then expanded on its own, so a path may
98
+ * be half rewritten and stay a path.
99
+ *
100
+ * @param token - The matched token (it may not be a prefixed name at all).
101
+ * @param namespaces - Prefix → namespace, the caller's declarations winning.
102
+ * @returns The rewritten token, or undefined to keep the original.
103
+ */
104
+ function expandToken(token, namespaces) {
105
+ // Every alternative but the candidate one is skipped here: a comment, a
106
+ // literal and an IRI all fail one of these guards.
107
+ if (token.indexOf(":") <= 0 ||
108
+ token.startsWith("<") ||
109
+ token.startsWith("#")) {
110
+ return undefined;
111
+ }
112
+ let rewritten = false;
113
+ const steps = pathSteps(token, namespaces).map((step) => {
114
+ const expanded = expandName(step, namespaces);
115
+ if (expanded === undefined)
116
+ return step;
117
+ rewritten = true;
118
+ return expanded;
119
+ });
120
+ return rewritten ? steps.join("/") : undefined;
121
+ }
122
+ /** Split a token into the property-path steps it is made of (usually one). */
123
+ function pathSteps(token, namespaces) {
124
+ const segments = token.split("/");
125
+ const steps = [];
126
+ let step = segments[0];
127
+ for (const segment of segments.slice(1)) {
128
+ const colon = segment.indexOf(":");
129
+ if (colon > 0 && namespaces[segment.slice(0, colon)] !== undefined) {
130
+ steps.push(step);
131
+ step = segment;
132
+ }
133
+ else {
134
+ step = `${step}/${segment}`;
135
+ }
136
+ }
137
+ steps.push(step);
138
+ return steps;
139
+ }
140
+ /**
141
+ * One prefixed name, as the `<IRI>` it stands for — or `undefined` to keep it.
142
+ *
143
+ * @param name - One path step: `prefix:local`, plus any trailing punctuation.
144
+ * @param namespaces - Prefix → namespace, the caller's declarations winning.
145
+ * @returns The rewritten name, or undefined to keep the original.
146
+ */
147
+ function expandName(name, namespaces) {
148
+ const colon = name.indexOf(":");
149
+ if (colon <= 0)
150
+ return undefined;
151
+ const namespace = namespaces[name.slice(0, colon)];
152
+ if (namespace === undefined)
153
+ return undefined;
154
+ // A local part may not END in a dot, so a trailing one is the statement
155
+ // terminator the caller typed, not part of the name.
156
+ const local = name.slice(colon + 1).replace(/\.+$/, "");
157
+ const tail = name.slice(colon + 1 + local.length);
158
+ if (local === "" || PLAIN_LOCAL.test(local))
159
+ return undefined;
160
+ const iri = `${namespace}${local}`;
161
+ return isEmbeddableIri(iri) ? `<${iri}>${tail}` : undefined;
162
+ }
163
+ /** How much of the parser's expected-token dump a reader is served by. */
164
+ const MAX_PARSER_DETAIL = 140;
165
+ /** `error at <line>:<column>: <what the parser expected>`. */
166
+ const PARSER_POSITION = /^error at (\d+):(\d+):\s*([\s\S]*)$/;
167
+ /**
168
+ * Restate a parser failure in terms of the text the CALLER wrote.
169
+ *
170
+ * Two edits, both about the same lie: the position is the parser's, and the
171
+ * parser read a query with N prepended `PREFIX` lines the caller never saw
172
+ * ("16:41" for an error on line 1). And the expectation is a full dump of every
173
+ * admissible Unicode range — five lines of `'\\u{00C0}'..='\\u{00D6}'` that tell
174
+ * a reader nothing they can act on. The line number is corrected, the dump is
175
+ * collapsed to one line and cut.
176
+ *
177
+ * The COLUMN is dropped when names were expanded: an expansion lengthens the
178
+ * line it sits on, so the parser's column is a position in text the caller
179
+ * never wrote. The line is safe either way — an expansion never adds a newline.
180
+ *
181
+ * @param detail - The parser's own message.
182
+ * @param prependedLines - How many `PREFIX` lines were added above the query.
183
+ * @param rewritten - Whether names were expanded (columns therefore moved).
184
+ * @returns A one-line message positioned in the caller's own text.
185
+ */
186
+ export function trimQueryError(detail, prependedLines, rewritten) {
187
+ const collapsed = detail.replace(/\s+/g, " ").trim();
188
+ const match = PARSER_POSITION.exec(collapsed);
189
+ if (!match)
190
+ return cut(collapsed);
191
+ const line = Number(match[1]) - prependedLines;
192
+ const expected = cut(match[3] ?? "");
193
+ if (line < 1)
194
+ return `error at line ${match[1]}, column ${match[2]}: ${expected}`;
195
+ const at = rewritten
196
+ ? `error at line ${line}`
197
+ : `error at line ${line}, column ${match[2]}`;
198
+ return `${at}: ${expected}`;
199
+ }
200
+ /** One line, at most {@link MAX_PARSER_DETAIL} characters of it. */
201
+ function cut(text) {
202
+ return text.length <= MAX_PARSER_DETAIL
203
+ ? text
204
+ : `${text.slice(0, MAX_PARSER_DETAIL - 1).trimEnd()}…`;
205
+ }
206
+ //# sourceMappingURL=queryText.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queryText.js","sourceRoot":"","sources":["../../../../src/capabilities/graph/queryText.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,302 @@
1
+ /**
2
+ * The relation graph: which edges `graph connect` may walk, and the rosters it
3
+ * may not.
4
+ *
5
+ * ## What a relation is
6
+ *
7
+ * The kernel's entity reader already draws this distinction, and defends it in
8
+ * its own source (`readEntity.ts:37-50`): a RELATION "fans in narrowly and
9
+ * every subject is part of the answer", a ROSTER "fans in without bound because
10
+ * it grows with the data rather than the model" and "is already answered by
11
+ * `pragma/instanceCount` and by the noun's list verb". Then the sentence that
12
+ * makes it reusable here: "The two are told apart by FAN-IN, not by predicate
13
+ * name, so the kernel names no vocabulary."
14
+ *
15
+ * This module applies that same rule to TRAVERSAL. An edge `(s, p, o)` is
16
+ * walkable only if neither of its groups is a roster:
17
+ *
18
+ * - at most {@link ROSTER_THRESHOLD} subjects share its `(p, o)` pair, and
19
+ * - at most that many objects share its `(s, p)` pair.
20
+ *
21
+ * The threshold is IMPORTED, never restated — one constant with two consumers,
22
+ * so the traversal cannot drift from the doctrine it claims to obey.
23
+ *
24
+ * ## Why not a list of predicates
25
+ *
26
+ * Because the rule is per edge, per node and per direction, and a list cannot
27
+ * be. On the pack this CLI ships, twelve predicates carry both kinds of edge:
28
+ * `ds:tier` fans in 218-deep for the global tier and 1-to-a-handful for a small
29
+ * one, so the same predicate is a roster at one node and a real relation at
30
+ * another. A list would also be an editorial judgement about five vocabularies
31
+ * frozen into this file, stale the day a pack ships a predicate nobody listed.
32
+ * Nothing in this module names a predicate, and nothing may start to: the rule
33
+ * has to hold for a graph whose rosters hang off terms this code never saw.
34
+ *
35
+ * Nor can the distinction be read off the ontology. It is not asserted there:
36
+ * 72 predicates are declared `owl:ObjectProperty` and every one of the eleven
37
+ * classifiers is among them. The fan-in rule is a measurement standing in for a
38
+ * statement the graph does not make — which is exactly why it is computed here,
39
+ * fresh, from whatever is loaded, rather than written down anywhere.
40
+ *
41
+ * ## What the scan covers, and what it costs
42
+ *
43
+ * ONE scan of every triple with a non-literal object. Both group tables are
44
+ * counted over that same edge set, because a literal object is not an edge and
45
+ * cannot be walked — counting attributes into a fan-in would refuse edges on
46
+ * the strength of triples no traversal could ever use. The counts must be taken
47
+ * over the whole edge set before any edge is admitted, so the two tests cannot
48
+ * be applied in sequence: dropping a hub edge first would shrink the group its
49
+ * sibling is measured against and quietly admit an edge the rule refuses.
50
+ *
51
+ * The index is built ONCE per store session and memoised on it, and nothing
52
+ * here is written into the pack (`C.05` forbids a pre-joined view artifact, and
53
+ * prescribes exactly this: a thin loader that joins at runtime, because "the
54
+ * join is milliseconds at this scale — code, not data"). It is reached only
55
+ * through the connect verb's dynamically-imported run body, behind
56
+ * `needsStore`, so a process that never asks a connect question never loads
57
+ * this module, let alone runs the scan.
58
+ */
59
+ import { compactUri } from "../../kernel/render/index.js";
60
+ import { isInformativeName, nameIndex, ROSTER_THRESHOLD, } from "../../kernel/runtime/readEntity.js";
61
+ /** Every triple whose object is a node rather than an attribute — one scan. */
62
+ const EDGE_SCAN = "SELECT ?s ?p ?o WHERE { ?s ?p ?o . FILTER(!isLiteral(?o)) }";
63
+ /**
64
+ * Field separator for composite map keys.
65
+ *
66
+ * A NUL, written as an ESCAPE so this file stays text: a literal NUL byte in
67
+ * the source makes git classify the module as binary, and a reviewer then gets
68
+ * no diff at all. It is the one character that cannot appear in an IRI or in a
69
+ * blank-node label, so a composite key is unambiguous.
70
+ */
71
+ const SEP = "\u0000";
72
+ /**
73
+ * The memo. Keyed on the session OBJECT, so it lives exactly as long as the
74
+ * session does: the lazy store hands out one immutable session per boot and
75
+ * `invalidate()` replaces it, which means a rebuilt store gets a rebuilt index
76
+ * with no invalidation hook of its own to forget to call. A WeakMap rather than
77
+ * a field on the session, because the index is this capability's concern and
78
+ * the kernel should not carry a structure only one verb reads.
79
+ */
80
+ const memo = new WeakMap();
81
+ /**
82
+ * The relation index for a session, built on first use and reused after.
83
+ *
84
+ * @param ctx - The booted session and its query facade.
85
+ * @returns The session's relation index.
86
+ * @note Impure — scans the store on the first call for a given session.
87
+ */
88
+ export function relationIndex(ctx) {
89
+ const cached = memo.get(ctx.session);
90
+ if (cached)
91
+ return cached;
92
+ // Memoise the PROMISE, not the result, so two concurrent questions on one
93
+ // session share a single scan instead of racing two.
94
+ const building = buildRelationIndex(ctx).catch((error) => {
95
+ memo.delete(ctx.session);
96
+ throw error;
97
+ });
98
+ memo.set(ctx.session, building);
99
+ return building;
100
+ }
101
+ /** Read every edge out of the store, deduplicated. */
102
+ async function scanEdges(ctx) {
103
+ const result = await ctx.sparql(EDGE_SCAN);
104
+ if (result.type !== "select")
105
+ return [];
106
+ const edges = [];
107
+ // Deduplicate by triple: ke queries with `use_default_graph_as_union` and
108
+ // oxigraph does not deduplicate across that union, so one triple asserted in
109
+ // two named graphs arrives twice. Left in, it would inflate every fan-in
110
+ // count it touches AND return the same path twice.
111
+ const seen = new Set();
112
+ for (const binding of result.termBindings) {
113
+ const s = binding.s;
114
+ const p = binding.p;
115
+ const o = binding.o;
116
+ if (!s || !p || !o)
117
+ continue;
118
+ const key = `${s.value}${SEP}${p.value}${SEP}${o.value}`;
119
+ if (seen.has(key))
120
+ continue;
121
+ seen.add(key);
122
+ edges.push({
123
+ s: s.value,
124
+ p: p.value,
125
+ o: o.value,
126
+ sBlank: s.termType === "BlankNode",
127
+ oBlank: o.termType === "BlankNode",
128
+ });
129
+ }
130
+ return edges;
131
+ }
132
+ /**
133
+ * Build the relation index: one scan, two group tables, then the rule.
134
+ *
135
+ * @param ctx - The booted session and its query facade.
136
+ * @returns The relation index, with the cost of producing it recorded.
137
+ * @note Impure — queries the store.
138
+ */
139
+ async function buildRelationIndex(ctx) {
140
+ const scanStart = performance.now();
141
+ const edges = await scanEdges(ctx);
142
+ const scanMs = performance.now() - scanStart;
143
+ const buildStart = performance.now();
144
+ // Both tables over the SAME edge set, before anything is admitted.
145
+ const bySubjectSide = new Map();
146
+ const byObjectSide = new Map();
147
+ for (const edge of edges) {
148
+ const inbound = `${edge.p}${SEP}${edge.o}`;
149
+ const outbound = `${edge.s}${SEP}${edge.p}`;
150
+ bySubjectSide.set(inbound, (bySubjectSide.get(inbound) ?? 0) + 1);
151
+ byObjectSide.set(outbound, (byObjectSide.get(outbound) ?? 0) + 1);
152
+ }
153
+ const adjacency = new Map();
154
+ const rosters = new Map();
155
+ const groups = new Map();
156
+ const blanks = new Set();
157
+ let relationEdges = 0;
158
+ const link = (from, edge) => {
159
+ const list = adjacency.get(from);
160
+ if (list)
161
+ list.push(edge);
162
+ else
163
+ adjacency.set(from, [edge]);
164
+ };
165
+ const enrol = (node, key, group) => {
166
+ if (!groups.has(key))
167
+ groups.set(key, group);
168
+ const list = rosters.get(node);
169
+ if (list) {
170
+ if (!list.includes(key))
171
+ list.push(key);
172
+ }
173
+ else
174
+ rosters.set(node, [key]);
175
+ };
176
+ for (const edge of edges) {
177
+ if (edge.sBlank)
178
+ blanks.add(edge.s);
179
+ if (edge.oBlank)
180
+ blanks.add(edge.o);
181
+ const inboundKey = `${edge.p}${SEP}${edge.o}`;
182
+ const outboundKey = `${edge.s}${SEP}${edge.p}`;
183
+ const subjectsSharing = bySubjectSide.get(inboundKey) ?? 0;
184
+ const objectsSharing = byObjectSide.get(outboundKey) ?? 0;
185
+ const inboundRoster = subjectsSharing > ROSTER_THRESHOLD;
186
+ const outboundRoster = objectsSharing > ROSTER_THRESHOLD;
187
+ if (!inboundRoster && !outboundRoster) {
188
+ relationEdges++;
189
+ link(edge.s, { to: edge.o, predicate: edge.p, forward: true });
190
+ link(edge.o, { to: edge.s, predicate: edge.p, forward: false });
191
+ continue;
192
+ }
193
+ // A refused edge still says something true: it records the node's
194
+ // MEMBERSHIP of the group that refused it, which is the whole content of a
195
+ // negative answer about two things that share only a classification.
196
+ if (inboundRoster) {
197
+ enrol(edge.s, `subjects${SEP}${inboundKey}`, {
198
+ side: "subjects",
199
+ predicate: edge.p,
200
+ node: edge.o,
201
+ members: subjectsSharing,
202
+ });
203
+ }
204
+ if (outboundRoster) {
205
+ enrol(edge.o, `objects${SEP}${outboundKey}`, {
206
+ side: "objects",
207
+ predicate: edge.p,
208
+ node: edge.s,
209
+ members: objectsSharing,
210
+ });
211
+ }
212
+ }
213
+ const names = nameIndex(ctx.session.index);
214
+ const prefixes = ctx.session.prefixes;
215
+ const term = (value, blank) => {
216
+ if (blank ?? blanks.has(value)) {
217
+ return { value, addressable: false };
218
+ }
219
+ const prefixed = compactUri(value, prefixes);
220
+ const name = names.get(value);
221
+ return {
222
+ value,
223
+ // `compactUri` returns its input when no namespace matches, so an
224
+ // unmatched IRI carries no `prefixed` echoing `value`.
225
+ ...(prefixed === value ? {} : { prefixed }),
226
+ ...(name && isInformativeName(name, prefixed) ? { title: name } : {}),
227
+ };
228
+ };
229
+ return {
230
+ adjacency,
231
+ rosters,
232
+ groups,
233
+ scannedEdges: edges.length,
234
+ relationEdges,
235
+ relationNodes: adjacency.size,
236
+ scanMs,
237
+ buildMs: performance.now() - buildStart,
238
+ term,
239
+ };
240
+ }
241
+ /**
242
+ * The roster groups two nodes both belong to, ordered deterministically.
243
+ *
244
+ * Scoped to one hop in each direction, which is what makes it cost nothing —
245
+ * and what it cannot see: two blocks whose shared library is attributed to
246
+ * their implementation objects rather than to themselves share that roster one
247
+ * step removed, and this will not report it.
248
+ *
249
+ * @param index - The session's relation index.
250
+ * @param a - One node's IRI or blank label.
251
+ * @param b - The other node's IRI or blank label.
252
+ * @returns The shared roster groups, largest first then by predicate.
253
+ */
254
+ export function sharedRosters(index, a, b) {
255
+ const mine = index.rosters.get(a) ?? [];
256
+ const theirs = new Set(index.rosters.get(b) ?? []);
257
+ const shared = [];
258
+ for (const key of mine) {
259
+ if (!theirs.has(key))
260
+ continue;
261
+ const group = index.groups.get(key);
262
+ if (!group)
263
+ continue;
264
+ shared.push({
265
+ side: group.side,
266
+ predicate: index.term(group.predicate),
267
+ node: index.term(group.node),
268
+ members: group.members,
269
+ });
270
+ }
271
+ return sortRosters(shared);
272
+ }
273
+ /**
274
+ * The roster groups one node belongs to — what classifies an entity that
275
+ * carries no relation at all.
276
+ *
277
+ * @param index - The session's relation index.
278
+ * @param node - The node's IRI or blank label.
279
+ * @returns The node's roster groups, largest first then by predicate.
280
+ */
281
+ export function rosterMemberships(index, node) {
282
+ const groups = [];
283
+ for (const key of index.rosters.get(node) ?? []) {
284
+ const group = index.groups.get(key);
285
+ if (!group)
286
+ continue;
287
+ groups.push({
288
+ side: group.side,
289
+ predicate: index.term(group.predicate),
290
+ node: index.term(group.node),
291
+ members: group.members,
292
+ });
293
+ }
294
+ return sortRosters(groups);
295
+ }
296
+ /** Order rosters by size then by name, so two runs agree. */
297
+ function sortRosters(groups) {
298
+ return groups.sort((x, y) => y.members - x.members ||
299
+ x.predicate.value.localeCompare(y.predicate.value) ||
300
+ x.node.value.localeCompare(y.node.value));
301
+ }
302
+ //# sourceMappingURL=relationIndex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"relationIndex.js","sourceRoot":"","sources":["../../../../src/capabilities/graph/relationIndex.ts"],"names":[],"mappings":"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"}