@ontrails/warden 1.0.0-beta.12 → 1.0.0-beta.13

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 (182) hide show
  1. package/CHANGELOG.md +51 -31
  2. package/README.md +17 -17
  3. package/dist/cli.d.ts +1 -1
  4. package/dist/cli.d.ts.map +1 -1
  5. package/dist/cli.js +14 -10
  6. package/dist/cli.js.map +1 -1
  7. package/dist/drift.d.ts +6 -6
  8. package/dist/drift.d.ts.map +1 -1
  9. package/dist/drift.js +8 -8
  10. package/dist/drift.js.map +1 -1
  11. package/dist/formatters.js +2 -2
  12. package/dist/formatters.js.map +1 -1
  13. package/dist/index.d.ts +4 -4
  14. package/dist/index.d.ts.map +1 -1
  15. package/dist/index.js +5 -5
  16. package/dist/index.js.map +1 -1
  17. package/dist/rules/ast.d.ts +15 -11
  18. package/dist/rules/ast.d.ts.map +1 -1
  19. package/dist/rules/ast.js +34 -30
  20. package/dist/rules/ast.js.map +1 -1
  21. package/dist/rules/context-no-trailhead-types.d.ts +12 -0
  22. package/dist/rules/context-no-trailhead-types.d.ts.map +1 -0
  23. package/dist/rules/context-no-trailhead-types.js +96 -0
  24. package/dist/rules/context-no-trailhead-types.js.map +1 -0
  25. package/dist/rules/cross-declarations.d.ts +13 -0
  26. package/dist/rules/cross-declarations.d.ts.map +1 -0
  27. package/dist/rules/cross-declarations.js +264 -0
  28. package/dist/rules/cross-declarations.js.map +1 -0
  29. package/dist/rules/follow-declarations.d.ts +1 -1
  30. package/dist/rules/follow-declarations.js +5 -5
  31. package/dist/rules/follow-declarations.js.map +1 -1
  32. package/dist/rules/implementation-returns-result.d.ts +2 -2
  33. package/dist/rules/implementation-returns-result.js +6 -6
  34. package/dist/rules/implementation-returns-result.js.map +1 -1
  35. package/dist/rules/index.d.ts +4 -4
  36. package/dist/rules/index.d.ts.map +1 -1
  37. package/dist/rules/index.js +12 -12
  38. package/dist/rules/index.js.map +1 -1
  39. package/dist/rules/no-direct-impl-in-route.d.ts +4 -4
  40. package/dist/rules/no-direct-impl-in-route.js +14 -14
  41. package/dist/rules/no-direct-impl-in-route.js.map +1 -1
  42. package/dist/rules/no-direct-implementation-call.d.ts +3 -3
  43. package/dist/rules/no-direct-implementation-call.js +7 -7
  44. package/dist/rules/no-direct-implementation-call.js.map +1 -1
  45. package/dist/rules/no-sync-result-assumption.d.ts +1 -1
  46. package/dist/rules/no-sync-result-assumption.js +5 -5
  47. package/dist/rules/no-sync-result-assumption.js.map +1 -1
  48. package/dist/rules/no-throw-in-detour-target.js +2 -2
  49. package/dist/rules/no-throw-in-detour-target.js.map +1 -1
  50. package/dist/rules/no-throw-in-implementation.d.ts +1 -1
  51. package/dist/rules/no-throw-in-implementation.js +3 -3
  52. package/dist/rules/no-throw-in-implementation.js.map +1 -1
  53. package/dist/rules/provision-declarations.d.ts +14 -0
  54. package/dist/rules/provision-declarations.d.ts.map +1 -0
  55. package/dist/rules/provision-declarations.js +344 -0
  56. package/dist/rules/provision-declarations.js.map +1 -0
  57. package/dist/rules/provision-exists.d.ts +6 -0
  58. package/dist/rules/provision-exists.d.ts.map +1 -0
  59. package/dist/rules/provision-exists.js +89 -0
  60. package/dist/rules/provision-exists.js.map +1 -0
  61. package/dist/rules/service-declarations.d.ts +7 -5
  62. package/dist/rules/service-declarations.d.ts.map +1 -1
  63. package/dist/rules/service-declarations.js +106 -103
  64. package/dist/rules/service-declarations.js.map +1 -1
  65. package/dist/rules/service-exists.d.ts +3 -1
  66. package/dist/rules/service-exists.d.ts.map +1 -1
  67. package/dist/rules/service-exists.js +35 -33
  68. package/dist/rules/service-exists.js.map +1 -1
  69. package/dist/rules/specs.d.ts +1 -1
  70. package/dist/rules/specs.d.ts.map +1 -1
  71. package/dist/rules/specs.js +1 -1
  72. package/dist/rules/specs.js.map +1 -1
  73. package/dist/rules/types.d.ts +2 -2
  74. package/dist/rules/types.d.ts.map +1 -1
  75. package/dist/trails/context-no-surface-types.trail.js +1 -1
  76. package/dist/trails/context-no-trailhead-types.trail.d.ts +13 -0
  77. package/dist/trails/context-no-trailhead-types.trail.d.ts.map +1 -0
  78. package/dist/trails/context-no-trailhead-types.trail.js +21 -0
  79. package/dist/trails/context-no-trailhead-types.trail.js.map +1 -0
  80. package/dist/trails/cross-declarations.trail.d.ts +13 -0
  81. package/dist/trails/cross-declarations.trail.d.ts.map +1 -0
  82. package/dist/trails/cross-declarations.trail.js +22 -0
  83. package/dist/trails/cross-declarations.trail.js.map +1 -0
  84. package/dist/trails/follow-declarations.trail.js +1 -1
  85. package/dist/trails/implementation-returns-result.trail.js +1 -1
  86. package/dist/trails/index.d.ts +4 -4
  87. package/dist/trails/index.d.ts.map +1 -1
  88. package/dist/trails/index.js +4 -4
  89. package/dist/trails/index.js.map +1 -1
  90. package/dist/trails/no-direct-impl-in-route.trail.js +4 -4
  91. package/dist/trails/no-direct-impl-in-route.trail.js.map +1 -1
  92. package/dist/trails/no-direct-implementation-call.trail.js +2 -2
  93. package/dist/trails/no-direct-implementation-call.trail.js.map +1 -1
  94. package/dist/trails/no-sync-result-assumption.trail.js +2 -2
  95. package/dist/trails/no-sync-result-assumption.trail.js.map +1 -1
  96. package/dist/trails/no-throw-in-detour-target.trail.d.ts +1 -1
  97. package/dist/trails/no-throw-in-detour-target.trail.js +1 -1
  98. package/dist/trails/no-throw-in-implementation.trail.js +1 -1
  99. package/dist/trails/prefer-schema-inference.trail.js +1 -1
  100. package/dist/trails/provision-declarations.trail.d.ts +13 -0
  101. package/dist/trails/provision-declarations.trail.d.ts.map +1 -0
  102. package/dist/trails/provision-declarations.trail.js +25 -0
  103. package/dist/trails/provision-declarations.trail.js.map +1 -0
  104. package/dist/trails/provision-exists.trail.d.ts +15 -0
  105. package/dist/trails/provision-exists.trail.d.ts.map +1 -0
  106. package/dist/trails/provision-exists.trail.js +27 -0
  107. package/dist/trails/provision-exists.trail.js.map +1 -0
  108. package/dist/trails/run.d.ts +2 -2
  109. package/dist/trails/run.d.ts.map +1 -1
  110. package/dist/trails/run.js +6 -6
  111. package/dist/trails/run.js.map +1 -1
  112. package/dist/trails/schema.d.ts +1 -1
  113. package/dist/trails/schema.js +2 -2
  114. package/dist/trails/schema.js.map +1 -1
  115. package/dist/trails/service-declarations.trail.d.ts +13 -0
  116. package/dist/trails/service-declarations.trail.d.ts.map +1 -1
  117. package/dist/trails/service-declarations.trail.js +9 -7
  118. package/dist/trails/service-declarations.trail.js.map +1 -1
  119. package/dist/trails/service-exists.trail.d.ts +17 -0
  120. package/dist/trails/service-exists.trail.d.ts.map +1 -1
  121. package/dist/trails/service-exists.trail.js +10 -8
  122. package/dist/trails/service-exists.trail.js.map +1 -1
  123. package/dist/trails/valid-describe-refs.trail.d.ts +1 -1
  124. package/dist/trails/valid-detour-refs.trail.d.ts +1 -1
  125. package/dist/trails/valid-detour-refs.trail.js +2 -2
  126. package/dist/trails/wrap-rule.js +14 -14
  127. package/dist/trails/wrap-rule.js.map +1 -1
  128. package/package.json +1 -1
  129. package/src/__tests__/cli.test.ts +8 -8
  130. package/src/__tests__/{follow-declarations.test.ts → cross-declarations.test.ts} +78 -78
  131. package/src/__tests__/drift.test.ts +5 -5
  132. package/src/__tests__/formatters.test.ts +2 -2
  133. package/src/__tests__/implementation-returns-result.test.ts +11 -11
  134. package/src/__tests__/no-direct-implementation-call.test.ts +10 -10
  135. package/src/__tests__/no-sync-result-assumption.test.ts +6 -6
  136. package/src/__tests__/no-throw-in-detour-target.test.ts +6 -6
  137. package/src/__tests__/prefer-schema-inference.test.ts +4 -4
  138. package/src/__tests__/provision-declarations.test.ts +318 -0
  139. package/src/__tests__/provision-exists.test.ts +122 -0
  140. package/src/__tests__/rules.test.ts +38 -38
  141. package/src/__tests__/valid-describe-refs.test.ts +4 -4
  142. package/src/__tests__/wrap-rule.test.ts +4 -4
  143. package/src/cli.ts +17 -13
  144. package/src/drift.ts +12 -12
  145. package/src/formatters.ts +2 -2
  146. package/src/index.ts +8 -8
  147. package/src/rules/ast.ts +36 -31
  148. package/src/rules/{context-no-surface-types.ts → context-no-trailhead-types.ts} +8 -8
  149. package/src/rules/{follow-declarations.ts → cross-declarations.ts} +63 -56
  150. package/src/rules/implementation-returns-result.ts +6 -6
  151. package/src/rules/index.ts +12 -12
  152. package/src/rules/no-direct-impl-in-route.ts +17 -17
  153. package/src/rules/no-direct-implementation-call.ts +7 -7
  154. package/src/rules/no-sync-result-assumption.ts +5 -5
  155. package/src/rules/no-throw-in-detour-target.ts +2 -2
  156. package/src/rules/no-throw-in-implementation.ts +3 -3
  157. package/src/rules/{service-declarations.ts → provision-declarations.ts} +145 -129
  158. package/src/rules/{service-exists.ts → provision-exists.ts} +51 -46
  159. package/src/rules/specs.ts +4 -4
  160. package/src/rules/types.ts +2 -2
  161. package/src/trails/{context-no-surface-types.trail.ts → context-no-trailhead-types.trail.ts} +5 -5
  162. package/src/trails/cross-declarations.trail.ts +22 -0
  163. package/src/trails/implementation-returns-result.trail.ts +1 -1
  164. package/src/trails/index.ts +4 -4
  165. package/src/trails/no-direct-impl-in-route.trail.ts +4 -4
  166. package/src/trails/no-direct-implementation-call.trail.ts +2 -2
  167. package/src/trails/no-sync-result-assumption.trail.ts +2 -2
  168. package/src/trails/no-throw-in-detour-target.trail.ts +1 -1
  169. package/src/trails/no-throw-in-implementation.trail.ts +1 -1
  170. package/src/trails/prefer-schema-inference.trail.ts +1 -1
  171. package/src/trails/provision-declarations.trail.ts +25 -0
  172. package/src/trails/provision-exists.trail.ts +27 -0
  173. package/src/trails/run.ts +7 -7
  174. package/src/trails/schema.ts +2 -2
  175. package/src/trails/valid-detour-refs.trail.ts +2 -2
  176. package/src/trails/wrap-rule.ts +17 -17
  177. package/tsconfig.tsbuildinfo +1 -1
  178. package/src/__tests__/service-declarations.test.ts +0 -318
  179. package/src/__tests__/service-exists.test.ts +0 -122
  180. package/src/trails/follow-declarations.trail.ts +0 -22
  181. package/src/trails/service-declarations.trail.ts +0 -25
  182. package/src/trails/service-exists.trail.ts +0 -27
@@ -1,14 +1,14 @@
1
1
  /**
2
- * Validates that `ctx.follow()` calls match the declared `follow` array.
2
+ * Validates that `ctx.cross()` calls match the declared `crosses` array.
3
3
  *
4
- * Statically analyzes trail run functions to find `ctx.follow('trailId', ...)`
5
- * calls and compares them against the `follow: [...]` declaration in the trail
6
- * config. Reports errors for undeclared follows and warnings for unused ones.
4
+ * Statically analyzes trail `blaze` functions to find `ctx.cross('trailId', ...)`
5
+ * calls and compares them against the `crosses: [...]` declaration in the trail
6
+ * config. Reports errors for undeclared crossings and warnings for unused ones.
7
7
  */
8
8
 
9
9
  import {
10
10
  findConfigProperty,
11
- findRunBodies,
11
+ findBlazeBodies,
12
12
  findTrailDefinitions,
13
13
  offsetToLine,
14
14
  parse,
@@ -87,18 +87,34 @@ const resolveIdentifierElement = (
87
87
  return resolveConstString(name, sourceCode);
88
88
  };
89
89
 
90
+ /** Resolve an array element to a static trail ID when possible. */
91
+ const resolveCrossElementId = (
92
+ element: AstNode,
93
+ sourceCode: string
94
+ ): string | null => {
95
+ if (isStringLiteral(element)) {
96
+ return getStringValue(element);
97
+ }
98
+
99
+ if (element.type === 'Identifier') {
100
+ return resolveIdentifierElement(element, sourceCode);
101
+ }
102
+
103
+ return null;
104
+ };
105
+
90
106
  // ---------------------------------------------------------------------------
91
- // Declared follow extraction
107
+ // Declared crossing extraction
92
108
  // ---------------------------------------------------------------------------
93
109
 
94
- /** Extract the ArrayExpression elements from a config's `follow` property. */
95
- const getFollowElements = (config: AstNode): readonly AstNode[] | null => {
96
- const followProp = findConfigProperty(config, 'follow');
97
- if (!followProp) {
110
+ /** Extract the ArrayExpression elements from a config's `crosses` property. */
111
+ const getCrossElements = (config: AstNode): readonly AstNode[] | null => {
112
+ const crossesProp = findConfigProperty(config, 'crosses');
113
+ if (!crossesProp) {
98
114
  return null;
99
115
  }
100
116
 
101
- const arrayNode = followProp.value;
117
+ const arrayNode = crossesProp.value;
102
118
  if (!arrayNode || (arrayNode as AstNode).type !== 'ArrayExpression') {
103
119
  return null;
104
120
  }
@@ -115,33 +131,26 @@ const collectStringIds = (
115
131
  sourceCode: string
116
132
  ): Set<string> => {
117
133
  const ids = new Set<string>();
118
- for (const el of elements) {
119
- if (isStringLiteral(el)) {
120
- const val = getStringValue(el);
121
- if (val) {
122
- ids.add(val);
123
- }
124
- } else if (el.type === 'Identifier') {
125
- const resolved = resolveIdentifierElement(el, sourceCode);
126
- if (resolved) {
127
- ids.add(resolved);
128
- }
134
+ for (const element of elements) {
135
+ const resolved = resolveCrossElementId(element, sourceCode);
136
+ if (resolved) {
137
+ ids.add(resolved);
129
138
  }
130
139
  }
131
140
  return ids;
132
141
  };
133
142
 
134
- /** Extract string literal elements from a `follow: [...]` array property. */
135
- const extractDeclaredFollows = (
143
+ /** Extract string literal elements from a `crosses: [...]` array property. */
144
+ const extractDeclaredCrosses = (
136
145
  config: AstNode,
137
146
  sourceCode: string
138
147
  ): ReadonlySet<string> => {
139
- const elements = getFollowElements(config);
148
+ const elements = getCrossElements(config);
140
149
  return elements ? collectStringIds(elements, sourceCode) : new Set();
141
150
  };
142
151
 
143
152
  // ---------------------------------------------------------------------------
144
- // Called follow extraction — member expression helpers
153
+ // Called crossing extraction — member expression helpers
145
154
  // ---------------------------------------------------------------------------
146
155
 
147
156
  const MEMBER_TYPES = new Set(['StaticMemberExpression', 'MemberExpression']);
@@ -173,7 +182,6 @@ const extractFirstStringArg = (node: AstNode): string | null => {
173
182
 
174
183
  const [firstArg] = args;
175
184
  if (!firstArg || !isStringLiteral(firstArg)) {
176
- // Dynamic ID — cannot resolve statically
177
185
  return null;
178
186
  }
179
187
 
@@ -181,34 +189,34 @@ const extractFirstStringArg = (node: AstNode): string | null => {
181
189
  };
182
190
 
183
191
  /**
184
- * Extract the second parameter name from a run function node.
192
+ * Extract the second parameter name from a blaze function node.
185
193
  *
186
- * Handles `(input, ctx) => ...` and `async (input, context) => ...` and
194
+ * Handles `(input, ctx) => ...`, `async (input, context) => ...`, and
187
195
  * `function(input, ctx) { ... }` forms.
188
196
  */
189
- const extractContextParamName = (runBody: AstNode): string | null => {
190
- const params = runBody['params'] as readonly AstNode[] | undefined;
197
+ const extractContextParamName = (blazeBody: AstNode): string | null => {
198
+ const params = blazeBody['params'] as readonly AstNode[] | undefined;
191
199
  if (!params || params.length < 2) {
192
200
  return null;
193
201
  }
194
202
  return identifierName(params[1]);
195
203
  };
196
204
 
197
- /** Check if a callee is a member-style follow call: <ctxName>.follow(...). */
198
- const isMemberFollowCall = (
205
+ /** Check if a callee is a member-style cross call: <ctxName>.cross(...). */
206
+ const isMemberCrossCall = (
199
207
  callee: AstNode,
200
208
  ctxNames: ReadonlySet<string>
201
209
  ): boolean => {
202
210
  const pair = extractMemberPair(callee);
203
- return !!pair && ctxNames.has(pair.objName) && pair.propName === 'follow';
211
+ return !!pair && ctxNames.has(pair.objName) && pair.propName === 'cross';
204
212
  };
205
213
 
206
214
  /**
207
- * Check if a node is a `<ctxName>.follow(...)` call and return the string trail ID.
215
+ * Check if a node is a `<ctxName>.cross(...)` call and return the string trail ID.
208
216
  *
209
- * Also matches bare `follow(...)` calls (destructured pattern).
217
+ * Also matches bare `cross(...)` calls from destructuring.
210
218
  */
211
- const extractFollowCallId = (
219
+ const extractCrossCallId = (
212
220
  node: AstNode,
213
221
  ctxNames: ReadonlySet<string>
214
222
  ): string | null => {
@@ -221,12 +229,11 @@ const extractFollowCallId = (
221
229
  return null;
222
230
  }
223
231
 
224
- if (isMemberFollowCall(callee, ctxNames)) {
232
+ if (isMemberCrossCall(callee, ctxNames)) {
225
233
  return extractFirstStringArg(node);
226
234
  }
227
235
 
228
- // Match bare follow(...) destructured pattern
229
- if (identifierName(callee) === 'follow') {
236
+ if (identifierName(callee) === 'cross') {
230
237
  return extractFirstStringArg(node);
231
238
  }
232
239
 
@@ -243,15 +250,15 @@ const buildCtxNames = (body: AstNode): ReadonlySet<string> => {
243
250
  return ctxNames;
244
251
  };
245
252
 
246
- /** Walk run bodies and collect all statically resolvable ctx.follow() trail IDs. */
247
- const extractCalledFollows = (config: AstNode): ReadonlySet<string> => {
253
+ /** Walk blaze bodies and collect all statically resolvable ctx.cross() trail IDs. */
254
+ const extractCalledCrosses = (config: AstNode): ReadonlySet<string> => {
248
255
  const ids = new Set<string>();
249
256
 
250
- for (const body of findRunBodies(config)) {
257
+ for (const body of findBlazeBodies(config)) {
251
258
  const ctxNames = buildCtxNames(body);
252
259
 
253
260
  walk(body, (node) => {
254
- const id = extractFollowCallId(node, ctxNames);
261
+ const id = extractCrossCallId(node, ctxNames);
255
262
  if (id) {
256
263
  ids.add(id);
257
264
  }
@@ -267,27 +274,27 @@ const extractCalledFollows = (config: AstNode): ReadonlySet<string> => {
267
274
 
268
275
  const buildUndeclaredDiagnostic = (
269
276
  trailId: string,
270
- followId: string,
277
+ crossedId: string,
271
278
  filePath: string,
272
279
  line: number
273
280
  ): WardenDiagnostic => ({
274
281
  filePath,
275
282
  line,
276
- message: `Trail "${trailId}": ctx.follow('${followId}') called but '${followId}' is not declared in follow`,
277
- rule: 'follow-declarations',
283
+ message: `Trail "${trailId}": ctx.cross('${crossedId}') called but '${crossedId}' is not declared in crosses`,
284
+ rule: 'cross-declarations',
278
285
  severity: 'error',
279
286
  });
280
287
 
281
288
  const buildUnusedDiagnostic = (
282
289
  trailId: string,
283
- followId: string,
290
+ crossedId: string,
284
291
  filePath: string,
285
292
  line: number
286
293
  ): WardenDiagnostic => ({
287
294
  filePath,
288
295
  line,
289
- message: `Trail "${trailId}": '${followId}' declared in follow but ctx.follow('${followId}') never called`,
290
- rule: 'follow-declarations',
296
+ message: `Trail "${trailId}": '${crossedId}' declared in crosses but ctx.cross('${crossedId}') never called`,
297
+ rule: 'cross-declarations',
291
298
  severity: 'warn',
292
299
  });
293
300
 
@@ -333,8 +340,8 @@ const checkTrailDefinition = (
333
340
  sourceCode: string,
334
341
  diagnostics: WardenDiagnostic[]
335
342
  ): void => {
336
- const declared = extractDeclaredFollows(def.config, sourceCode);
337
- const called = extractCalledFollows(def.config);
343
+ const declared = extractDeclaredCrosses(def.config, sourceCode);
344
+ const called = extractCalledCrosses(def.config);
338
345
 
339
346
  if (declared.size === 0 && called.size === 0) {
340
347
  return;
@@ -352,9 +359,9 @@ const checkTrailDefinition = (
352
359
  // ---------------------------------------------------------------------------
353
360
 
354
361
  /**
355
- * Validates that `ctx.follow()` calls align with declared `follow` arrays.
362
+ * Validates that `ctx.cross()` calls align with declared `crosses` arrays.
356
363
  */
357
- export const followDeclarations: WardenRule = {
364
+ export const crossDeclarations: WardenRule = {
358
365
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
359
366
  if (isTestFile(filePath)) {
360
367
  return [];
@@ -374,7 +381,7 @@ export const followDeclarations: WardenRule = {
374
381
  return diagnostics;
375
382
  },
376
383
  description:
377
- 'Ensure ctx.follow() calls match the declared follow array in trail definitions.',
378
- name: 'follow-declarations',
384
+ 'Ensure ctx.cross() calls match the declared crosses array in trail definitions.',
385
+ name: 'cross-declarations',
379
386
  severity: 'error',
380
387
  };
@@ -1,13 +1,13 @@
1
1
  /**
2
2
  * Finds implementations that return raw values instead of `Result`.
3
3
  *
4
- * Uses AST parsing to find `run:` bodies and check that
5
- * every return statement returns Result.ok(), Result.err(), ctx.follow(),
4
+ * Uses AST parsing to find `blaze:` bodies and check that
5
+ * every return statement returns Result.ok(), Result.err(), ctx.cross(),
6
6
  * or a tracked Result-typed variable.
7
7
  */
8
8
 
9
9
  import {
10
- findRunBodies,
10
+ findBlazeBodies,
11
11
  findTrailDefinitions,
12
12
  offsetToLine,
13
13
  parse,
@@ -60,10 +60,10 @@ const isResultMemberCall = (callee: AstNode): boolean => {
60
60
  if (objName === 'Result' && (propName === 'ok' || propName === 'err')) {
61
61
  return true;
62
62
  }
63
- if (objName === 'ctx' && propName === 'follow') {
63
+ if (objName === 'ctx' && propName === 'cross') {
64
64
  return true;
65
65
  }
66
- return propName === 'run';
66
+ return propName === 'blaze';
67
67
  };
68
68
 
69
69
  // ---------------------------------------------------------------------------
@@ -362,7 +362,7 @@ const checkAllDefinitions = (
362
362
 
363
363
  for (const def of findTrailDefinitions(ast)) {
364
364
  const info = { id: def.id, label: 'Trail' };
365
- for (const implValue of findRunBodies(def.config as AstNode)) {
365
+ for (const implValue of findBlazeBodies(def.config as AstNode)) {
366
366
  checkImplementation(
367
367
  implValue,
368
368
  info,
@@ -1,5 +1,5 @@
1
- import { contextNoSurfaceTypes } from './context-no-surface-types.js';
2
- import { followDeclarations } from './follow-declarations.js';
1
+ import { contextNoTrailheadTypes } from './context-no-trailhead-types.js';
2
+ import { crossDeclarations } from './cross-declarations.js';
3
3
  import { implementationReturnsResult } from './implementation-returns-result.js';
4
4
  import { noDirectImplInRoute } from './no-direct-impl-in-route.js';
5
5
  import { noDirectImplementationCall } from './no-direct-implementation-call.js';
@@ -7,8 +7,8 @@ import { noSyncResultAssumption } from './no-sync-result-assumption.js';
7
7
  import { noThrowInDetourTarget } from './no-throw-in-detour-target.js';
8
8
  import { noThrowInImplementation } from './no-throw-in-implementation.js';
9
9
  import { preferSchemaInference } from './prefer-schema-inference.js';
10
- import { serviceDeclarations } from './service-declarations.js';
11
- import { serviceExists } from './service-exists.js';
10
+ import { provisionDeclarations } from './provision-declarations.js';
11
+ import { provisionExists } from './provision-exists.js';
12
12
  import type { WardenRule } from './types.js';
13
13
  import { validDescribeRefs } from './valid-describe-refs.js';
14
14
  import { validDetourRefs } from './valid-detour-refs.js';
@@ -22,8 +22,8 @@ export type {
22
22
  } from './types.js';
23
23
 
24
24
  export { noThrowInImplementation } from './no-throw-in-implementation.js';
25
- export { contextNoSurfaceTypes } from './context-no-surface-types.js';
26
- export { followDeclarations } from './follow-declarations.js';
25
+ export { contextNoTrailheadTypes } from './context-no-trailhead-types.js';
26
+ export { crossDeclarations } from './cross-declarations.js';
27
27
  export { validDetourRefs } from './valid-detour-refs.js';
28
28
  export { noDirectImplInRoute } from './no-direct-impl-in-route.js';
29
29
  export { noDirectImplementationCall } from './no-direct-implementation-call.js';
@@ -31,8 +31,8 @@ export { noSyncResultAssumption } from './no-sync-result-assumption.js';
31
31
  export { implementationReturnsResult } from './implementation-returns-result.js';
32
32
  export { noThrowInDetourTarget } from './no-throw-in-detour-target.js';
33
33
  export { preferSchemaInference } from './prefer-schema-inference.js';
34
- export { serviceDeclarations } from './service-declarations.js';
35
- export { serviceExists } from './service-exists.js';
34
+ export { provisionDeclarations } from './provision-declarations.js';
35
+ export { provisionExists } from './provision-exists.js';
36
36
  export { validDescribeRefs } from './valid-describe-refs.js';
37
37
 
38
38
  /** All built-in warden rules, keyed by rule name. */
@@ -41,10 +41,10 @@ export const wardenRules: ReadonlyMap<string, WardenRule> = new Map<
41
41
  WardenRule
42
42
  >([
43
43
  [noThrowInImplementation.name, noThrowInImplementation],
44
- [contextNoSurfaceTypes.name, contextNoSurfaceTypes],
45
- [followDeclarations.name, followDeclarations],
46
- [serviceDeclarations.name, serviceDeclarations],
47
- [serviceExists.name, serviceExists],
44
+ [contextNoTrailheadTypes.name, contextNoTrailheadTypes],
45
+ [crossDeclarations.name, crossDeclarations],
46
+ [provisionDeclarations.name, provisionDeclarations],
47
+ [provisionExists.name, provisionExists],
48
48
  [preferSchemaInference.name, preferSchemaInference],
49
49
  [validDescribeRefs.name, validDescribeRefs],
50
50
  [validDetourRefs.name, validDetourRefs],
@@ -1,15 +1,15 @@
1
1
  /**
2
- * Detects trail implementations with `follow` that call `.run()` directly.
2
+ * Detects trail implementations with `crosses` that call `.blaze()` directly.
3
3
  *
4
- * Uses AST parsing to find trail definitions that declare `follow` and check for
5
- * `.run()` call expressions in their bodies.
4
+ * Uses AST parsing to find trail definitions that declare `crosses` and check for
5
+ * `.blaze()` call expressions in their bodies.
6
6
  */
7
7
 
8
8
  import {
9
9
  findConfigProperty,
10
- findRunBodies,
10
+ findBlazeBodies,
11
11
  findTrailDefinitions,
12
- isRunCall,
12
+ isBlazeCall,
13
13
  offsetToLine,
14
14
  parse,
15
15
  walk,
@@ -23,20 +23,20 @@ interface AstNode {
23
23
  readonly [key: string]: unknown;
24
24
  }
25
25
 
26
- const findImplCallsInTrailWithFollow = (
26
+ const findImplCallsInTrailWithCrosses = (
27
27
  def: { readonly config: AstNode },
28
28
  filePath: string,
29
29
  sourceCode: string,
30
30
  diagnostics: WardenDiagnostic[]
31
31
  ): void => {
32
- for (const body of findRunBodies(def.config as AstNode)) {
32
+ for (const body of findBlazeBodies(def.config as AstNode)) {
33
33
  walk(body, (node) => {
34
- if (isRunCall(node as AstNode)) {
34
+ if (isBlazeCall(node as AstNode)) {
35
35
  diagnostics.push({
36
36
  filePath,
37
37
  line: offsetToLine(sourceCode, node.start),
38
38
  message:
39
- 'Use ctx.follow("trailId", input) instead of direct .run() calls. ctx.follow() validates input and propagates tracing.',
39
+ 'Use ctx.cross("trailId", input) instead of direct .blaze() calls. ctx.cross() validates input and propagates tracing.',
40
40
  rule: 'no-direct-impl-in-route',
41
41
  severity: 'warn',
42
42
  });
@@ -45,11 +45,11 @@ const findImplCallsInTrailWithFollow = (
45
45
  }
46
46
  };
47
47
 
48
- const hasFollowProperty = (config: AstNode): boolean =>
49
- findConfigProperty(config as AstNode, 'follow') !== null;
48
+ const hasCrossesProperty = (config: AstNode): boolean =>
49
+ findConfigProperty(config as AstNode, 'crosses') !== null;
50
50
 
51
51
  /**
52
- * Detects trails with `follow` that call another trail's `.run()` directly.
52
+ * Detects trails with `crosses` that call another trail's `.blaze()` directly.
53
53
  */
54
54
  export const noDirectImplInRoute: WardenRule = {
55
55
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
@@ -63,18 +63,18 @@ export const noDirectImplInRoute: WardenRule = {
63
63
  }
64
64
 
65
65
  const diagnostics: WardenDiagnostic[] = [];
66
- const followDefs = findTrailDefinitions(ast as AstNode).filter((d) =>
67
- hasFollowProperty(d.config as AstNode)
66
+ const crossDefs = findTrailDefinitions(ast as AstNode).filter((d) =>
67
+ hasCrossesProperty(d.config as AstNode)
68
68
  );
69
69
 
70
- for (const def of followDefs) {
71
- findImplCallsInTrailWithFollow(def, filePath, sourceCode, diagnostics);
70
+ for (const def of crossDefs) {
71
+ findImplCallsInTrailWithCrosses(def, filePath, sourceCode, diagnostics);
72
72
  }
73
73
 
74
74
  return diagnostics;
75
75
  },
76
76
  description:
77
- 'Prefer ctx.follow() over direct .run() calls in trail bodies with follow.',
77
+ 'Prefer ctx.cross() over direct .blaze() calls in trail bodies with crossings.',
78
78
  name: 'no-direct-impl-in-route',
79
79
 
80
80
  severity: 'warn',
@@ -1,16 +1,16 @@
1
1
  /**
2
- * Flags direct `.run()` calls in application code.
2
+ * Flags direct `.blaze()` calls in application code.
3
3
  *
4
- * Uses AST parsing to find `.run()` call expressions,
4
+ * Uses AST parsing to find `.blaze()` call expressions,
5
5
  * ignoring occurrences in strings and comments.
6
6
  */
7
7
 
8
- import { isRunCall, offsetToLine, parse, walk } from './ast.js';
8
+ import { isBlazeCall, offsetToLine, parse, walk } from './ast.js';
9
9
  import { isFrameworkInternalFile, isTestFile } from './scan.js';
10
10
  import type { WardenDiagnostic, WardenRule } from './types.js';
11
11
 
12
12
  /**
13
- * Flags direct `.run()` calls in application code.
13
+ * Flags direct `.blaze()` calls in application code.
14
14
  */
15
15
  export const noDirectImplementationCall: WardenRule = {
16
16
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
@@ -26,12 +26,12 @@ export const noDirectImplementationCall: WardenRule = {
26
26
  const diagnostics: WardenDiagnostic[] = [];
27
27
 
28
28
  walk(ast, (node) => {
29
- if (isRunCall(node)) {
29
+ if (isBlazeCall(node)) {
30
30
  diagnostics.push({
31
31
  filePath,
32
32
  line: offsetToLine(sourceCode, node.start),
33
33
  message:
34
- 'Use ctx.follow("trailId", input) instead of direct .run() calls. Direct implementation access bypasses validation, tracing, and layers.',
34
+ 'Use ctx.cross("trailId", input) instead of direct .blaze() calls. Direct implementation access bypasses validation, tracing, and gates.',
35
35
  rule: 'no-direct-implementation-call',
36
36
  severity: 'warn',
37
37
  });
@@ -41,7 +41,7 @@ export const noDirectImplementationCall: WardenRule = {
41
41
  return diagnostics;
42
42
  },
43
43
  description:
44
- 'Disallow direct .run() calls in application code. Use ctx.follow() instead.',
44
+ 'Disallow direct .blaze() calls in application code. Use ctx.cross() instead.',
45
45
  name: 'no-direct-implementation-call',
46
46
  severity: 'warn',
47
47
  };
@@ -7,10 +7,10 @@ import {
7
7
 
8
8
  const RESULT_ACCESS_PATTERN =
9
9
  /\.(?:isOk|isErr|match|map)\s*\(|\.(?:value|error)\b/;
10
- const IMPLEMENTATION_CALL_PATTERN = /\.run\s*\(/;
10
+ const IMPLEMENTATION_CALL_PATTERN = /\.blaze\s*\(/;
11
11
 
12
12
  const isAwaitedImplementationCall = (line: string): boolean => {
13
- const callIndex = line.indexOf('.run(');
13
+ const callIndex = line.indexOf('.blaze(');
14
14
  if (callIndex === -1) {
15
15
  return false;
16
16
  }
@@ -39,7 +39,7 @@ interface PendingCall {
39
39
  }
40
40
 
41
41
  const MISSING_AWAIT_MESSAGE =
42
- 'Missing await: .run() returns Promise<Result> after normalization. Use `const result = await trail.run(input, ctx)`.';
42
+ 'Missing await: .blaze() returns Promise<Result> after normalization. Use `const result = await trail.blaze(input, ctx)`.';
43
43
 
44
44
  const createMissingAwaitDiagnostic = (
45
45
  filePath: string,
@@ -140,7 +140,7 @@ const scanSourceCode = (
140
140
  };
141
141
 
142
142
  /**
143
- * Flags code that assumes `.run()` returns a synchronous result.
143
+ * Flags code that assumes `.blaze()` returns a synchronous result.
144
144
  */
145
145
  export const noSyncResultAssumption: WardenRule = {
146
146
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
@@ -150,7 +150,7 @@ export const noSyncResultAssumption: WardenRule = {
150
150
  return scanSourceCode(stripQuotedContent(sourceCode), filePath);
151
151
  },
152
152
  description:
153
- 'Disallow treating .run() as synchronous after normalization. Always await the returned Promise<Result>.',
153
+ 'Disallow treating .blaze() as synchronous after normalization. Always await the returned Promise<Result>.',
154
154
  name: 'no-sync-result-assumption',
155
155
  severity: 'error',
156
156
  };
@@ -6,7 +6,7 @@
6
6
  */
7
7
 
8
8
  import {
9
- findRunBodies,
9
+ findBlazeBodies,
10
10
  findTrailDefinitions,
11
11
  offsetToLine,
12
12
  parse,
@@ -66,7 +66,7 @@ const findThrowsInTargetedTrails = (
66
66
  continue;
67
67
  }
68
68
 
69
- for (const body of findRunBodies(def.config as AstNode)) {
69
+ for (const body of findBlazeBodies(def.config as AstNode)) {
70
70
  walk(body, (node) => {
71
71
  if (node.type === 'ThrowStatement') {
72
72
  diagnostics.push({
@@ -1,11 +1,11 @@
1
1
  /**
2
- * Finds `throw` statements inside `run:` function bodies.
2
+ * Finds `throw` statements inside `blaze:` function bodies.
3
3
  *
4
4
  * Uses AST parsing for accurate detection — no false positives from
5
5
  * throw in comments, strings, or nested non-implementation functions.
6
6
  */
7
7
 
8
- import { findRunBodies, offsetToLine, parse, walk } from './ast.js';
8
+ import { findBlazeBodies, offsetToLine, parse, walk } from './ast.js';
9
9
  import type { WardenDiagnostic, WardenRule } from './types.js';
10
10
 
11
11
  export const noThrowInImplementation: WardenRule = {
@@ -17,7 +17,7 @@ export const noThrowInImplementation: WardenRule = {
17
17
 
18
18
  const diagnostics: WardenDiagnostic[] = [];
19
19
 
20
- for (const body of findRunBodies(ast)) {
20
+ for (const body of findBlazeBodies(ast)) {
21
21
  walk(body, (node) => {
22
22
  if (node.type === 'ThrowStatement') {
23
23
  diagnostics.push({