@ontrails/warden 1.0.0-beta.11 → 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 (183) hide show
  1. package/.turbo/turbo-lint.log +1 -1
  2. package/CHANGELOG.md +59 -31
  3. package/README.md +17 -17
  4. package/dist/cli.d.ts +1 -1
  5. package/dist/cli.d.ts.map +1 -1
  6. package/dist/cli.js +14 -10
  7. package/dist/cli.js.map +1 -1
  8. package/dist/drift.d.ts +6 -6
  9. package/dist/drift.d.ts.map +1 -1
  10. package/dist/drift.js +8 -8
  11. package/dist/drift.js.map +1 -1
  12. package/dist/formatters.js +2 -2
  13. package/dist/formatters.js.map +1 -1
  14. package/dist/index.d.ts +4 -4
  15. package/dist/index.d.ts.map +1 -1
  16. package/dist/index.js +5 -5
  17. package/dist/index.js.map +1 -1
  18. package/dist/rules/ast.d.ts +15 -11
  19. package/dist/rules/ast.d.ts.map +1 -1
  20. package/dist/rules/ast.js +34 -30
  21. package/dist/rules/ast.js.map +1 -1
  22. package/dist/rules/context-no-trailhead-types.d.ts +12 -0
  23. package/dist/rules/context-no-trailhead-types.d.ts.map +1 -0
  24. package/dist/rules/context-no-trailhead-types.js +96 -0
  25. package/dist/rules/context-no-trailhead-types.js.map +1 -0
  26. package/dist/rules/cross-declarations.d.ts +13 -0
  27. package/dist/rules/cross-declarations.d.ts.map +1 -0
  28. package/dist/rules/cross-declarations.js +264 -0
  29. package/dist/rules/cross-declarations.js.map +1 -0
  30. package/dist/rules/follow-declarations.d.ts +1 -1
  31. package/dist/rules/follow-declarations.js +5 -5
  32. package/dist/rules/follow-declarations.js.map +1 -1
  33. package/dist/rules/implementation-returns-result.d.ts +2 -2
  34. package/dist/rules/implementation-returns-result.js +6 -6
  35. package/dist/rules/implementation-returns-result.js.map +1 -1
  36. package/dist/rules/index.d.ts +4 -4
  37. package/dist/rules/index.d.ts.map +1 -1
  38. package/dist/rules/index.js +12 -12
  39. package/dist/rules/index.js.map +1 -1
  40. package/dist/rules/no-direct-impl-in-route.d.ts +4 -4
  41. package/dist/rules/no-direct-impl-in-route.js +14 -14
  42. package/dist/rules/no-direct-impl-in-route.js.map +1 -1
  43. package/dist/rules/no-direct-implementation-call.d.ts +3 -3
  44. package/dist/rules/no-direct-implementation-call.js +7 -7
  45. package/dist/rules/no-direct-implementation-call.js.map +1 -1
  46. package/dist/rules/no-sync-result-assumption.d.ts +1 -1
  47. package/dist/rules/no-sync-result-assumption.js +5 -5
  48. package/dist/rules/no-sync-result-assumption.js.map +1 -1
  49. package/dist/rules/no-throw-in-detour-target.js +2 -2
  50. package/dist/rules/no-throw-in-detour-target.js.map +1 -1
  51. package/dist/rules/no-throw-in-implementation.d.ts +1 -1
  52. package/dist/rules/no-throw-in-implementation.js +3 -3
  53. package/dist/rules/no-throw-in-implementation.js.map +1 -1
  54. package/dist/rules/provision-declarations.d.ts +14 -0
  55. package/dist/rules/provision-declarations.d.ts.map +1 -0
  56. package/dist/rules/provision-declarations.js +344 -0
  57. package/dist/rules/provision-declarations.js.map +1 -0
  58. package/dist/rules/provision-exists.d.ts +6 -0
  59. package/dist/rules/provision-exists.d.ts.map +1 -0
  60. package/dist/rules/provision-exists.js +89 -0
  61. package/dist/rules/provision-exists.js.map +1 -0
  62. package/dist/rules/service-declarations.d.ts +7 -5
  63. package/dist/rules/service-declarations.d.ts.map +1 -1
  64. package/dist/rules/service-declarations.js +106 -103
  65. package/dist/rules/service-declarations.js.map +1 -1
  66. package/dist/rules/service-exists.d.ts +3 -1
  67. package/dist/rules/service-exists.d.ts.map +1 -1
  68. package/dist/rules/service-exists.js +35 -33
  69. package/dist/rules/service-exists.js.map +1 -1
  70. package/dist/rules/specs.d.ts +1 -1
  71. package/dist/rules/specs.d.ts.map +1 -1
  72. package/dist/rules/specs.js +1 -1
  73. package/dist/rules/specs.js.map +1 -1
  74. package/dist/rules/types.d.ts +2 -2
  75. package/dist/rules/types.d.ts.map +1 -1
  76. package/dist/trails/context-no-surface-types.trail.js +1 -1
  77. package/dist/trails/context-no-trailhead-types.trail.d.ts +13 -0
  78. package/dist/trails/context-no-trailhead-types.trail.d.ts.map +1 -0
  79. package/dist/trails/context-no-trailhead-types.trail.js +21 -0
  80. package/dist/trails/context-no-trailhead-types.trail.js.map +1 -0
  81. package/dist/trails/cross-declarations.trail.d.ts +13 -0
  82. package/dist/trails/cross-declarations.trail.d.ts.map +1 -0
  83. package/dist/trails/cross-declarations.trail.js +22 -0
  84. package/dist/trails/cross-declarations.trail.js.map +1 -0
  85. package/dist/trails/follow-declarations.trail.js +1 -1
  86. package/dist/trails/implementation-returns-result.trail.js +1 -1
  87. package/dist/trails/index.d.ts +4 -4
  88. package/dist/trails/index.d.ts.map +1 -1
  89. package/dist/trails/index.js +4 -4
  90. package/dist/trails/index.js.map +1 -1
  91. package/dist/trails/no-direct-impl-in-route.trail.js +4 -4
  92. package/dist/trails/no-direct-impl-in-route.trail.js.map +1 -1
  93. package/dist/trails/no-direct-implementation-call.trail.js +2 -2
  94. package/dist/trails/no-direct-implementation-call.trail.js.map +1 -1
  95. package/dist/trails/no-sync-result-assumption.trail.js +2 -2
  96. package/dist/trails/no-sync-result-assumption.trail.js.map +1 -1
  97. package/dist/trails/no-throw-in-detour-target.trail.d.ts +1 -1
  98. package/dist/trails/no-throw-in-detour-target.trail.js +1 -1
  99. package/dist/trails/no-throw-in-implementation.trail.js +1 -1
  100. package/dist/trails/prefer-schema-inference.trail.js +1 -1
  101. package/dist/trails/provision-declarations.trail.d.ts +13 -0
  102. package/dist/trails/provision-declarations.trail.d.ts.map +1 -0
  103. package/dist/trails/provision-declarations.trail.js +25 -0
  104. package/dist/trails/provision-declarations.trail.js.map +1 -0
  105. package/dist/trails/provision-exists.trail.d.ts +15 -0
  106. package/dist/trails/provision-exists.trail.d.ts.map +1 -0
  107. package/dist/trails/provision-exists.trail.js +27 -0
  108. package/dist/trails/provision-exists.trail.js.map +1 -0
  109. package/dist/trails/run.d.ts +2 -2
  110. package/dist/trails/run.d.ts.map +1 -1
  111. package/dist/trails/run.js +6 -6
  112. package/dist/trails/run.js.map +1 -1
  113. package/dist/trails/schema.d.ts +1 -1
  114. package/dist/trails/schema.js +2 -2
  115. package/dist/trails/schema.js.map +1 -1
  116. package/dist/trails/service-declarations.trail.d.ts +13 -0
  117. package/dist/trails/service-declarations.trail.d.ts.map +1 -1
  118. package/dist/trails/service-declarations.trail.js +9 -7
  119. package/dist/trails/service-declarations.trail.js.map +1 -1
  120. package/dist/trails/service-exists.trail.d.ts +17 -0
  121. package/dist/trails/service-exists.trail.d.ts.map +1 -1
  122. package/dist/trails/service-exists.trail.js +10 -8
  123. package/dist/trails/service-exists.trail.js.map +1 -1
  124. package/dist/trails/valid-describe-refs.trail.d.ts +1 -1
  125. package/dist/trails/valid-detour-refs.trail.d.ts +1 -1
  126. package/dist/trails/valid-detour-refs.trail.js +2 -2
  127. package/dist/trails/wrap-rule.js +14 -14
  128. package/dist/trails/wrap-rule.js.map +1 -1
  129. package/package.json +4 -4
  130. package/src/__tests__/cli.test.ts +8 -8
  131. package/src/__tests__/{follow-declarations.test.ts → cross-declarations.test.ts} +78 -78
  132. package/src/__tests__/drift.test.ts +5 -5
  133. package/src/__tests__/formatters.test.ts +2 -2
  134. package/src/__tests__/implementation-returns-result.test.ts +11 -11
  135. package/src/__tests__/no-direct-implementation-call.test.ts +10 -10
  136. package/src/__tests__/no-sync-result-assumption.test.ts +6 -6
  137. package/src/__tests__/no-throw-in-detour-target.test.ts +6 -6
  138. package/src/__tests__/prefer-schema-inference.test.ts +4 -4
  139. package/src/__tests__/provision-declarations.test.ts +318 -0
  140. package/src/__tests__/provision-exists.test.ts +122 -0
  141. package/src/__tests__/rules.test.ts +38 -38
  142. package/src/__tests__/valid-describe-refs.test.ts +4 -4
  143. package/src/__tests__/wrap-rule.test.ts +4 -4
  144. package/src/cli.ts +17 -13
  145. package/src/drift.ts +12 -12
  146. package/src/formatters.ts +2 -2
  147. package/src/index.ts +8 -8
  148. package/src/rules/ast.ts +36 -31
  149. package/src/rules/{context-no-surface-types.ts → context-no-trailhead-types.ts} +8 -8
  150. package/src/rules/{follow-declarations.ts → cross-declarations.ts} +63 -56
  151. package/src/rules/implementation-returns-result.ts +6 -6
  152. package/src/rules/index.ts +12 -12
  153. package/src/rules/no-direct-impl-in-route.ts +17 -17
  154. package/src/rules/no-direct-implementation-call.ts +7 -7
  155. package/src/rules/no-sync-result-assumption.ts +5 -5
  156. package/src/rules/no-throw-in-detour-target.ts +2 -2
  157. package/src/rules/no-throw-in-implementation.ts +3 -3
  158. package/src/rules/{service-declarations.ts → provision-declarations.ts} +145 -129
  159. package/src/rules/{service-exists.ts → provision-exists.ts} +51 -46
  160. package/src/rules/specs.ts +4 -4
  161. package/src/rules/types.ts +2 -2
  162. package/src/trails/{context-no-surface-types.trail.ts → context-no-trailhead-types.trail.ts} +5 -5
  163. package/src/trails/cross-declarations.trail.ts +22 -0
  164. package/src/trails/implementation-returns-result.trail.ts +1 -1
  165. package/src/trails/index.ts +4 -4
  166. package/src/trails/no-direct-impl-in-route.trail.ts +4 -4
  167. package/src/trails/no-direct-implementation-call.trail.ts +2 -2
  168. package/src/trails/no-sync-result-assumption.trail.ts +2 -2
  169. package/src/trails/no-throw-in-detour-target.trail.ts +1 -1
  170. package/src/trails/no-throw-in-implementation.trail.ts +1 -1
  171. package/src/trails/prefer-schema-inference.trail.ts +1 -1
  172. package/src/trails/provision-declarations.trail.ts +25 -0
  173. package/src/trails/provision-exists.trail.ts +27 -0
  174. package/src/trails/run.ts +7 -7
  175. package/src/trails/schema.ts +2 -2
  176. package/src/trails/valid-detour-refs.trail.ts +2 -2
  177. package/src/trails/wrap-rule.ts +17 -17
  178. package/tsconfig.tsbuildinfo +1 -1
  179. package/src/__tests__/service-declarations.test.ts +0 -318
  180. package/src/__tests__/service-exists.test.ts +0 -122
  181. package/src/trails/follow-declarations.trail.ts +0 -22
  182. package/src/trails/service-declarations.trail.ts +0 -25
  183. package/src/trails/service-exists.trail.ts +0 -27
@@ -1,17 +1,17 @@
1
1
  /**
2
- * Validates that service access matches the declared `services` array.
2
+ * Validates that provision access matches the declared `provisions` array.
3
3
  *
4
- * Statically analyzes trail run functions to find `db.from(ctx)` and
5
- * `ctx.service('db.main')` calls and compares them against the declared
6
- * `services: [...]` array in the trail config. Reports errors for undeclared
4
+ * Statically analyzes trail `blaze` functions to find `db.from(ctx)` and
5
+ * `ctx.provision('db.main')` calls and compares them against the declared
6
+ * `provisions: [...]` array in the trail config. Reports errors for undeclared
7
7
  * access and warnings for unused declarations.
8
8
  */
9
9
 
10
10
  import {
11
- collectNamedServiceIds,
11
+ collectNamedProvisionIds,
12
12
  extractFirstStringArg,
13
13
  findConfigProperty,
14
- findRunBodies,
14
+ findBlazeBodies,
15
15
  findTrailDefinitions,
16
16
  getStringValue,
17
17
  identifierName,
@@ -25,15 +25,15 @@ import { isTestFile } from './scan.js';
25
25
  import type { WardenDiagnostic, WardenRule } from './types.js';
26
26
 
27
27
  // ---------------------------------------------------------------------------
28
- // Service declaration extraction
28
+ // Provision declaration extraction
29
29
  // ---------------------------------------------------------------------------
30
30
 
31
- interface DeclaredService {
31
+ interface DeclaredProvision {
32
32
  readonly id: string | null;
33
33
  readonly name: string | null;
34
34
  }
35
35
 
36
- interface CalledServices {
36
+ interface CalledProvisions {
37
37
  readonly fromNames: ReadonlySet<string>;
38
38
  readonly lookupIds: ReadonlySet<string>;
39
39
  readonly lookupNames: ReadonlySet<string>;
@@ -59,25 +59,25 @@ const extractMemberPair = (
59
59
  return objName && propName ? { objName, propName } : null;
60
60
  };
61
61
 
62
- /** Check if a node is an inline `service('id', ...)` call. */
63
- const isInlineServiceCall = (node: AstNode): boolean => {
62
+ /** Check if a node is an inline `provision('id', ...)` call. */
63
+ const isInlineProvisionCall = (node: AstNode): boolean => {
64
64
  if (node.type !== 'CallExpression') {
65
65
  return false;
66
66
  }
67
67
  return (
68
68
  identifierName((node as unknown as { callee?: AstNode }).callee) ===
69
- 'service'
69
+ 'provision'
70
70
  );
71
71
  };
72
72
 
73
- /** Get `services` array elements from a trail config. */
74
- const getServiceElements = (config: AstNode): readonly AstNode[] => {
75
- const servicesProp = findConfigProperty(config, 'services');
76
- if (!servicesProp) {
73
+ /** Get `provisions` array elements from a trail config. */
74
+ const getProvisionElements = (config: AstNode): readonly AstNode[] => {
75
+ const provisionsProp = findConfigProperty(config, 'provisions');
76
+ if (!provisionsProp) {
77
77
  return [];
78
78
  }
79
79
 
80
- const arrayNode = servicesProp.value;
80
+ const arrayNode = provisionsProp.value;
81
81
  if (!arrayNode || (arrayNode as AstNode).type !== 'ArrayExpression') {
82
82
  return [];
83
83
  }
@@ -88,15 +88,15 @@ const getServiceElements = (config: AstNode): readonly AstNode[] => {
88
88
  return elements ?? [];
89
89
  };
90
90
 
91
- /** Extract one declared service from a `services` array element. */
92
- const extractDeclaredService = (
91
+ /** Extract one declared provision from a `provisions` array element. */
92
+ const extractDeclaredProvision = (
93
93
  element: AstNode,
94
- serviceIdsByName: ReadonlyMap<string, string>
95
- ): DeclaredService | null => {
94
+ provisionIdsByName: ReadonlyMap<string, string>
95
+ ): DeclaredProvision | null => {
96
96
  if (element.type === 'Identifier') {
97
97
  const name = identifierName(element);
98
98
  return {
99
- id: name ? (serviceIdsByName.get(name) ?? null) : null,
99
+ id: name ? (provisionIdsByName.get(name) ?? null) : null,
100
100
  name,
101
101
  };
102
102
  }
@@ -105,30 +105,30 @@ const extractDeclaredService = (
105
105
  return { id: getStringValue(element), name: null };
106
106
  }
107
107
 
108
- if (isInlineServiceCall(element)) {
108
+ if (isInlineProvisionCall(element)) {
109
109
  return { id: extractFirstStringArg(element), name: null };
110
110
  }
111
111
 
112
112
  return null;
113
113
  };
114
114
 
115
- /** Extract declared services from a trail config's `services` array. */
116
- const extractDeclaredServices = (
115
+ /** Extract declared provisions from a trail config's `provisions` array. */
116
+ const extractDeclaredProvisions = (
117
117
  config: AstNode,
118
- serviceIdsByName: ReadonlyMap<string, string>
119
- ): readonly DeclaredService[] =>
120
- getServiceElements(config).flatMap((element) => {
121
- const service = extractDeclaredService(element, serviceIdsByName);
122
- return service ? [service] : [];
118
+ provisionIdsByName: ReadonlyMap<string, string>
119
+ ): readonly DeclaredProvision[] =>
120
+ getProvisionElements(config).flatMap((element) => {
121
+ const provision = extractDeclaredProvision(element, provisionIdsByName);
122
+ return provision ? [provision] : [];
123
123
  });
124
124
 
125
125
  // ---------------------------------------------------------------------------
126
126
  // Called service extraction
127
127
  // ---------------------------------------------------------------------------
128
128
 
129
- /** Extract the second parameter name from a run function node. */
130
- const extractContextParamName = (runBody: AstNode): string | null => {
131
- const params = runBody['params'] as readonly AstNode[] | undefined;
129
+ /** Extract the second parameter name from a blaze function node. */
130
+ const extractContextParamName = (blazeBody: AstNode): string | null => {
131
+ const params = blazeBody['params'] as readonly AstNode[] | undefined;
132
132
  if (!params || params.length < 2) {
133
133
  return null;
134
134
  }
@@ -189,63 +189,63 @@ const extractFromCallName = (
189
189
  : null;
190
190
  };
191
191
 
192
- /** Check if a callee is a member-style `ctx.service(...)` call. */
193
- const isMemberServiceCall = (
192
+ /** Check if a callee is a member-style `ctx.provision(...)` call. */
193
+ const isMemberProvisionCall = (
194
194
  callee: AstNode,
195
195
  ctxNames: ReadonlySet<string>
196
196
  ): boolean => {
197
197
  const pair = extractMemberPair(callee);
198
- return !!pair && ctxNames.has(pair.objName) && pair.propName === 'service';
198
+ return !!pair && ctxNames.has(pair.objName) && pair.propName === 'provision';
199
199
  };
200
200
 
201
- /** Extract `ctx.service(db)` and destructured `service(db)` lookup names. */
202
- const extractLookupServiceName = (
201
+ /** Extract `ctx.provision(db)` and destructured `provision(db)` lookup names. */
202
+ const extractLookupProvisionName = (
203
203
  node: AstNode,
204
204
  ctxNames: ReadonlySet<string>,
205
- serviceAliases: ReadonlySet<string>
205
+ provisionAliases: ReadonlySet<string>
206
206
  ): string | null => {
207
207
  const callee = extractCallCallee(node);
208
208
  if (!callee) {
209
209
  return null;
210
210
  }
211
211
 
212
- if (isMemberServiceCall(callee, ctxNames)) {
212
+ if (isMemberProvisionCall(callee, ctxNames)) {
213
213
  return extractFirstIdentifierArg(node);
214
214
  }
215
215
 
216
- if (serviceAliases.has(identifierName(callee) ?? '')) {
216
+ if (provisionAliases.has(identifierName(callee) ?? '')) {
217
217
  return extractFirstIdentifierArg(node);
218
218
  }
219
219
 
220
220
  return null;
221
221
  };
222
222
 
223
- /** Extract `ctx.service('id')` and destructured `service('id')` lookup IDs. */
224
- const extractLookupServiceId = (
223
+ /** Extract `ctx.provision('id')` and destructured `provision('id')` lookup IDs. */
224
+ const extractLookupProvisionId = (
225
225
  node: AstNode,
226
226
  ctxNames: ReadonlySet<string>,
227
- serviceAliases: ReadonlySet<string>
227
+ provisionAliases: ReadonlySet<string>
228
228
  ): string | null => {
229
229
  const callee = extractCallCallee(node);
230
230
  if (!callee) {
231
231
  return null;
232
232
  }
233
233
 
234
- if (isMemberServiceCall(callee, ctxNames)) {
234
+ if (isMemberProvisionCall(callee, ctxNames)) {
235
235
  return extractFirstStringArg(node);
236
236
  }
237
237
 
238
238
  const calleeName = identifierName(callee);
239
239
  const args = node['arguments'] as readonly AstNode[] | undefined;
240
- if (calleeName && serviceAliases.has(calleeName) && args?.length === 1) {
240
+ if (calleeName && provisionAliases.has(calleeName) && args?.length === 1) {
241
241
  return extractFirstStringArg(node);
242
242
  }
243
243
 
244
244
  return null;
245
245
  };
246
246
 
247
- /** Collect local aliases for the service accessor (e.g. `const { service } = ctx`). */
248
- const collectServiceAliases = (
247
+ /** Collect local aliases for the provision accessor (e.g. `const { provision } = ctx`). */
248
+ const collectProvisionAliases = (
249
249
  body: AstNode,
250
250
  ctxNames: ReadonlySet<string>
251
251
  ): ReadonlySet<string> => {
@@ -267,7 +267,7 @@ const collectServiceAliases = (
267
267
  const keyName = identifierName(
268
268
  (property as unknown as { key?: AstNode }).key
269
269
  );
270
- if (keyName !== 'service') {
270
+ if (keyName !== 'provision') {
271
271
  return [];
272
272
  }
273
273
 
@@ -300,15 +300,15 @@ const collectServiceAliases = (
300
300
  return aliases;
301
301
  };
302
302
 
303
- /** Walk run bodies and collect service access that can be resolved statically. */
304
- const extractCalledServices = (config: AstNode): CalledServices => {
303
+ /** Walk blaze bodies and collect provision access that can be resolved statically. */
304
+ const extractCalledProvisions = (config: AstNode): CalledProvisions => {
305
305
  const fromNames = new Set<string>();
306
306
  const lookupIds = new Set<string>();
307
307
  const lookupNames = new Set<string>();
308
308
 
309
- for (const body of findRunBodies(config)) {
309
+ for (const body of findBlazeBodies(config)) {
310
310
  const ctxNames = buildCtxNames(body);
311
- const serviceAliases = collectServiceAliases(body, ctxNames);
311
+ const provisionAliases = collectProvisionAliases(body, ctxNames);
312
312
 
313
313
  walkScope(body, (node) => {
314
314
  const fromName = extractFromCallName(node, ctxNames);
@@ -316,15 +316,19 @@ const extractCalledServices = (config: AstNode): CalledServices => {
316
316
  fromNames.add(fromName);
317
317
  }
318
318
 
319
- const lookupId = extractLookupServiceId(node, ctxNames, serviceAliases);
319
+ const lookupId = extractLookupProvisionId(
320
+ node,
321
+ ctxNames,
322
+ provisionAliases
323
+ );
320
324
  if (lookupId) {
321
325
  lookupIds.add(lookupId);
322
326
  }
323
327
 
324
- const lookupName = extractLookupServiceName(
328
+ const lookupName = extractLookupProvisionName(
325
329
  node,
326
330
  ctxNames,
327
- serviceAliases
331
+ provisionAliases
328
332
  );
329
333
  if (lookupName) {
330
334
  lookupNames.add(lookupName);
@@ -339,58 +343,58 @@ const extractCalledServices = (config: AstNode): CalledServices => {
339
343
  // Diagnostics
340
344
  // ---------------------------------------------------------------------------
341
345
 
342
- const renderDeclaredService = (service: DeclaredService): string =>
343
- service.name ?? service.id ?? '<unknown>';
346
+ const renderDeclaredProvision = (provision: DeclaredProvision): string =>
347
+ provision.name ?? provision.id ?? '<unknown>';
344
348
 
345
349
  const buildUndeclaredFromDiagnostic = (
346
350
  trailId: string,
347
- serviceName: string,
351
+ provisionName: string,
348
352
  filePath: string,
349
353
  line: number
350
354
  ): WardenDiagnostic => ({
351
355
  filePath,
352
356
  line,
353
- message: `Trail "${trailId}": ${serviceName}.from(ctx) called but '${serviceName}' is not declared in services`,
354
- rule: 'service-declarations',
357
+ message: `Trail "${trailId}": ${provisionName}.from(ctx) called but '${provisionName}' is not declared in provisions`,
358
+ rule: 'provision-declarations',
355
359
  severity: 'error',
356
360
  });
357
361
 
358
362
  const buildUndeclaredLookupDiagnostic = (
359
363
  trailId: string,
360
- serviceId: string,
364
+ provisionId: string,
361
365
  filePath: string,
362
366
  line: number
363
367
  ): WardenDiagnostic => ({
364
368
  filePath,
365
369
  line,
366
- message: `Trail "${trailId}": ctx.service('${serviceId}') called but '${serviceId}' is not declared in services`,
367
- rule: 'service-declarations',
370
+ message: `Trail "${trailId}": ctx.provision('${provisionId}') called but '${provisionId}' is not declared in provisions`,
371
+ rule: 'provision-declarations',
368
372
  severity: 'error',
369
373
  });
370
374
 
371
375
  const buildUndeclaredLookupNameDiagnostic = (
372
376
  trailId: string,
373
- serviceName: string,
377
+ provisionName: string,
374
378
  filePath: string,
375
379
  line: number
376
380
  ): WardenDiagnostic => ({
377
381
  filePath,
378
382
  line,
379
- message: `Trail "${trailId}": ctx.service(${serviceName}) called but '${serviceName}' is not declared in services`,
380
- rule: 'service-declarations',
383
+ message: `Trail "${trailId}": ctx.provision(${provisionName}) called but '${provisionName}' is not declared in provisions`,
384
+ rule: 'provision-declarations',
381
385
  severity: 'error',
382
386
  });
383
387
 
384
388
  const buildUnusedDiagnostic = (
385
389
  trailId: string,
386
- declaredService: DeclaredService,
390
+ declaredProvision: DeclaredProvision,
387
391
  filePath: string,
388
392
  line: number
389
393
  ): WardenDiagnostic => ({
390
394
  filePath,
391
395
  line,
392
- message: `Trail "${trailId}": '${renderDeclaredService(declaredService)}' declared in services but never used`,
393
- rule: 'service-declarations',
396
+ message: `Trail "${trailId}": '${renderDeclaredProvision(declaredProvision)}' declared in provisions but never used`,
397
+ rule: 'provision-declarations',
394
398
  severity: 'warn',
395
399
  });
396
400
 
@@ -398,19 +402,22 @@ const buildUnusedDiagnostic = (
398
402
  // Comparison
399
403
  // ---------------------------------------------------------------------------
400
404
 
401
- const serviceWasUsed = (
402
- declaredService: DeclaredService,
403
- calledServices: CalledServices
405
+ const provisionWasUsed = (
406
+ declaredProvision: DeclaredProvision,
407
+ calledProvisions: CalledProvisions
404
408
  ): boolean => {
405
409
  if (
406
- declaredService.name &&
407
- (calledServices.fromNames.has(declaredService.name) ||
408
- calledServices.lookupNames.has(declaredService.name))
410
+ declaredProvision.name &&
411
+ (calledProvisions.fromNames.has(declaredProvision.name) ||
412
+ calledProvisions.lookupNames.has(declaredProvision.name))
409
413
  ) {
410
414
  return true;
411
415
  }
412
416
 
413
- if (declaredService.id && calledServices.lookupIds.has(declaredService.id)) {
417
+ if (
418
+ declaredProvision.id &&
419
+ calledProvisions.lookupIds.has(declaredProvision.id)
420
+ ) {
414
421
  return true;
415
422
  }
416
423
 
@@ -418,31 +425,35 @@ const serviceWasUsed = (
418
425
  };
419
426
 
420
427
  const buildDeclaredNames = (
421
- declaredServices: readonly DeclaredService[]
428
+ declaredProvisions: readonly DeclaredProvision[]
422
429
  ): ReadonlySet<string> =>
423
430
  new Set(
424
- declaredServices.flatMap((service) => (service.name ? [service.name] : []))
431
+ declaredProvisions.flatMap((provision) =>
432
+ provision.name ? [provision.name] : []
433
+ )
425
434
  );
426
435
 
427
436
  const buildDeclaredIds = (
428
- declaredServices: readonly DeclaredService[]
437
+ declaredProvisions: readonly DeclaredProvision[]
429
438
  ): ReadonlySet<string> =>
430
439
  new Set(
431
- declaredServices.flatMap((service) => (service.id ? [service.id] : []))
440
+ declaredProvisions.flatMap((provision) =>
441
+ provision.id ? [provision.id] : []
442
+ )
432
443
  );
433
444
 
434
445
  const reportUndeclaredFromCalls = (
435
446
  trailId: string,
436
447
  filePath: string,
437
448
  line: number,
438
- calledServices: CalledServices,
449
+ calledProvisions: CalledProvisions,
439
450
  declaredNames: ReadonlySet<string>,
440
451
  diagnostics: WardenDiagnostic[]
441
452
  ): void => {
442
- for (const serviceName of calledServices.fromNames) {
443
- if (!declaredNames.has(serviceName)) {
453
+ for (const provisionName of calledProvisions.fromNames) {
454
+ if (!declaredNames.has(provisionName)) {
444
455
  diagnostics.push(
445
- buildUndeclaredFromDiagnostic(trailId, serviceName, filePath, line)
456
+ buildUndeclaredFromDiagnostic(trailId, provisionName, filePath, line)
446
457
  );
447
458
  }
448
459
  }
@@ -452,19 +463,19 @@ const reportUndeclaredLookupCalls = (
452
463
  trailId: string,
453
464
  filePath: string,
454
465
  line: number,
455
- calledServices: CalledServices,
466
+ calledProvisions: CalledProvisions,
456
467
  declaredIds: ReadonlySet<string>,
457
468
  declaredNames: ReadonlySet<string>,
458
469
  diagnostics: WardenDiagnostic[]
459
470
  ): void => {
460
- for (const serviceName of calledServices.lookupNames) {
461
- // Name-based lookup checks remain reliable even when an imported service ID
471
+ for (const provisionName of calledProvisions.lookupNames) {
472
+ // Name-based lookup checks remain reliable even when an imported provision ID
462
473
  // cannot be resolved locally.
463
- if (!declaredNames.has(serviceName)) {
474
+ if (!declaredNames.has(provisionName)) {
464
475
  diagnostics.push(
465
476
  buildUndeclaredLookupNameDiagnostic(
466
477
  trailId,
467
- serviceName,
478
+ provisionName,
468
479
  filePath,
469
480
  line
470
481
  )
@@ -472,10 +483,10 @@ const reportUndeclaredLookupCalls = (
472
483
  }
473
484
  }
474
485
 
475
- for (const serviceId of calledServices.lookupIds) {
476
- if (!declaredIds.has(serviceId)) {
486
+ for (const provisionId of calledProvisions.lookupIds) {
487
+ if (!declaredIds.has(provisionId)) {
477
488
  diagnostics.push(
478
- buildUndeclaredLookupDiagnostic(trailId, serviceId, filePath, line)
489
+ buildUndeclaredLookupDiagnostic(trailId, provisionId, filePath, line)
479
490
  );
480
491
  }
481
492
  }
@@ -485,54 +496,54 @@ const reportUnusedDeclarations = (
485
496
  trailId: string,
486
497
  filePath: string,
487
498
  line: number,
488
- declaredServices: readonly DeclaredService[],
489
- calledServices: CalledServices,
499
+ declaredProvisions: readonly DeclaredProvision[],
500
+ calledProvisions: CalledProvisions,
490
501
  diagnostics: WardenDiagnostic[]
491
502
  ): void => {
492
- for (const declaredService of declaredServices) {
493
- if (serviceWasUsed(declaredService, calledServices)) {
503
+ for (const declaredProvision of declaredProvisions) {
504
+ if (provisionWasUsed(declaredProvision, calledProvisions)) {
494
505
  continue;
495
506
  }
496
507
 
497
- if (declaredService.name && declaredService.id === null) {
508
+ if (declaredProvision.name && declaredProvision.id === null) {
498
509
  continue;
499
510
  }
500
511
 
501
512
  diagnostics.push(
502
- buildUnusedDiagnostic(trailId, declaredService, filePath, line)
513
+ buildUnusedDiagnostic(trailId, declaredProvision, filePath, line)
503
514
  );
504
515
  }
505
516
  };
506
517
 
507
- const hasNoServiceActivity = (
508
- declaredServices: readonly DeclaredService[],
509
- calledServices: CalledServices
518
+ const hasNoProvisionActivity = (
519
+ declaredProvisions: readonly DeclaredProvision[],
520
+ calledProvisions: CalledProvisions
510
521
  ): boolean =>
511
- declaredServices.length === 0 &&
512
- calledServices.fromNames.size === 0 &&
513
- calledServices.lookupIds.size === 0 &&
514
- calledServices.lookupNames.size === 0;
522
+ declaredProvisions.length === 0 &&
523
+ calledProvisions.fromNames.size === 0 &&
524
+ calledProvisions.lookupIds.size === 0 &&
525
+ calledProvisions.lookupNames.size === 0;
515
526
 
516
527
  const analyzeTrailServices = (
517
528
  def: { config: AstNode; start: number },
518
529
  sourceCode: string,
519
- serviceIdsByName: ReadonlyMap<string, string>
530
+ provisionIdsByName: ReadonlyMap<string, string>
520
531
  ): {
521
- readonly calledServices: CalledServices;
532
+ readonly calledProvisions: CalledProvisions;
522
533
  readonly declaredIds: ReadonlySet<string>;
523
534
  readonly declaredNames: ReadonlySet<string>;
524
- readonly declaredServices: readonly DeclaredService[];
535
+ readonly declaredProvisions: readonly DeclaredProvision[];
525
536
  readonly line: number;
526
537
  } => {
527
- const declaredServices = extractDeclaredServices(
538
+ const declaredProvisions = extractDeclaredProvisions(
528
539
  def.config,
529
- serviceIdsByName
540
+ provisionIdsByName
530
541
  );
531
542
  return {
532
- calledServices: extractCalledServices(def.config),
533
- declaredIds: buildDeclaredIds(declaredServices),
534
- declaredNames: buildDeclaredNames(declaredServices),
535
- declaredServices,
543
+ calledProvisions: extractCalledProvisions(def.config),
544
+ declaredIds: buildDeclaredIds(declaredProvisions),
545
+ declaredNames: buildDeclaredNames(declaredProvisions),
546
+ declaredProvisions,
536
547
  line: offsetToLine(sourceCode, def.start),
537
548
  };
538
549
  };
@@ -541,13 +552,18 @@ const checkTrailDefinition = (
541
552
  def: { id: string; config: AstNode; start: number },
542
553
  filePath: string,
543
554
  sourceCode: string,
544
- serviceIdsByName: ReadonlyMap<string, string>,
555
+ provisionIdsByName: ReadonlyMap<string, string>,
545
556
  diagnostics: WardenDiagnostic[]
546
557
  ): void => {
547
- const { calledServices, declaredIds, declaredNames, declaredServices, line } =
548
- analyzeTrailServices(def, sourceCode, serviceIdsByName);
558
+ const {
559
+ calledProvisions,
560
+ declaredIds,
561
+ declaredNames,
562
+ declaredProvisions,
563
+ line,
564
+ } = analyzeTrailServices(def, sourceCode, provisionIdsByName);
549
565
 
550
- if (hasNoServiceActivity(declaredServices, calledServices)) {
566
+ if (hasNoProvisionActivity(declaredProvisions, calledProvisions)) {
551
567
  return;
552
568
  }
553
569
 
@@ -555,7 +571,7 @@ const checkTrailDefinition = (
555
571
  def.id,
556
572
  filePath,
557
573
  line,
558
- calledServices,
574
+ calledProvisions,
559
575
  declaredNames,
560
576
  diagnostics
561
577
  );
@@ -563,7 +579,7 @@ const checkTrailDefinition = (
563
579
  def.id,
564
580
  filePath,
565
581
  line,
566
- calledServices,
582
+ calledProvisions,
567
583
  declaredIds,
568
584
  declaredNames,
569
585
  diagnostics
@@ -572,8 +588,8 @@ const checkTrailDefinition = (
572
588
  def.id,
573
589
  filePath,
574
590
  line,
575
- declaredServices,
576
- calledServices,
591
+ declaredProvisions,
592
+ calledProvisions,
577
593
  diagnostics
578
594
  );
579
595
  };
@@ -583,9 +599,9 @@ const checkTrailDefinition = (
583
599
  // ---------------------------------------------------------------------------
584
600
 
585
601
  /**
586
- * Validates that service access aligns with declared `services` arrays.
602
+ * Validates that provision access aligns with declared `provisions` arrays.
587
603
  */
588
- export const serviceDeclarations: WardenRule = {
604
+ export const provisionDeclarations: WardenRule = {
589
605
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
590
606
  if (isTestFile(filePath)) {
591
607
  return [];
@@ -597,14 +613,14 @@ export const serviceDeclarations: WardenRule = {
597
613
  }
598
614
 
599
615
  const diagnostics: WardenDiagnostic[] = [];
600
- const serviceIdsByName = collectNamedServiceIds(ast);
616
+ const provisionIdsByName = collectNamedProvisionIds(ast);
601
617
 
602
618
  for (const def of findTrailDefinitions(ast)) {
603
619
  checkTrailDefinition(
604
620
  def,
605
621
  filePath,
606
622
  sourceCode,
607
- serviceIdsByName,
623
+ provisionIdsByName,
608
624
  diagnostics
609
625
  );
610
626
  }
@@ -612,7 +628,7 @@ export const serviceDeclarations: WardenRule = {
612
628
  return diagnostics;
613
629
  },
614
630
  description:
615
- 'Ensure service.from(ctx) and ctx.service() calls match the declared services array in trail definitions.',
616
- name: 'service-declarations',
631
+ 'Ensure provision.from(ctx) and ctx.provision() calls match the declared provisions array in trail definitions.',
632
+ name: 'provision-declarations',
617
633
  severity: 'error',
618
634
  };