@thymian/plugin-sampler 0.3.0-canary.20261007-e6cb8dc → 0.3.0-canary.20261007-cdbe1d3

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 (264) hide show
  1. package/dist/cli/check-result.d.ts +88 -0
  2. package/dist/cli/check-result.d.ts.map +1 -0
  3. package/dist/cli/check-result.js +160 -0
  4. package/dist/cli/check-result.js.map +1 -0
  5. package/dist/cli/commands/sampler/check.d.ts +32 -4
  6. package/dist/cli/commands/sampler/check.d.ts.map +1 -1
  7. package/dist/cli/commands/sampler/check.js +126 -88
  8. package/dist/cli/commands/sampler/check.js.map +1 -1
  9. package/dist/cli/commands/sampler/init.d.ts +4 -6
  10. package/dist/cli/commands/sampler/init.d.ts.map +1 -1
  11. package/dist/cli/commands/sampler/init.js +33 -49
  12. package/dist/cli/commands/sampler/init.js.map +1 -1
  13. package/dist/cli/commands/sampler/show.d.ts +11 -0
  14. package/dist/cli/commands/sampler/show.d.ts.map +1 -0
  15. package/dist/cli/commands/sampler/show.js +36 -0
  16. package/dist/cli/commands/sampler/show.js.map +1 -0
  17. package/dist/cli/commands/sampler/sync.d.ts +11 -0
  18. package/dist/cli/commands/sampler/sync.d.ts.map +1 -0
  19. package/dist/cli/commands/sampler/sync.js +65 -0
  20. package/dist/cli/commands/sampler/sync.js.map +1 -0
  21. package/dist/cli/commands/sampler/validate.d.ts +3 -10
  22. package/dist/cli/commands/sampler/validate.d.ts.map +1 -1
  23. package/dist/cli/commands/sampler/validate.js +57 -126
  24. package/dist/cli/commands/sampler/validate.js.map +1 -1
  25. package/dist/generation/closed-schema.d.ts +22 -0
  26. package/dist/generation/closed-schema.d.ts.map +1 -0
  27. package/dist/generation/closed-schema.js +45 -0
  28. package/dist/generation/closed-schema.js.map +1 -0
  29. package/dist/generation/content-type-strategies/json.content-type-strategy.d.ts.map +1 -1
  30. package/dist/generation/content-type-strategies/json.content-type-strategy.js +3 -1
  31. package/dist/generation/content-type-strategies/json.content-type-strategy.js.map +1 -1
  32. package/dist/generation/content-type-strategies/xml.content-type-strategy.d.ts.map +1 -1
  33. package/dist/generation/content-type-strategies/xml.content-type-strategy.js +3 -1
  34. package/dist/generation/content-type-strategies/xml.content-type-strategy.js.map +1 -1
  35. package/dist/generation/generate-request-sample.d.ts +12 -0
  36. package/dist/generation/generate-request-sample.d.ts.map +1 -0
  37. package/dist/generation/{generate-samples.js → generate-request-sample.js} +11 -4
  38. package/dist/generation/generate-request-sample.js.map +1 -0
  39. package/dist/generation/request-generators/default-request-generator.d.ts +14 -0
  40. package/dist/generation/request-generators/default-request-generator.d.ts.map +1 -1
  41. package/dist/generation/request-generators/default-request-generator.js +18 -1
  42. package/dist/generation/request-generators/default-request-generator.js.map +1 -1
  43. package/dist/generation/types/declaration-set.d.ts +124 -0
  44. package/dist/generation/types/declaration-set.d.ts.map +1 -0
  45. package/dist/generation/types/declaration-set.js +389 -0
  46. package/dist/generation/types/declaration-set.js.map +1 -0
  47. package/dist/generation/types/example-reflection.d.ts +21 -0
  48. package/dist/generation/types/example-reflection.d.ts.map +1 -0
  49. package/dist/generation/types/example-reflection.js +135 -0
  50. package/dist/generation/types/example-reflection.js.map +1 -0
  51. package/dist/generation/types/generate-type-surface.d.ts +23 -0
  52. package/dist/generation/types/generate-type-surface.d.ts.map +1 -0
  53. package/dist/generation/types/generate-type-surface.js +671 -0
  54. package/dist/generation/types/generate-type-surface.js.map +1 -0
  55. package/dist/generation/types/schema-type.d.ts +20 -0
  56. package/dist/generation/types/schema-type.d.ts.map +1 -0
  57. package/dist/generation/types/schema-type.js +203 -0
  58. package/dist/generation/types/schema-type.js.map +1 -0
  59. package/dist/generation/types/self-check-surface.d.ts +32 -0
  60. package/dist/generation/types/self-check-surface.d.ts.map +1 -0
  61. package/dist/generation/types/self-check-surface.js +92 -0
  62. package/dist/generation/types/self-check-surface.js.map +1 -0
  63. package/dist/generation/types/type-names.d.ts +135 -0
  64. package/dist/generation/types/type-names.d.ts.map +1 -0
  65. package/dist/generation/types/type-names.js +213 -0
  66. package/dist/generation/types/type-names.js.map +1 -0
  67. package/dist/generation/types/write-type-surface.d.ts +58 -0
  68. package/dist/generation/types/write-type-surface.d.ts.map +1 -0
  69. package/dist/generation/types/write-type-surface.js +119 -0
  70. package/dist/generation/types/write-type-surface.js.map +1 -0
  71. package/dist/hooks/create-hook-utils.d.ts +22 -6
  72. package/dist/hooks/create-hook-utils.d.ts.map +1 -1
  73. package/dist/hooks/create-hook-utils.js +74 -96
  74. package/dist/hooks/create-hook-utils.js.map +1 -1
  75. package/dist/hooks/hook-api.d.ts +49 -0
  76. package/dist/hooks/hook-api.d.ts.map +1 -0
  77. package/dist/hooks/hook-api.js +105 -0
  78. package/dist/hooks/hook-api.js.map +1 -0
  79. package/dist/hooks/hook-diagnostics.d.ts +45 -0
  80. package/dist/hooks/hook-diagnostics.d.ts.map +1 -0
  81. package/dist/hooks/hook-diagnostics.js +80 -0
  82. package/dist/hooks/hook-diagnostics.js.map +1 -0
  83. package/dist/hooks/hook-errors.d.ts +33 -0
  84. package/dist/hooks/hook-errors.d.ts.map +1 -1
  85. package/dist/hooks/hook-errors.js +46 -0
  86. package/dist/hooks/hook-errors.js.map +1 -1
  87. package/dist/hooks/hook-registration.d.ts +108 -0
  88. package/dist/hooks/hook-registration.d.ts.map +1 -0
  89. package/dist/hooks/hook-registration.js +69 -0
  90. package/dist/hooks/hook-registration.js.map +1 -0
  91. package/dist/hooks/hook-runner.d.ts +111 -11
  92. package/dist/hooks/hook-runner.d.ts.map +1 -1
  93. package/dist/hooks/hook-runner.js +309 -142
  94. package/dist/hooks/hook-runner.js.map +1 -1
  95. package/dist/hooks/hook-utils-factory.d.ts +19 -0
  96. package/dist/hooks/hook-utils-factory.d.ts.map +1 -0
  97. package/dist/hooks/hook-utils-factory.js +2 -0
  98. package/dist/hooks/hook-utils-factory.js.map +1 -0
  99. package/dist/hooks/hook-utils.d.ts +80 -12
  100. package/dist/hooks/hook-utils.d.ts.map +1 -1
  101. package/dist/hooks/invoke-hook.d.ts +71 -0
  102. package/dist/hooks/invoke-hook.d.ts.map +1 -0
  103. package/dist/hooks/invoke-hook.js +161 -0
  104. package/dist/hooks/invoke-hook.js.map +1 -0
  105. package/dist/hooks/load-user-hooks.d.ts +96 -0
  106. package/dist/hooks/load-user-hooks.d.ts.map +1 -0
  107. package/dist/hooks/load-user-hooks.js +432 -0
  108. package/dist/hooks/load-user-hooks.js.map +1 -0
  109. package/dist/hooks/nested-request.d.ts +21 -0
  110. package/dist/hooks/nested-request.d.ts.map +1 -0
  111. package/dist/hooks/nested-request.js +24 -0
  112. package/dist/hooks/nested-request.js.map +1 -0
  113. package/dist/hooks/overlay-args.d.ts +40 -0
  114. package/dist/hooks/overlay-args.d.ts.map +1 -0
  115. package/dist/hooks/overlay-args.js +84 -0
  116. package/dist/hooks/overlay-args.js.map +1 -0
  117. package/dist/hooks/resolve-targeting.d.ts +16 -0
  118. package/dist/hooks/resolve-targeting.d.ts.map +1 -0
  119. package/dist/hooks/resolve-targeting.js +168 -0
  120. package/dist/hooks/resolve-targeting.js.map +1 -0
  121. package/dist/hooks/run-scoped-hooks.d.ts +83 -0
  122. package/dist/hooks/run-scoped-hooks.d.ts.map +1 -0
  123. package/dist/hooks/run-scoped-hooks.js +153 -0
  124. package/dist/hooks/run-scoped-hooks.js.map +1 -0
  125. package/dist/index.d.ts +42 -19
  126. package/dist/index.d.ts.map +1 -1
  127. package/dist/index.js +152 -165
  128. package/dist/index.js.map +1 -1
  129. package/dist/request-sampler.d.ts +40 -11
  130. package/dist/request-sampler.d.ts.map +1 -1
  131. package/dist/request-sampler.js +51 -76
  132. package/dist/request-sampler.js.map +1 -1
  133. package/dist/sampler-paths.d.ts +19 -0
  134. package/dist/sampler-paths.d.ts.map +1 -0
  135. package/dist/sampler-paths.js +22 -0
  136. package/dist/sampler-paths.js.map +1 -0
  137. package/dist/selectors/nearest-paths.d.ts +14 -0
  138. package/dist/selectors/nearest-paths.d.ts.map +1 -0
  139. package/dist/selectors/nearest-paths.js +32 -0
  140. package/dist/selectors/nearest-paths.js.map +1 -0
  141. package/dist/selectors/path-glob.d.ts +94 -0
  142. package/dist/selectors/path-glob.d.ts.map +1 -0
  143. package/dist/selectors/path-glob.js +136 -0
  144. package/dist/selectors/path-glob.js.map +1 -0
  145. package/dist/selectors/selector-errors.d.ts +17 -0
  146. package/dist/selectors/selector-errors.d.ts.map +1 -0
  147. package/dist/selectors/selector-errors.js +139 -0
  148. package/dist/selectors/selector-errors.js.map +1 -0
  149. package/dist/selectors/selector.d.ts +55 -0
  150. package/dist/selectors/selector.d.ts.map +1 -0
  151. package/dist/selectors/selector.js +305 -0
  152. package/dist/selectors/selector.js.map +1 -0
  153. package/dist/selectors/transaction-catalog.d.ts +96 -0
  154. package/dist/selectors/transaction-catalog.d.ts.map +1 -0
  155. package/dist/selectors/transaction-catalog.js +193 -0
  156. package/dist/selectors/transaction-catalog.js.map +1 -0
  157. package/dist/selectors/transaction-filter.d.ts +119 -0
  158. package/dist/selectors/transaction-filter.d.ts.map +1 -0
  159. package/dist/selectors/transaction-filter.js +191 -0
  160. package/dist/selectors/transaction-filter.js.map +1 -0
  161. package/dist/ts-path.d.ts +36 -0
  162. package/dist/ts-path.d.ts.map +1 -0
  163. package/dist/ts-path.js +46 -0
  164. package/dist/ts-path.js.map +1 -0
  165. package/dist/utils.d.ts +1 -2
  166. package/dist/utils.d.ts.map +1 -1
  167. package/dist/utils.js +2 -20
  168. package/dist/utils.js.map +1 -1
  169. package/dist/validation/canonicalize.d.ts +17 -0
  170. package/dist/validation/canonicalize.d.ts.map +1 -0
  171. package/dist/validation/canonicalize.js +29 -0
  172. package/dist/validation/canonicalize.js.map +1 -0
  173. package/dist/validation/shared-compiler-host.d.ts +17 -0
  174. package/dist/validation/shared-compiler-host.d.ts.map +1 -0
  175. package/dist/validation/shared-compiler-host.js +58 -0
  176. package/dist/validation/shared-compiler-host.js.map +1 -0
  177. package/dist/validation/typecheck-hooks.d.ts +37 -0
  178. package/dist/validation/typecheck-hooks.d.ts.map +1 -0
  179. package/dist/validation/typecheck-hooks.js +169 -0
  180. package/dist/validation/typecheck-hooks.js.map +1 -0
  181. package/dist/validation/validate-sampler.d.ts +79 -0
  182. package/dist/validation/validate-sampler.d.ts.map +1 -0
  183. package/dist/validation/validate-sampler.js +89 -0
  184. package/dist/validation/validate-sampler.js.map +1 -0
  185. package/package.json +7 -11
  186. package/dist/cli/commands/sampler/generate/hook.d.ts +0 -10
  187. package/dist/cli/commands/sampler/generate/hook.d.ts.map +0 -1
  188. package/dist/cli/commands/sampler/generate/hook.js +0 -19
  189. package/dist/cli/commands/sampler/generate/hook.js.map +0 -1
  190. package/dist/cli/generate-hook.d.ts +0 -4
  191. package/dist/cli/generate-hook.d.ts.map +0 -1
  192. package/dist/cli/generate-hook.js +0 -96
  193. package/dist/cli/generate-hook.js.map +0 -1
  194. package/dist/cli/templates.d.ts +0 -4
  195. package/dist/cli/templates.d.ts.map +0 -1
  196. package/dist/cli/templates.js +0 -28
  197. package/dist/cli/templates.js.map +0 -1
  198. package/dist/constants.d.ts +0 -12
  199. package/dist/constants.d.ts.map +0 -1
  200. package/dist/constants.js +0 -16
  201. package/dist/constants.js.map +0 -1
  202. package/dist/generation/generate-samples-for-thymian-format.d.ts +0 -4
  203. package/dist/generation/generate-samples-for-thymian-format.d.ts.map +0 -1
  204. package/dist/generation/generate-samples-for-thymian-format.js +0 -18
  205. package/dist/generation/generate-samples-for-thymian-format.js.map +0 -1
  206. package/dist/generation/generate-samples.d.ts +0 -4
  207. package/dist/generation/generate-samples.d.ts.map +0 -1
  208. package/dist/generation/generate-samples.js.map +0 -1
  209. package/dist/hooks/generate-request-types.d.ts +0 -34
  210. package/dist/hooks/generate-request-types.d.ts.map +0 -1
  211. package/dist/hooks/generate-request-types.js +0 -458
  212. package/dist/hooks/generate-request-types.js.map +0 -1
  213. package/dist/hooks/hook-types.d.ts +0 -7
  214. package/dist/hooks/hook-types.d.ts.map +0 -1
  215. package/dist/hooks/hook-types.js +0 -2
  216. package/dist/hooks/hook-types.js.map +0 -1
  217. package/dist/hooks/load-hooks-from-samples.d.ts +0 -3
  218. package/dist/hooks/load-hooks-from-samples.d.ts.map +0 -1
  219. package/dist/hooks/load-hooks-from-samples.js +0 -22
  220. package/dist/hooks/load-hooks-from-samples.js.map +0 -1
  221. package/dist/hooks/ts-config.d.ts +0 -10
  222. package/dist/hooks/ts-config.d.ts.map +0 -1
  223. package/dist/hooks/ts-config.js +0 -10
  224. package/dist/hooks/ts-config.js.map +0 -1
  225. package/dist/samples-structure/file-request-sample.d.ts +0 -20
  226. package/dist/samples-structure/file-request-sample.d.ts.map +0 -1
  227. package/dist/samples-structure/file-request-sample.js +0 -5
  228. package/dist/samples-structure/file-request-sample.js.map +0 -1
  229. package/dist/samples-structure/get-path-transaction-id.d.ts +0 -3
  230. package/dist/samples-structure/get-path-transaction-id.d.ts.map +0 -1
  231. package/dist/samples-structure/get-path-transaction-id.js +0 -22
  232. package/dist/samples-structure/get-path-transaction-id.js.map +0 -1
  233. package/dist/samples-structure/merge-tree.d.ts +0 -5
  234. package/dist/samples-structure/merge-tree.d.ts.map +0 -1
  235. package/dist/samples-structure/merge-tree.js +0 -118
  236. package/dist/samples-structure/merge-tree.js.map +0 -1
  237. package/dist/samples-structure/read-samples-from-dir.d.ts +0 -13
  238. package/dist/samples-structure/read-samples-from-dir.d.ts.map +0 -1
  239. package/dist/samples-structure/read-samples-from-dir.js +0 -205
  240. package/dist/samples-structure/read-samples-from-dir.js.map +0 -1
  241. package/dist/samples-structure/samples-from-transactions.d.ts +0 -5
  242. package/dist/samples-structure/samples-from-transactions.d.ts.map +0 -1
  243. package/dist/samples-structure/samples-from-transactions.js +0 -120
  244. package/dist/samples-structure/samples-from-transactions.js.map +0 -1
  245. package/dist/samples-structure/samples-tree-structure.d.ts +0 -106
  246. package/dist/samples-structure/samples-tree-structure.d.ts.map +0 -1
  247. package/dist/samples-structure/samples-tree-structure.js +0 -26
  248. package/dist/samples-structure/samples-tree-structure.js.map +0 -1
  249. package/dist/samples-structure/structure-meta-on-disc.d.ts +0 -11
  250. package/dist/samples-structure/structure-meta-on-disc.d.ts.map +0 -1
  251. package/dist/samples-structure/structure-meta-on-disc.js +0 -2
  252. package/dist/samples-structure/structure-meta-on-disc.js.map +0 -1
  253. package/dist/samples-structure/traverse.d.ts +0 -4
  254. package/dist/samples-structure/traverse.d.ts.map +0 -1
  255. package/dist/samples-structure/traverse.js +0 -13
  256. package/dist/samples-structure/traverse.js.map +0 -1
  257. package/dist/samples-structure/write-samples-to-dir.d.ts +0 -37
  258. package/dist/samples-structure/write-samples-to-dir.d.ts.map +0 -1
  259. package/dist/samples-structure/write-samples-to-dir.js +0 -183
  260. package/dist/samples-structure/write-samples-to-dir.js.map +0 -1
  261. package/dist/validation/validate-sampler-output.d.ts +0 -38
  262. package/dist/validation/validate-sampler-output.d.ts.map +0 -1
  263. package/dist/validation/validate-sampler-output.js +0 -288
  264. package/dist/validation/validate-sampler-output.js.map +0 -1
@@ -0,0 +1,305 @@
1
+ import { canonicalPath, encodeMediaType, encodeMethod, encodePath, errorSuggestions, formatRequestSelector, formatResponseSelector, formatSelector, SELECTOR_METHOD_CHARS, selectorForTransaction, } from '@thymian/core';
2
+ import { malformedSelectorError } from './selector-errors.js';
3
+ /**
4
+ * The selector grammar, plugin side: everything that reads a selector.
5
+ *
6
+ * **Rendering lives in `@thymian/core`** (`selector/render-selector.ts`) and is
7
+ * re-exported here, because a selector is two things at once — the sampler's
8
+ * *address* of a Transaction and the application's *label* for one — and every
9
+ * surface core prints has to render the same grammar the sampler resolves
10
+ * (ADR-0022). What stays here is what only an address needs: parsing back,
11
+ * near-miss diagnostics and the catalog's ordering.
12
+ *
13
+ * The reader below is the inverse of core's encoders. The two are one grammar
14
+ * split across two packages, so the round-trip property — every rendered
15
+ * selector parses, and parses back to what it was rendered from — is the test
16
+ * that keeps them honest.
17
+ */
18
+ export { canonicalPath, encodeMediaType, encodeMethod, encodePath, formatRequestSelector, formatResponseSelector, formatSelector, selectorForTransaction, };
19
+ const METHOD_TOKEN = new RegExp(`^[${SELECTOR_METHOD_CHARS}]+$`);
20
+ const UPPERCASE_METHOD = new RegExp(`^[A-Z0-9!#$%&'*+.^_\`|~-]+$`);
21
+ /** Reads a quoted component starting at `open`, and says where it ended. */
22
+ function readQuoted(value, open) {
23
+ let content = '';
24
+ for (let i = open + 1; i < value.length; i++) {
25
+ const char = value[i];
26
+ if (char === '\\') {
27
+ const next = value[i + 1];
28
+ if (next === undefined) {
29
+ return undefined;
30
+ }
31
+ content += next;
32
+ i++;
33
+ continue;
34
+ }
35
+ if (char === '"') {
36
+ return { content, end: i };
37
+ }
38
+ content += char;
39
+ }
40
+ return undefined;
41
+ }
42
+ /**
43
+ * Reads a media group starting at the `(` at `open`, and says where it ended.
44
+ *
45
+ * The inverse of core's media-type encoder: outside a quoted string a `\`
46
+ * escapes the next character and is dropped, a `"` opens quote state, and the
47
+ * first unescaped, unquoted `)` ends the group. Inside a quoted string
48
+ * everything is carried through, quoted-pairs included, because that text is
49
+ * the media type's own.
50
+ */
51
+ function readMediaGroup(value, open) {
52
+ let content = '';
53
+ let inQuotes = false;
54
+ for (let i = open + 1; i < value.length; i++) {
55
+ const char = value[i];
56
+ if (inQuotes) {
57
+ if (char === '\\' && i + 1 < value.length) {
58
+ content += char + value[i + 1];
59
+ i++;
60
+ continue;
61
+ }
62
+ if (char === '"') {
63
+ inQuotes = false;
64
+ }
65
+ content += char;
66
+ continue;
67
+ }
68
+ if (char === '\\') {
69
+ const next = value[i + 1];
70
+ if (next === undefined) {
71
+ return undefined;
72
+ }
73
+ content += next;
74
+ i++;
75
+ continue;
76
+ }
77
+ if (char === '"') {
78
+ inQuotes = true;
79
+ content += char;
80
+ continue;
81
+ }
82
+ if (char === ')') {
83
+ return { content, end: i };
84
+ }
85
+ content += char;
86
+ }
87
+ return undefined;
88
+ }
89
+ /**
90
+ * Total order on selectors, by UTF-16 code unit.
91
+ *
92
+ * Deliberately not `localeCompare`: the catalog's order is the order of the
93
+ * generated type surface, and a locale-sensitive comparison would make the
94
+ * committed types depend on the machine that generated them.
95
+ */
96
+ export function compareSelectors(a, b) {
97
+ return a < b ? -1 : a > b ? 1 : 0;
98
+ }
99
+ /**
100
+ * Splits a selector into its five components.
101
+ *
102
+ * This hand-written reader is the **only** description of the grammar's read
103
+ * direction. An equivalent regex used to sit beside it as a shape test, and the
104
+ * two disagreed: a media type containing a newline rendered into a selector the
105
+ * regex rejected, because `.` excludes line terminators. One grammar, one
106
+ * reader.
107
+ *
108
+ * Returns `undefined` for anything that is not a selector; the caller decides
109
+ * whether that is a diagnostic or a hint attempt.
110
+ */
111
+ function splitSelector(value) {
112
+ let at = 0;
113
+ const method = readComponent(value, at);
114
+ if (!method) {
115
+ return undefined;
116
+ }
117
+ if (!method.quoted && !METHOD_TOKEN.test(method.content)) {
118
+ return undefined;
119
+ }
120
+ at = method.end;
121
+ if (value[at] !== ' ') {
122
+ return undefined;
123
+ }
124
+ at += 1;
125
+ const path = readComponent(value, at);
126
+ if (!path || !path.content.startsWith('/')) {
127
+ return undefined;
128
+ }
129
+ at = path.end;
130
+ let requestMediaType;
131
+ if (value.startsWith(' (', at)) {
132
+ const group = readMediaGroup(value, at + 1);
133
+ if (!group) {
134
+ return undefined;
135
+ }
136
+ requestMediaType = group.content;
137
+ at = group.end + 1;
138
+ }
139
+ if (!value.startsWith(' -> ', at)) {
140
+ return undefined;
141
+ }
142
+ at += 4;
143
+ const statusEnd = value.indexOf(' ', at);
144
+ const status = value.slice(at, statusEnd === -1 ? undefined : statusEnd);
145
+ if (status.length === 0 || /[\s()]/.test(status)) {
146
+ return undefined;
147
+ }
148
+ let responseMediaType;
149
+ if (statusEnd !== -1) {
150
+ at = statusEnd;
151
+ if (!value.startsWith(' (', at)) {
152
+ return undefined;
153
+ }
154
+ const group = readMediaGroup(value, at + 1);
155
+ if (!group || group.end !== value.length - 1) {
156
+ return undefined;
157
+ }
158
+ responseMediaType = group.content;
159
+ }
160
+ return {
161
+ method: method.content,
162
+ path: path.content,
163
+ requestMediaType,
164
+ status: Number(status),
165
+ responseMediaType,
166
+ };
167
+ }
168
+ /**
169
+ * Reads a method or path: a quoted string when it begins with `"`, otherwise the
170
+ * run of characters up to the next space.
171
+ */
172
+ function readComponent(value, at) {
173
+ if (at >= value.length) {
174
+ return undefined;
175
+ }
176
+ if (value[at] === '"') {
177
+ const read = readQuoted(value, at);
178
+ return read
179
+ ? { content: read.content, end: read.end + 1, quoted: true }
180
+ : undefined;
181
+ }
182
+ const space = value.indexOf(' ', at);
183
+ const end = space === -1 ? value.length : space;
184
+ const content = value.slice(at, end);
185
+ return content.length > 0 ? { content, end, quoted: false } : undefined;
186
+ }
187
+ /**
188
+ * Parses a selector back into its components.
189
+ *
190
+ * For DIAGNOSTICS ONLY. Resolution is a map lookup
191
+ * (`TransactionCatalog.resolve`); a parse happens only after a miss, to decide
192
+ * whether the value was malformed or merely unknown. Do not move a parse onto
193
+ * the happy path.
194
+ */
195
+ export function parseSelector(value) {
196
+ const parts = splitSelector(value);
197
+ if (!parts) {
198
+ throw malformedSelectorError(value, canonicalFormHint(value));
199
+ }
200
+ return parts;
201
+ }
202
+ /** Whether `value` is a syntactically well-formed selector. */
203
+ export function isSelector(value) {
204
+ return splitSelector(value) !== undefined;
205
+ }
206
+ /**
207
+ * The suggestions a malformed selector's diagnostic carries — the grammar,
208
+ * an example, and a canonical-form guess when the value is close. Never
209
+ * throws.
210
+ *
211
+ * Reads `malformedSelectorError`'s own message composition rather than
212
+ * duplicating it, so a hook-target diagnostic for a malformed Selector and
213
+ * the error `catalog.resolve` throws for one typed on the CLI say exactly the
214
+ * same thing — one grammar, one set of hints, two call sites.
215
+ */
216
+ export function malformedSelectorHints(value) {
217
+ return errorSuggestions(malformedSelectorError(value, canonicalFormHint(value)));
218
+ }
219
+ /**
220
+ * The grammar relaxed on exactly the three axes a hand-authored selector slips
221
+ * on — method case, the leading slash, and a zero-padded status. Used ONLY to
222
+ * turn a rejection into a "did you mean …?" suggestion; it never decides whether
223
+ * a selector is valid.
224
+ */
225
+ const LENIENT_SHAPE = new RegExp(`^([${SELECTOR_METHOD_CHARS}]+) (\\S+)(?: \\(([^()]*)\\))? -> (\\d+)(?: \\(([^()]*)\\))?$`);
226
+ /**
227
+ * Whether prepending the missing leading slash would be a correction rather than
228
+ * an invention. Without this the hint manufactures paths out of URLs.
229
+ *
230
+ * A path that merely lost its slash begins with a path *segment*, so the
231
+ * judgement is made on the first segment alone: a `:` there is a scheme or an
232
+ * authority port, a `.` there is a host label or a relative-path marker, and a
233
+ * leading `(`, `?` or `#` is a media type, query string or fragment promoted
234
+ * into the path slot. Judging only the first segment keeps a legal slash-less
235
+ * path such as `users/{id}:activate` eligible.
236
+ */
237
+ function canonicalizablePath(path) {
238
+ if (path.startsWith('/')) {
239
+ return true;
240
+ }
241
+ if (/^[(?#]/.test(path)) {
242
+ return false;
243
+ }
244
+ const firstSegment = path.split('/', 1)[0] ?? path;
245
+ return !(firstSegment.includes(':') || firstSegment.includes('.'));
246
+ }
247
+ /**
248
+ * Strips a status's zero padding, but only when what is left is a status code —
249
+ * three digits, per RFC 9110 §15. Reinterpreting through `Number` instead would
250
+ * turn `007` into `7`, suggesting a selector no transaction can carry.
251
+ */
252
+ function canonicalStatus(status) {
253
+ const stripped = status.replace(/^0+/, '');
254
+ return /^[1-9]\d\d$/.test(stripped) ? stripped : status;
255
+ }
256
+ function joinWithAnd(items) {
257
+ if (items.length < 2) {
258
+ return items.join('');
259
+ }
260
+ return `${items.slice(0, -1).join(', ')} and ${items[items.length - 1] ?? ''}`;
261
+ }
262
+ /** States only the corrections the hint actually made. */
263
+ function describeNormalizations(method, path, status) {
264
+ const rules = [];
265
+ if (!UPPERCASE_METHOD.test(method)) {
266
+ rules.push('spells its method in uppercase');
267
+ }
268
+ if (!path.startsWith('/')) {
269
+ rules.push('spells its path with a leading "/"');
270
+ }
271
+ if (canonicalStatus(status) !== status) {
272
+ rules.push('spells its status without leading zeros');
273
+ }
274
+ return rules.length > 0 ? `A selector ${joinWithAnd(rules)}. ` : '';
275
+ }
276
+ /**
277
+ * Suggests the canonical spelling of a value that is *nearly* a selector:
278
+ * lowercase method, missing leading slash, zero-padded status. Returns nothing
279
+ * when the value is not recognizable or already canonical.
280
+ */
281
+ function canonicalFormHint(value) {
282
+ const match = LENIENT_SHAPE.exec(value);
283
+ if (!match) {
284
+ return [];
285
+ }
286
+ const method = match[1];
287
+ const path = match[2];
288
+ const status = match[4];
289
+ if (method === undefined || path === undefined || status === undefined) {
290
+ return [];
291
+ }
292
+ if (!canonicalizablePath(path)) {
293
+ return [];
294
+ }
295
+ const requestMedia = match[3] ? ` (${match[3]})` : '';
296
+ const responseMedia = match[5] ? ` (${match[5]})` : '';
297
+ const canonical = `${method.toUpperCase()} ${encodePath(path)}${requestMedia} -> ${canonicalStatus(status)}${responseMedia}`;
298
+ if (canonical === value || !isSelector(canonical)) {
299
+ return [];
300
+ }
301
+ return [
302
+ `${describeNormalizations(method, path, status)}Did you mean "${canonical}"?`,
303
+ ];
304
+ }
305
+ //# sourceMappingURL=selector.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"selector.js","sourceRoot":"","sources":["../../src/selectors/selector.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,96 @@
1
+ import type { ThymianFormat, ThymianHttpTransaction } from '@thymian/core';
2
+ import { type Selector, type SelectorParts } from './selector.js';
3
+ export type TransactionCatalogEntry = readonly [
4
+ Selector,
5
+ ThymianHttpTransaction
6
+ ];
7
+ /**
8
+ * A bijection between the selectors of a loaded `ThymianFormat` and its
9
+ * transactions.
10
+ *
11
+ * Built once per format load and thrown away with the format — it is cheap, and
12
+ * caching it on `format.toHash()` would reintroduce exactly the staleness the
13
+ * selector exists to remove.
14
+ */
15
+ export declare class TransactionCatalog {
16
+ private readonly bySelector;
17
+ private readonly orderedEntries;
18
+ private readonly selectorByTransactionId;
19
+ private readonly distinctPaths;
20
+ private readonly byOperation;
21
+ private constructor();
22
+ /**
23
+ * One pass over `format.getThymianHttpTransactions()`, then a sort.
24
+ *
25
+ * @throws `SelectorCollisionError` as soon as two transactions render the same
26
+ * selector. That is the only hard error here. Rendering is total and
27
+ * injective, so no description can make catalog construction impossible and no
28
+ * two *distinct* transactions can collide by accident of encoding: a collision
29
+ * means two sources describe the same method, path, status and media types,
30
+ * and a selector is host-stripped, so nothing distinguishes them. Silently
31
+ * picking one would make a hook target whichever load order won.
32
+ */
33
+ static fromThymianFormat(format: ThymianFormat): TransactionCatalog;
34
+ get size(): number;
35
+ /**
36
+ * Selectors sorted by selector.
37
+ *
38
+ * The order is a decision, not an accident: it is the order the generated type
39
+ * surface is emitted in, so sorting is what makes reordering paths or schemas
40
+ * in the source document a drift non-event. Correctness never depends on it.
41
+ */
42
+ selectors(): readonly Selector[];
43
+ entries(): readonly TransactionCatalogEntry[];
44
+ /**
45
+ * Every distinct path the catalog holds, sorted — the universe a path glob is
46
+ * matched against, and the set a vacuous glob fails against.
47
+ *
48
+ * Derived once at construction, like the selector index: both are read once
49
+ * per hook that targets by filter, and the catalog is rebuilt per format load
50
+ * anyway.
51
+ */
52
+ paths(): readonly string[];
53
+ /**
54
+ * Every Transaction the same operation declares — the responses a call to
55
+ * `transaction` may legitimately be answered with.
56
+ *
57
+ * Grouped by the **request half of the selector**, which is what the
58
+ * generated `Responses` map is keyed by, so the union the types promise and
59
+ * the set the runtime checks against are built by one rule. Two sources
60
+ * describing the same operation contribute to one group; that is a superset,
61
+ * and a superset is the safe direction — it never calls a declared response
62
+ * undeclared.
63
+ */
64
+ responsesOf(transaction: ThymianHttpTransaction): readonly TransactionCatalogEntry[];
65
+ /** The selector one transaction renders as, for a diagnostic that has the id. */
66
+ selectorFor(transactionId: string): Selector | undefined;
67
+ /** Every Transaction, in catalog order. */
68
+ transactions(): readonly ThymianHttpTransaction[];
69
+ /** Never throws. Use where a miss is an expected outcome. */
70
+ tryResolve(selector: string): ThymianHttpTransaction | undefined;
71
+ /**
72
+ * A plain map lookup. Parsing happens only after a miss, to tell the caller
73
+ * whether the selector was malformed or merely unknown — never on the happy
74
+ * path.
75
+ *
76
+ * @throws `MalformedSelectorError` when the input is not a selector,
77
+ * `UnknownSelectorError` when it is well-formed but names nothing loaded.
78
+ */
79
+ resolve(selector: string): ThymianHttpTransaction;
80
+ /**
81
+ * What to say to someone who named a selector nothing answers to.
82
+ *
83
+ * Public because the hook loader needs the same sentences without wanting the
84
+ * throw: it has already missed through {@link tryResolve}, and asking for the
85
+ * diagnostic by catching a second, deliberately failing lookup would make the
86
+ * error channel do the work of a query.
87
+ */
88
+ nearMissSuggestions(parts: SelectorParts): string[];
89
+ /**
90
+ * Deterministic rank buckets, in catalog order: same method and path first,
91
+ * then the same path under another method. No fuzzy matching — it would add a
92
+ * dependency and make the ordering unexplainable.
93
+ */
94
+ private nearMisses;
95
+ }
96
+ //# sourceMappingURL=transaction-catalog.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-catalog.d.ts","sourceRoot":"","sources":["../../src/selectors/transaction-catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAC;AAG3E,OAAO,EAML,KAAK,QAAQ,EAEb,KAAK,aAAa,EACnB,MAAM,eAAe,CAAC;AASvB,MAAM,MAAM,uBAAuB,GAAG,SAAS;IAC7C,QAAQ;IACR,sBAAsB;CACvB,CAAC;AAEF;;;;;;;GAOG;AACH,qBAAa,kBAAkB;IAE3B,OAAO,CAAC,QAAQ,CAAC,UAAU;IAC3B,OAAO,CAAC,QAAQ,CAAC,cAAc;IAC/B,OAAO,CAAC,QAAQ,CAAC,uBAAuB;IACxC,OAAO,CAAC,QAAQ,CAAC,aAAa;IAC9B,OAAO,CAAC,QAAQ,CAAC,WAAW;IAL9B,OAAO;IAWP;;;;;;;;;;OAUG;IACH,MAAM,CAAC,iBAAiB,CAAC,MAAM,EAAE,aAAa,GAAG,kBAAkB;IA+CnE,IAAI,IAAI,IAAI,MAAM,CAEjB;IAED;;;;;;OAMG;IACH,SAAS,IAAI,SAAS,QAAQ,EAAE;IAIhC,OAAO,IAAI,SAAS,uBAAuB,EAAE;IAI7C;;;;;;;OAOG;IACH,KAAK,IAAI,SAAS,MAAM,EAAE;IAI1B;;;;;;;;;;OAUG;IACH,WAAW,CACT,WAAW,EAAE,sBAAsB,GAClC,SAAS,uBAAuB,EAAE;IAMrC,iFAAiF;IACjF,WAAW,CAAC,aAAa,EAAE,MAAM,GAAG,QAAQ,GAAG,SAAS;IAIxD,2CAA2C;IAC3C,YAAY,IAAI,SAAS,sBAAsB,EAAE;IAIjD,6DAA6D;IAC7D,UAAU,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB,GAAG,SAAS;IAIhE;;;;;;;OAOG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,sBAAsB;IAajD;;;;;;;OAOG;IACH,mBAAmB,CAAC,KAAK,EAAE,aAAa,GAAG,MAAM,EAAE;IAgCnD;;;;OAIG;IACH,OAAO,CAAC,UAAU;CAmBnB"}
@@ -0,0 +1,193 @@
1
+ import { nearestPathHints } from './nearest-paths.js';
2
+ import { canonicalPath, compareSelectors, encodePath, formatRequestSelector, parseSelector, selectorForTransaction, } from './selector.js';
3
+ import { selectorCollisionError, unknownSelectorError, } from './selector-errors.js';
4
+ import { pathOf } from './transaction-filter.js';
5
+ const MAX_NEAR_MISSES = 5;
6
+ /**
7
+ * A bijection between the selectors of a loaded `ThymianFormat` and its
8
+ * transactions.
9
+ *
10
+ * Built once per format load and thrown away with the format — it is cheap, and
11
+ * caching it on `format.toHash()` would reintroduce exactly the staleness the
12
+ * selector exists to remove.
13
+ */
14
+ export class TransactionCatalog {
15
+ bySelector;
16
+ orderedEntries;
17
+ selectorByTransactionId;
18
+ distinctPaths;
19
+ byOperation;
20
+ constructor(bySelector, orderedEntries, selectorByTransactionId, distinctPaths, byOperation) {
21
+ this.bySelector = bySelector;
22
+ this.orderedEntries = orderedEntries;
23
+ this.selectorByTransactionId = selectorByTransactionId;
24
+ this.distinctPaths = distinctPaths;
25
+ this.byOperation = byOperation;
26
+ }
27
+ /**
28
+ * One pass over `format.getThymianHttpTransactions()`, then a sort.
29
+ *
30
+ * @throws `SelectorCollisionError` as soon as two transactions render the same
31
+ * selector. That is the only hard error here. Rendering is total and
32
+ * injective, so no description can make catalog construction impossible and no
33
+ * two *distinct* transactions can collide by accident of encoding: a collision
34
+ * means two sources describe the same method, path, status and media types,
35
+ * and a selector is host-stripped, so nothing distinguishes them. Silently
36
+ * picking one would make a hook target whichever load order won.
37
+ */
38
+ static fromThymianFormat(format) {
39
+ const bySelector = new Map();
40
+ for (const transaction of format.getThymianHttpTransactions()) {
41
+ const selector = selectorForTransaction(transaction);
42
+ const existing = bySelector.get(selector);
43
+ if (existing) {
44
+ throw selectorCollisionError(selector, existing, transaction);
45
+ }
46
+ bySelector.set(selector, transaction);
47
+ }
48
+ const orderedEntries = [...bySelector.entries()]
49
+ .sort(([a], [b]) => compareSelectors(a, b))
50
+ .map(([selector, transaction]) => [selector, transaction]);
51
+ const byOperation = new Map();
52
+ for (const entry of orderedEntries) {
53
+ const operation = formatRequestSelector(entry[1].thymianReq);
54
+ byOperation.set(operation, [
55
+ ...(byOperation.get(operation) ?? []),
56
+ entry,
57
+ ]);
58
+ }
59
+ return new TransactionCatalog(bySelector, orderedEntries, new Map(orderedEntries.map(([selector, transaction]) => [
60
+ transaction.transactionId,
61
+ selector,
62
+ ])), [
63
+ ...new Set(orderedEntries.map(([, transaction]) => pathOf(transaction))),
64
+ ].sort(), byOperation);
65
+ }
66
+ get size() {
67
+ return this.bySelector.size;
68
+ }
69
+ /**
70
+ * Selectors sorted by selector.
71
+ *
72
+ * The order is a decision, not an accident: it is the order the generated type
73
+ * surface is emitted in, so sorting is what makes reordering paths or schemas
74
+ * in the source document a drift non-event. Correctness never depends on it.
75
+ */
76
+ selectors() {
77
+ return this.orderedEntries.map(([selector]) => selector);
78
+ }
79
+ entries() {
80
+ return this.orderedEntries;
81
+ }
82
+ /**
83
+ * Every distinct path the catalog holds, sorted — the universe a path glob is
84
+ * matched against, and the set a vacuous glob fails against.
85
+ *
86
+ * Derived once at construction, like the selector index: both are read once
87
+ * per hook that targets by filter, and the catalog is rebuilt per format load
88
+ * anyway.
89
+ */
90
+ paths() {
91
+ return this.distinctPaths;
92
+ }
93
+ /**
94
+ * Every Transaction the same operation declares — the responses a call to
95
+ * `transaction` may legitimately be answered with.
96
+ *
97
+ * Grouped by the **request half of the selector**, which is what the
98
+ * generated `Responses` map is keyed by, so the union the types promise and
99
+ * the set the runtime checks against are built by one rule. Two sources
100
+ * describing the same operation contribute to one group; that is a superset,
101
+ * and a superset is the safe direction — it never calls a declared response
102
+ * undeclared.
103
+ */
104
+ responsesOf(transaction) {
105
+ return (this.byOperation.get(formatRequestSelector(transaction.thymianReq)) ?? []);
106
+ }
107
+ /** The selector one transaction renders as, for a diagnostic that has the id. */
108
+ selectorFor(transactionId) {
109
+ return this.selectorByTransactionId.get(transactionId);
110
+ }
111
+ /** Every Transaction, in catalog order. */
112
+ transactions() {
113
+ return this.orderedEntries.map(([, transaction]) => transaction);
114
+ }
115
+ /** Never throws. Use where a miss is an expected outcome. */
116
+ tryResolve(selector) {
117
+ return this.bySelector.get(selector);
118
+ }
119
+ /**
120
+ * A plain map lookup. Parsing happens only after a miss, to tell the caller
121
+ * whether the selector was malformed or merely unknown — never on the happy
122
+ * path.
123
+ *
124
+ * @throws `MalformedSelectorError` when the input is not a selector,
125
+ * `UnknownSelectorError` when it is well-formed but names nothing loaded.
126
+ */
127
+ resolve(selector) {
128
+ const transaction = this.bySelector.get(selector);
129
+ if (transaction) {
130
+ return transaction;
131
+ }
132
+ throw unknownSelectorError(selector, this.nearMissSuggestions(parseSelector(selector)));
133
+ }
134
+ /**
135
+ * What to say to someone who named a selector nothing answers to.
136
+ *
137
+ * Public because the hook loader needs the same sentences without wanting the
138
+ * throw: it has already missed through {@link tryResolve}, and asking for the
139
+ * diagnostic by catching a second, deliberately failing lookup would make the
140
+ * error channel do the work of a query.
141
+ */
142
+ nearMissSuggestions(parts) {
143
+ // An empty catalog is a state core explicitly warns about ("No nodes found
144
+ // in Thymian format"). Sending the user after a path typo would be wrong
145
+ // advice: no path would have resolved.
146
+ if (this.size === 0) {
147
+ return [
148
+ 'No transactions are loaded, so no selector can resolve. Check that your configured specifications were found and describe at least one operation.',
149
+ ];
150
+ }
151
+ const candidates = this.nearMisses(parts);
152
+ if (candidates.length > 0) {
153
+ return [
154
+ 'Did you mean one of these selectors?',
155
+ ...candidates.map((candidate) => `"${candidate}"`),
156
+ ];
157
+ }
158
+ // No transaction shares this exact path under any method, so the typo is
159
+ // most likely in the path itself. Falls back to the same prefix walk a
160
+ // vacuous filter path value gets, so a path typo in a Selector is
161
+ // diagnosed the same way one in a filter is — one near-miss story, not
162
+ // two that could disagree.
163
+ // `canonicalPath`, matching how `distinctPaths` is spelled (`pathOf`).
164
+ // `encodePath` adds selector quoting for a path carrying whitespace or
165
+ // `>`, and a quoted needle never prefix-matches an unquoted haystack — so
166
+ // exactly the paths whose spelling is hardest to guess got no suggestion
167
+ // and fell through to the bare "no path begins with" line.
168
+ return nearestPathHints(canonicalPath(parts.path), this.distinctPaths);
169
+ }
170
+ /**
171
+ * Deterministic rank buckets, in catalog order: same method and path first,
172
+ * then the same path under another method. No fuzzy matching — it would add a
173
+ * dependency and make the ordering unexplainable.
174
+ */
175
+ nearMisses(parts) {
176
+ const sameMethod = [];
177
+ const otherMethod = [];
178
+ const path = encodePath(parts.path);
179
+ for (const [selector, transaction] of this.orderedEntries) {
180
+ if (encodePath(transaction.thymianReq.path) !== path) {
181
+ continue;
182
+ }
183
+ if (transaction.thymianReq.method.toUpperCase() === parts.method) {
184
+ sameMethod.push(selector);
185
+ }
186
+ else {
187
+ otherMethod.push(selector);
188
+ }
189
+ }
190
+ return [...sameMethod, ...otherMethod].slice(0, MAX_NEAR_MISSES);
191
+ }
192
+ }
193
+ //# sourceMappingURL=transaction-catalog.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"transaction-catalog.js","sourceRoot":"","sources":["../../src/selectors/transaction-catalog.ts"],"names":[],"mappings":"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"}