@ontrails/warden 1.0.0-beta.39 → 1.0.0-beta.41

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 (134) hide show
  1. package/CHANGELOG.md +125 -0
  2. package/README.md +5 -5
  3. package/package.json +10 -12
  4. package/src/cli.ts +49 -44
  5. package/src/command.ts +2 -2
  6. package/src/drift.ts +4 -3
  7. package/src/index.ts +3 -2
  8. package/src/project-context.ts +3 -3
  9. package/src/resolve.ts +2 -2
  10. package/src/rules/captured-kernel.ts +375 -0
  11. package/src/rules/circular-refs.ts +12 -16
  12. package/src/rules/cli-command-route-coherence.ts +1 -1
  13. package/src/rules/composes-declarations.ts +15 -13
  14. package/src/rules/context-no-surface-types.ts +4 -3
  15. package/src/rules/dead-internal-trail.ts +3 -3
  16. package/src/rules/dead-public-trail.ts +3 -3
  17. package/src/rules/draft-file-marking.ts +4 -9
  18. package/src/rules/draft-visible-debt.ts +3 -8
  19. package/src/rules/duplicate-public-contract.ts +50 -5
  20. package/src/rules/{contour-exists.ts → entity-exists.ts} +67 -64
  21. package/src/rules/entity-ids.ts +15 -0
  22. package/src/rules/error-mapping-completeness.ts +2 -2
  23. package/src/rules/example-valid.ts +84 -84
  24. package/src/rules/fires-declarations.ts +27 -22
  25. package/src/rules/governed-symbol-residue.ts +339 -32
  26. package/src/rules/implementation-returns-result.ts +8 -8
  27. package/src/rules/incomplete-accessor-for-standard-op.ts +15 -15
  28. package/src/rules/incomplete-crud.ts +42 -40
  29. package/src/rules/index.ts +9 -6
  30. package/src/rules/intent-propagation.ts +3 -5
  31. package/src/rules/layer-field-name-drift.ts +2 -2
  32. package/src/rules/library-projection-coherence.ts +2 -2
  33. package/src/rules/metadata.ts +37 -15
  34. package/src/rules/missing-reconcile.ts +3 -4
  35. package/src/rules/missing-visibility.ts +2 -1
  36. package/src/rules/no-destructured-compose.ts +14 -12
  37. package/src/rules/no-direct-implementation-call.ts +12 -7
  38. package/src/rules/no-legacy-cli-alias-export.ts +2 -2
  39. package/src/rules/no-native-error-result.ts +2 -2
  40. package/src/rules/no-redundant-result-error-wrap.ts +10 -10
  41. package/src/rules/no-sync-result-assumption.ts +84 -78
  42. package/src/rules/no-throw-in-detour-recover.ts +2 -2
  43. package/src/rules/no-throw-in-implementation.ts +13 -7
  44. package/src/rules/no-top-level-surface.ts +2 -2
  45. package/src/rules/on-references-exist.ts +3 -3
  46. package/src/rules/orphaned-signal.ts +4 -5
  47. package/src/rules/owner-projection-parity.ts +2 -2
  48. package/src/rules/public-export-example-coverage.ts +10 -4
  49. package/src/rules/public-internal-deep-imports.ts +2 -3
  50. package/src/rules/read-intent-fires.ts +4 -3
  51. package/src/rules/reference-exists.ts +20 -21
  52. package/src/rules/registry-names.ts +6 -4
  53. package/src/rules/resolved-import-boundary.ts +1 -1
  54. package/src/rules/resource-declarations.ts +21 -17
  55. package/src/rules/resource-exists.ts +4 -2
  56. package/src/rules/resource-id-grammar.ts +2 -2
  57. package/src/rules/resource-mock-coverage.ts +2 -2
  58. package/src/rules/retired-vocabulary.ts +242 -5
  59. package/src/rules/source/composition.ts +165 -0
  60. package/src/rules/source/drafts.ts +164 -0
  61. package/src/rules/source/entities.ts +618 -0
  62. package/src/rules/source/pragmas.ts +45 -0
  63. package/src/rules/source/resources.ts +64 -0
  64. package/src/rules/source/signals.ts +397 -0
  65. package/src/rules/source/stores.ts +310 -0
  66. package/src/rules/static-resource-accessor-preference.ts +15 -11
  67. package/src/rules/surface-overlay-coherence.ts +1 -1
  68. package/src/rules/surface-trailhead-coherence.ts +2 -2
  69. package/src/rules/trail-fork-coaching.ts +27 -18
  70. package/src/rules/trail-versioning-source.ts +16 -12
  71. package/src/rules/trail-versioning-topo.ts +2 -2
  72. package/src/rules/trailhead-override-divergence.ts +2 -2
  73. package/src/rules/types.ts +7 -7
  74. package/src/rules/unmaterialized-activation-source.ts +1 -0
  75. package/src/rules/unreachable-detour-shadowing.ts +2 -2
  76. package/src/rules/valid-describe-refs.ts +2 -2
  77. package/src/rules/warden-export-symmetry.ts +3 -3
  78. package/src/rules/warden-rules-use-ast.ts +12 -17
  79. package/src/trails/activation-orphan.trail.ts +5 -5
  80. package/src/trails/captured-kernel.trail.ts +108 -0
  81. package/src/trails/circular-refs.trail.ts +6 -6
  82. package/src/trails/cli-command-route-coherence.trail.ts +2 -2
  83. package/src/trails/composes-declarations.trail.ts +1 -1
  84. package/src/trails/context-no-surface-types.trail.ts +1 -1
  85. package/src/trails/dead-internal-trail.trail.ts +2 -2
  86. package/src/trails/dead-public-trail.trail.ts +1 -1
  87. package/src/trails/deprecation-without-guidance.trail.ts +1 -1
  88. package/src/trails/duplicate-public-contract.trail.ts +3 -3
  89. package/src/trails/entity-exists.trail.ts +21 -0
  90. package/src/trails/example-valid.trail.ts +3 -3
  91. package/src/trails/fires-declarations.trail.ts +1 -1
  92. package/src/trails/{fork-without-preserved-blaze.trail.ts → fork-without-preserved-implementation.trail.ts} +4 -4
  93. package/src/trails/implementation-returns-result.trail.ts +1 -1
  94. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +4 -4
  95. package/src/trails/index.ts +3 -2
  96. package/src/trails/intent-propagation.trail.ts +2 -2
  97. package/src/trails/library-projection-coherence.trail.ts +2 -2
  98. package/src/trails/marker-schema-unsupported.trail.ts +1 -1
  99. package/src/trails/missing-visibility.trail.ts +1 -1
  100. package/src/trails/no-destructured-compose.trail.ts +5 -5
  101. package/src/trails/no-direct-implementation-call.trail.ts +1 -1
  102. package/src/trails/no-redundant-result-error-wrap.trail.ts +2 -2
  103. package/src/trails/no-sync-result-assumption.trail.ts +2 -2
  104. package/src/trails/no-throw-in-detour-recover.trail.ts +1 -1
  105. package/src/trails/no-throw-in-implementation.trail.ts +1 -1
  106. package/src/trails/on-references-exist.trail.ts +1 -1
  107. package/src/trails/pending-force.trail.ts +1 -1
  108. package/src/trails/permit-governance.trail.ts +2 -2
  109. package/src/trails/prefer-schema-inference.trail.ts +1 -1
  110. package/src/trails/public-output-schema.trail.ts +2 -2
  111. package/src/trails/public-union-output-discriminants.trail.ts +1 -1
  112. package/src/trails/read-intent-fires.trail.ts +1 -1
  113. package/src/trails/reference-exists.trail.ts +5 -5
  114. package/src/trails/resource-declarations.trail.ts +1 -1
  115. package/src/trails/resource-exists.trail.ts +1 -1
  116. package/src/trails/run.ts +4 -6
  117. package/src/trails/scheduled-destroy-intent.trail.ts +2 -2
  118. package/src/trails/schema.ts +9 -9
  119. package/src/trails/signal-graph-coaching.trail.ts +2 -2
  120. package/src/trails/static-resource-accessor-preference.trail.ts +1 -1
  121. package/src/trails/surface-overlay-coherence.trail.ts +1 -1
  122. package/src/trails/trail-fork-coaching.trail.ts +1 -1
  123. package/src/trails/unmaterialized-activation-source.trail.ts +5 -5
  124. package/src/trails/valid-detour-contract.trail.ts +1 -1
  125. package/src/trails/version-gap.trail.ts +1 -1
  126. package/src/trails/version-pinned-compose.trail.ts +1 -1
  127. package/src/trails/version-without-examples.trail.ts +1 -1
  128. package/src/trails/warden-rules-use-ast.trail.ts +2 -2
  129. package/src/trails/webhook-route-collision.trail.ts +2 -2
  130. package/src/trails/wrap-rule.ts +17 -17
  131. package/src/ast.ts +0 -137
  132. package/src/rules/ast.ts +0 -4143
  133. package/src/rules/contour-ids.ts +0 -15
  134. package/src/trails/contour-exists.trail.ts +0 -21
@@ -1,10 +1,10 @@
1
- import { contour } from '@ontrails/core';
1
+ import { entity } from '@ontrails/core';
2
2
  import { z } from 'zod';
3
3
 
4
4
  import {
5
5
  extractStringLiteral,
6
6
  findConfigProperty,
7
- findContourDefinitions,
7
+ findEntityDefinitions,
8
8
  getNodeExpression,
9
9
  getNodeObject,
10
10
  getNodeProperty,
@@ -12,24 +12,24 @@ import {
12
12
  identifierName,
13
13
  offsetToLine,
14
14
  parse,
15
- } from './ast.js';
16
- import type { AstNode, ContourDefinition } from './ast.js';
15
+ } from '@ontrails/source';
16
+ import type { AstNode, EntityDefinition } from '@ontrails/source';
17
17
  import { isTestFile } from './scan.js';
18
18
  import type { WardenDiagnostic, WardenRule } from './types.js';
19
19
 
20
- class UnsupportedContourEvaluationError extends Error {}
20
+ class UnsupportedEntityEvaluationError extends Error {}
21
21
 
22
- type ContourEvaluationEnvironment = ReadonlyMap<string, unknown>;
22
+ type EntityEvaluationEnvironment = ReadonlyMap<string, unknown>;
23
23
 
24
24
  const buildInvalidExampleDiagnostic = (
25
- contourName: string,
25
+ entityName: string,
26
26
  message: string,
27
27
  filePath: string,
28
28
  line: number
29
29
  ): WardenDiagnostic => ({
30
30
  filePath,
31
31
  line,
32
- message: `Contour "${contourName}" has invalid examples: ${message}`,
32
+ message: `Entity "${entityName}" has invalid examples: ${message}`,
33
33
  rule: 'example-valid',
34
34
  severity: 'error',
35
35
  });
@@ -49,53 +49,53 @@ const getPropertyName = (node: unknown): string | null => {
49
49
 
50
50
  const requireNode = (node: AstNode | undefined): AstNode => {
51
51
  if (!node) {
52
- throw new UnsupportedContourEvaluationError(
53
- 'Missing node in contour evaluation.'
52
+ throw new UnsupportedEntityEvaluationError(
53
+ 'Missing node in entity evaluation.'
54
54
  );
55
55
  }
56
56
 
57
57
  return node;
58
58
  };
59
59
 
60
- type ContourNodeEvaluator = (
60
+ type EntityNodeEvaluator = (
61
61
  node: AstNode,
62
- env: ContourEvaluationEnvironment
62
+ env: EntityEvaluationEnvironment
63
63
  ) => unknown;
64
64
 
65
65
  // The evaluator table is declared before `evaluateNode` so the recursive
66
66
  // dispatch can read it at call time without any forward references. Entries
67
67
  // are registered below once each per-type evaluator is defined.
68
- const contourNodeEvaluators = new Map<string, ContourNodeEvaluator>();
68
+ const entityNodeEvaluators = new Map<string, EntityNodeEvaluator>();
69
69
 
70
- const evaluateNode: ContourNodeEvaluator = (
70
+ const evaluateNode: EntityNodeEvaluator = (
71
71
  node: AstNode,
72
- env: ContourEvaluationEnvironment
72
+ env: EntityEvaluationEnvironment
73
73
  ): unknown => {
74
- const evaluator = contourNodeEvaluators.get(node.type);
74
+ const evaluator = entityNodeEvaluators.get(node.type);
75
75
  if (evaluator) {
76
76
  return evaluator(node, env);
77
77
  }
78
78
 
79
- throw new UnsupportedContourEvaluationError(
80
- `Unsupported AST node "${node.type}" in contour evaluation.`
79
+ throw new UnsupportedEntityEvaluationError(
80
+ `Unsupported AST node "${node.type}" in entity evaluation.`
81
81
  );
82
82
  };
83
83
 
84
- const evaluateArrayExpression: ContourNodeEvaluator = (
84
+ const evaluateArrayExpression: EntityNodeEvaluator = (
85
85
  node: AstNode,
86
- env: ContourEvaluationEnvironment
86
+ env: EntityEvaluationEnvironment
87
87
  ): readonly unknown[] => {
88
88
  const elements = node['elements'] as readonly AstNode[] | undefined;
89
89
  return (elements ?? []).map((element) => evaluateNode(element, env));
90
90
  };
91
91
 
92
- const evaluateLiteralExpression: ContourNodeEvaluator = (
92
+ const evaluateLiteralExpression: EntityNodeEvaluator = (
93
93
  node: AstNode
94
94
  ): unknown => getStringValue(node) ?? node.value;
95
95
 
96
- const evaluateIdentifierExpression: ContourNodeEvaluator = (
96
+ const evaluateIdentifierExpression: EntityNodeEvaluator = (
97
97
  node: AstNode,
98
- env: ContourEvaluationEnvironment
98
+ env: EntityEvaluationEnvironment
99
99
  ): unknown => {
100
100
  const name = identifierName(node);
101
101
  if (name === 'undefined') {
@@ -107,39 +107,39 @@ const evaluateIdentifierExpression: ContourNodeEvaluator = (
107
107
  }
108
108
 
109
109
  if (!name || !env.has(name)) {
110
- throw new UnsupportedContourEvaluationError(
111
- `Unknown identifier "${name ?? '<unknown>'}" in contour evaluation.`
110
+ throw new UnsupportedEntityEvaluationError(
111
+ `Unknown identifier "${name ?? '<unknown>'}" in entity evaluation.`
112
112
  );
113
113
  }
114
114
 
115
115
  return env.get(name);
116
116
  };
117
117
 
118
- const evaluateWrappedExpression: ContourNodeEvaluator = (
118
+ const evaluateWrappedExpression: EntityNodeEvaluator = (
119
119
  node: AstNode,
120
- env: ContourEvaluationEnvironment
120
+ env: EntityEvaluationEnvironment
121
121
  ): unknown => evaluateNode(requireNode(getNodeExpression(node)), env);
122
122
 
123
- const evaluateNullExpression: ContourNodeEvaluator = (): null => null;
123
+ const evaluateNullExpression: EntityNodeEvaluator = (): null => null;
124
124
 
125
- const evaluateObjectExpression: ContourNodeEvaluator = (
125
+ const evaluateObjectExpression: EntityNodeEvaluator = (
126
126
  node: AstNode,
127
- env: ContourEvaluationEnvironment
127
+ env: EntityEvaluationEnvironment
128
128
  ): Record<string, unknown> => {
129
129
  const properties = node['properties'] as readonly AstNode[] | undefined;
130
130
  const value: Record<string, unknown> = {};
131
131
 
132
132
  for (const property of properties ?? []) {
133
133
  if (property.type !== 'Property') {
134
- throw new UnsupportedContourEvaluationError(
134
+ throw new UnsupportedEntityEvaluationError(
135
135
  `Unsupported object property type "${property.type}".`
136
136
  );
137
137
  }
138
138
 
139
139
  const propertyName = getPropertyName(property.key);
140
140
  if (!propertyName) {
141
- throw new UnsupportedContourEvaluationError(
142
- 'Unsupported object property key in contour evaluation.'
141
+ throw new UnsupportedEntityEvaluationError(
142
+ 'Unsupported object property key in entity evaluation.'
143
143
  );
144
144
  }
145
145
 
@@ -154,107 +154,107 @@ const evaluateObjectExpression: ContourNodeEvaluator = (
154
154
 
155
155
  const evaluateCallArguments = (
156
156
  node: AstNode,
157
- env: ContourEvaluationEnvironment
157
+ env: EntityEvaluationEnvironment
158
158
  ): readonly unknown[] =>
159
159
  ((node['arguments'] as readonly AstNode[] | undefined) ?? []).map((arg) =>
160
160
  evaluateNode(arg, env)
161
161
  );
162
162
 
163
- const resolveContourFallbackOptions = (
163
+ const resolveEntityFallbackOptions = (
164
164
  shape: unknown
165
- ): Parameters<typeof contour>[2] | null =>
165
+ ): Parameters<typeof entity>[2] | null =>
166
166
  typeof shape === 'object' &&
167
167
  shape !== null &&
168
168
  Object.hasOwn(shape, 'id') &&
169
169
  (shape as z.ZodRawShape)['id'] !== undefined
170
- ? ({ identity: 'id' } as Parameters<typeof contour>[2])
170
+ ? ({ identity: 'id' } as Parameters<typeof entity>[2])
171
171
  : null;
172
172
 
173
- const resolveContourOptions = (
173
+ const resolveEntityOptions = (
174
174
  shape: unknown,
175
175
  options: unknown
176
- ): Parameters<typeof contour>[2] => {
176
+ ): Parameters<typeof entity>[2] => {
177
177
  if (options === undefined) {
178
- const fallbackOptions = resolveContourFallbackOptions(shape);
178
+ const fallbackOptions = resolveEntityFallbackOptions(shape);
179
179
  if (fallbackOptions !== null) {
180
180
  return fallbackOptions;
181
181
  }
182
182
 
183
- throw new UnsupportedContourEvaluationError(
184
- 'Contour evaluator requires literal options, or an `id` field when options are omitted.'
183
+ throw new UnsupportedEntityEvaluationError(
184
+ 'Entity evaluator requires literal options, or an `id` field when options are omitted.'
185
185
  );
186
186
  }
187
187
 
188
188
  if (typeof options !== 'object' || options === null) {
189
- throw new UnsupportedContourEvaluationError(
190
- 'Contour evaluator requires literal options when provided.'
189
+ throw new UnsupportedEntityEvaluationError(
190
+ 'Entity evaluator requires literal options when provided.'
191
191
  );
192
192
  }
193
193
 
194
- return options as Parameters<typeof contour>[2];
194
+ return options as Parameters<typeof entity>[2];
195
195
  };
196
196
 
197
- const evaluateContourCall = (args: readonly unknown[]): unknown => {
197
+ const evaluateEntityCall = (args: readonly unknown[]): unknown => {
198
198
  const [name, shape, options] = args;
199
199
  if (typeof name !== 'string') {
200
- throw new UnsupportedContourEvaluationError(
201
- 'Contour evaluator requires a literal name.'
200
+ throw new UnsupportedEntityEvaluationError(
201
+ 'Entity evaluator requires a literal name.'
202
202
  );
203
203
  }
204
204
 
205
- return contour(
205
+ return entity(
206
206
  name,
207
207
  shape as z.ZodRawShape,
208
- resolveContourOptions(shape, options)
208
+ resolveEntityOptions(shape, options)
209
209
  );
210
210
  };
211
211
 
212
212
  const evaluateMemberCall = (
213
213
  callee: AstNode,
214
214
  args: readonly unknown[],
215
- env: ContourEvaluationEnvironment
215
+ env: EntityEvaluationEnvironment
216
216
  ): unknown => {
217
217
  const receiver = evaluateNode(requireNode(getNodeObject(callee)), env);
218
218
  const propertyName = getPropertyName(getNodeProperty(callee));
219
219
  if (!propertyName) {
220
- throw new UnsupportedContourEvaluationError(
221
- 'Unsupported member property in contour evaluation.'
220
+ throw new UnsupportedEntityEvaluationError(
221
+ 'Unsupported member property in entity evaluation.'
222
222
  );
223
223
  }
224
224
 
225
225
  const method = (receiver as Record<string, unknown>)[propertyName];
226
226
  if (typeof method !== 'function') {
227
- throw new UnsupportedContourEvaluationError(
228
- `Contour evaluator could not call "${propertyName}".`
227
+ throw new UnsupportedEntityEvaluationError(
228
+ `Entity evaluator could not call "${propertyName}".`
229
229
  );
230
230
  }
231
231
 
232
232
  return Reflect.apply(method, receiver, args);
233
233
  };
234
234
 
235
- const evaluateCallExpression: ContourNodeEvaluator = (
235
+ const evaluateCallExpression: EntityNodeEvaluator = (
236
236
  node: AstNode,
237
- env: ContourEvaluationEnvironment
237
+ env: EntityEvaluationEnvironment
238
238
  ): unknown => {
239
239
  const args = evaluateCallArguments(node, env);
240
240
  const callee = requireNode(node['callee'] as AstNode | undefined);
241
241
 
242
242
  if (callee.type === 'Identifier') {
243
243
  const calleeName = identifierName(callee);
244
- if (calleeName !== 'contour') {
245
- throw new UnsupportedContourEvaluationError(
246
- `Unsupported contour evaluator call "${calleeName ?? '<unknown>'}".`
244
+ if (calleeName !== 'entity') {
245
+ throw new UnsupportedEntityEvaluationError(
246
+ `Unsupported entity evaluator call "${calleeName ?? '<unknown>'}".`
247
247
  );
248
248
  }
249
249
 
250
- return evaluateContourCall(args);
250
+ return evaluateEntityCall(args);
251
251
  }
252
252
 
253
253
  if (
254
254
  callee.type !== 'MemberExpression' &&
255
255
  callee.type !== 'StaticMemberExpression'
256
256
  ) {
257
- throw new UnsupportedContourEvaluationError(
257
+ throw new UnsupportedEntityEvaluationError(
258
258
  `Unsupported callee type "${callee.type}".`
259
259
  );
260
260
  }
@@ -264,7 +264,7 @@ const evaluateCallExpression: ContourNodeEvaluator = (
264
264
 
265
265
  const EVALUATOR_REGISTRATIONS: readonly (readonly [
266
266
  string,
267
- ContourNodeEvaluator,
267
+ EntityNodeEvaluator,
268
268
  ])[] = [
269
269
  ['ArrayExpression', evaluateArrayExpression],
270
270
  ['BooleanLiteral', evaluateLiteralExpression],
@@ -281,26 +281,26 @@ const EVALUATOR_REGISTRATIONS: readonly (readonly [
281
281
  ];
282
282
 
283
283
  for (const [type, evaluator] of EVALUATOR_REGISTRATIONS) {
284
- contourNodeEvaluators.set(type, evaluator);
284
+ entityNodeEvaluators.set(type, evaluator);
285
285
  }
286
286
 
287
- const hasExamples = (definition: ContourDefinition): boolean =>
287
+ const hasExamples = (definition: EntityDefinition): boolean =>
288
288
  definition.options !== null &&
289
289
  findConfigProperty(definition.options, 'examples') !== null;
290
290
 
291
- const evaluateContourDefinition = (
292
- definition: ContourDefinition,
293
- env: ContourEvaluationEnvironment
291
+ const evaluateEntityDefinition = (
292
+ definition: EntityDefinition,
293
+ env: EntityEvaluationEnvironment
294
294
  ): unknown => evaluateNode(definition.call, env);
295
295
 
296
- const buildContourExampleErrorDiagnostic = (
297
- definition: ContourDefinition,
296
+ const buildEntityExampleErrorDiagnostic = (
297
+ definition: EntityDefinition,
298
298
  error: unknown,
299
299
  sourceCode: string,
300
300
  filePath: string
301
301
  ): WardenDiagnostic | null => {
302
302
  if (
303
- error instanceof UnsupportedContourEvaluationError ||
303
+ error instanceof UnsupportedEntityEvaluationError ||
304
304
  !hasExamples(definition) ||
305
305
  !(error instanceof Error)
306
306
  ) {
@@ -315,21 +315,21 @@ const buildContourExampleErrorDiagnostic = (
315
315
  );
316
316
  };
317
317
 
318
- const evaluateContourExamples = (
319
- definition: ContourDefinition,
318
+ const evaluateEntityExamples = (
319
+ definition: EntityDefinition,
320
320
  env: Map<string, unknown>,
321
321
  sourceCode: string,
322
322
  filePath: string
323
323
  ): WardenDiagnostic | null => {
324
324
  try {
325
- const value = evaluateContourDefinition(definition, env);
325
+ const value = evaluateEntityDefinition(definition, env);
326
326
  if (definition.bindingName) {
327
327
  env.set(definition.bindingName, value);
328
328
  }
329
329
 
330
330
  return null;
331
331
  } catch (error) {
332
- return buildContourExampleErrorDiagnostic(
332
+ return buildEntityExampleErrorDiagnostic(
333
333
  definition,
334
334
  error,
335
335
  sourceCode,
@@ -338,8 +338,8 @@ const evaluateContourExamples = (
338
338
  }
339
339
  };
340
340
 
341
- const collectContourExampleDiagnostics = (
342
- definitions: readonly ContourDefinition[],
341
+ const collectEntityExampleDiagnostics = (
342
+ definitions: readonly EntityDefinition[],
343
343
  sourceCode: string,
344
344
  filePath: string
345
345
  ): readonly WardenDiagnostic[] => {
@@ -347,7 +347,7 @@ const collectContourExampleDiagnostics = (
347
347
  const env = new Map<string, unknown>();
348
348
 
349
349
  for (const definition of definitions) {
350
- const diagnostic = evaluateContourExamples(
350
+ const diagnostic = evaluateEntityExamples(
351
351
  definition,
352
352
  env,
353
353
  sourceCode,
@@ -361,7 +361,7 @@ const collectContourExampleDiagnostics = (
361
361
  return diagnostics;
362
362
  };
363
363
 
364
- const checkContourExamples = (
364
+ const checkEntityExamples = (
365
365
  sourceCode: string,
366
366
  filePath: string
367
367
  ): readonly WardenDiagnostic[] => {
@@ -374,22 +374,22 @@ const checkContourExamples = (
374
374
  return [];
375
375
  }
376
376
 
377
- return collectContourExampleDiagnostics(
378
- findContourDefinitions(ast),
377
+ return collectEntityExampleDiagnostics(
378
+ findEntityDefinitions(ast),
379
379
  sourceCode,
380
380
  filePath
381
381
  );
382
382
  };
383
383
 
384
384
  /**
385
- * Checks that contour examples validate against their schema.
385
+ * Checks that entity examples validate against their schema.
386
386
  */
387
387
  export const exampleValid: WardenRule = {
388
388
  check(sourceCode: string, filePath: string): readonly WardenDiagnostic[] {
389
- return checkContourExamples(sourceCode, filePath);
389
+ return checkEntityExamples(sourceCode, filePath);
390
390
  },
391
391
  description:
392
- 'Ensure every contour example validates against the declared contour schema.',
392
+ 'Ensure every entity example validates against the declared entity schema.',
393
393
  name: 'example-valid',
394
394
  severity: 'error',
395
395
  };
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Validates that `ctx.fire()` calls match the declared `fires` array.
3
3
  *
4
- * Statically analyzes trail `blaze` functions to find `ctx.fire(signal, ...)`
4
+ * Statically analyzes trail `implementation` functions to find `ctx.fire(signal, ...)`
5
5
  * calls and compares locally-resolved `Signal` values against the `fires: [...]`
6
6
  * declaration in the trail config. Reports errors for undeclared fires, string
7
7
  * fire calls that no longer match the public runtime API, and warnings for
@@ -11,12 +11,12 @@
11
11
  * shape, same const-identifier resolution, same context-parameter handling.
12
12
  */
13
13
 
14
+ import { buildSignalIdentifierResolver } from './source/signals.js';
14
15
  import {
15
- buildSignalIdentifierResolver,
16
16
  deriveConstString,
17
17
  extractStringLiteral,
18
- findBlazeBodies,
19
18
  findConfigProperty,
19
+ findImplementationBodies,
20
20
  findTrailDefinitions,
21
21
  getNodeBodyNode,
22
22
  getNodeBodyStatements,
@@ -34,8 +34,9 @@ import {
34
34
  offsetToLine,
35
35
  parse,
36
36
  walkScope,
37
- } from './ast.js';
38
- import type { AstNode, SignalIdentifierResolver } from './ast.js';
37
+ } from '@ontrails/source';
38
+ import type { AstNode } from '@ontrails/source';
39
+ import type { SignalIdentifierResolver } from './source/signals.js';
39
40
  import { isTestFile } from './scan.js';
40
41
  import type { WardenDiagnostic, WardenRule } from './types.js';
41
42
 
@@ -164,14 +165,16 @@ const extractMemberPair = (
164
165
  };
165
166
 
166
167
  /**
167
- * Extract the second parameter node from a blaze function node.
168
+ * Extract the second parameter node from a implementation function node.
168
169
  *
169
170
  * Handles `(input, ctx) => ...`, `async (input, context) => ...`,
170
171
  * `function(input, ctx) { ... }`, and parameter-level destructuring
171
172
  * like `(input, { fire }) => ...`.
172
173
  */
173
- const extractContextParamNode = (blazeBody: AstNode): AstNode | null => {
174
- const params = blazeBody['params'] as readonly AstNode[] | undefined;
174
+ const extractContextParamNode = (
175
+ implementationBody: AstNode
176
+ ): AstNode | null => {
177
+ const params = implementationBody['params'] as readonly AstNode[] | undefined;
175
178
  if (!params || params.length < 2) {
176
179
  return null;
177
180
  }
@@ -212,7 +215,7 @@ const collectFireNamesFromPattern = (
212
215
  };
213
216
 
214
217
  /**
215
- * Extract the second parameter name from a blaze function node.
218
+ * Extract the second parameter name from a implementation function node.
216
219
  *
217
220
  * Returns null when the parameter is not a plain Identifier (e.g. when the
218
221
  * author destructures `{ fire }` in the parameter list). Parameter-level
@@ -222,8 +225,10 @@ const collectFireNamesFromPattern = (
222
225
  * (AssignmentPattern whose `.left` is the Identifier). Without this, valid
223
226
  * signatures would silently drop out of ctx-access analysis.
224
227
  */
225
- const extractContextParamName = (blazeBody: AstNode): string | null => {
226
- const param = extractContextParamNode(blazeBody);
228
+ const extractContextParamName = (
229
+ implementationBody: AstNode
230
+ ): string | null => {
231
+ const param = extractContextParamNode(implementationBody);
227
232
  if (!param) {
228
233
  return null;
229
234
  }
@@ -238,7 +243,7 @@ const extractContextParamName = (blazeBody: AstNode): string | null => {
238
243
  * Collect `fire` local names bound via parameter-level destructuring.
239
244
  *
240
245
  * Recognizes `(input, { fire }) => ...` and `(input, { fire: emit }) => ...`.
241
- * When the blaze author destructures in the parameter list, there is no
246
+ * When the implementation author destructures in the parameter list, there is no
242
247
  * enclosing `ctx` identifier to track — we seed the fire local set directly
243
248
  * from the ObjectPattern in `params[1]`.
244
249
  */
@@ -350,7 +355,7 @@ const extractFireCallId = (
350
355
  };
351
356
 
352
357
  /**
353
- * Walk a blaze body and collect local names bound to `ctx.fire` via destructure.
358
+ * Walk a implementation body and collect local names bound to `ctx.fire` via destructure.
354
359
  *
355
360
  * Recognizes:
356
361
  * - `const { fire } = ctx;` → adds `fire`
@@ -382,8 +387,8 @@ const getCtxDestructurePattern = (
382
387
 
383
388
  /**
384
389
  * Collect `fire` local names destructured from ctx at the TOP LEVEL of the
385
- * blaze body. Destructures inside nested functions are intentionally ignored
386
- * to avoid leaking nested-scope bindings into the outer blaze scope — a
390
+ * implementation body. Destructures inside nested functions are intentionally ignored
391
+ * to avoid leaking nested-scope bindings into the outer implementation scope — a
387
392
  * `const { fire } = ctx` inside a nested helper should not cause an outer
388
393
  * bare `fire('x')` to be treated as a ctx-bound call.
389
394
  *
@@ -398,7 +403,7 @@ const getCtxDestructurePattern = (
398
403
  * class of false positives. The runtime + signal-id compose-check still
399
404
  * validate real undeclared fires.
400
405
  */
401
- /** Get the top-level statements of a blaze function's BlockStatement body. */
406
+ /** Get the top-level statements of a implementation function's BlockStatement body. */
402
407
  const getTopLevelStatements = (body: AstNode): readonly AstNode[] => {
403
408
  const blockBody = getNodeBodyNode(body);
404
409
  if (!blockBody || blockBody.type !== 'BlockStatement') {
@@ -448,10 +453,10 @@ const collectDestructuredFireNames = (
448
453
  /**
449
454
  * Build the set of context parameter names to match against.
450
455
  *
451
- * Returns ONLY the actual second-parameter name from the blaze signature.
452
- * No seeded defaults: if the blaze has no second parameter, the returned set
456
+ * Returns ONLY the actual second-parameter name from the implementation signature.
457
+ * No seeded defaults: if the implementation has no second parameter, the returned set
453
458
  * is empty and no `ctx.fire(...)` / `context.fire(...)` calls are tracked
454
- * for that blaze. An unrelated closure-scoped `ctx` identifier is not the
459
+ * for that implementation. An unrelated closure-scoped `ctx` identifier is not the
455
460
  * trail context and must not be treated as one.
456
461
  */
457
462
  const buildCtxNames = (body: AstNode): ReadonlySet<string> => {
@@ -464,7 +469,7 @@ const buildCtxNames = (body: AstNode): ReadonlySet<string> => {
464
469
  };
465
470
 
466
471
  /**
467
- * Walk blaze bodies and collect all statically resolvable ctx.fire() signal IDs.
472
+ * Walk implementation bodies and collect all statically resolvable ctx.fire() signal IDs.
468
473
  *
469
474
  * Traversal uses `walkScope`, which stops at nested function boundaries
470
475
  * (FunctionDeclaration, FunctionExpression, ArrowFunctionExpression). This
@@ -473,7 +478,7 @@ const buildCtxNames = (body: AstNode): ReadonlySet<string> => {
473
478
  * destructured `fire` local:
474
479
  *
475
480
  * ```ts
476
- * blaze: async (_, ctx) => {
481
+ * implementation: async (_, ctx) => {
477
482
  * const { fire } = ctx;
478
483
  * function nested(fire) { fire(orderPlaced); } // ignored — shadowed
479
484
  * function other(ctx) { ctx.fire(orderPlaced); } // ignored — shadowed
@@ -558,7 +563,7 @@ const extractCalledFires = (
558
563
  const stringIds = new Set<string>();
559
564
  const merged = { hasUnresolved: false, ids, stringIds };
560
565
 
561
- for (const body of findBlazeBodies(config)) {
566
+ for (const body of findImplementationBodies(config)) {
562
567
  mergeCalledFires(
563
568
  merged,
564
569
  extractCalledFiresFromBody(body, sourceCode, signalIds)