@ontrails/warden 1.0.0-beta.2 → 1.0.0-beta.22

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 (249) hide show
  1. package/CHANGELOG.md +508 -6
  2. package/README.md +77 -26
  3. package/bin/warden.ts +50 -0
  4. package/package.json +27 -5
  5. package/src/adapter-check.ts +136 -0
  6. package/src/ast.ts +28 -0
  7. package/src/cli.ts +1374 -103
  8. package/src/command.ts +953 -0
  9. package/src/config.ts +184 -0
  10. package/src/draft.ts +22 -0
  11. package/src/drift.ts +106 -22
  12. package/src/fix.ts +120 -0
  13. package/src/formatters.ts +79 -9
  14. package/src/guide.ts +245 -0
  15. package/src/index.ts +206 -14
  16. package/src/project-context.ts +163 -0
  17. package/src/resolve.ts +530 -0
  18. package/src/rules/activation-orphan.ts +97 -0
  19. package/src/rules/ast.ts +3176 -85
  20. package/src/rules/circular-refs.ts +154 -0
  21. package/src/rules/composes-declarations.ts +704 -0
  22. package/src/rules/context-no-surface-types.ts +68 -8
  23. package/src/rules/contour-exists.ts +251 -0
  24. package/src/rules/contour-ids.ts +15 -0
  25. package/src/rules/dead-internal-trail.ts +154 -0
  26. package/src/rules/draft-file-marking.ts +160 -0
  27. package/src/rules/draft-visible-debt.ts +87 -0
  28. package/src/rules/error-mapping-completeness.ts +288 -0
  29. package/src/rules/example-valid.ts +401 -0
  30. package/src/rules/fires-declarations.ts +758 -0
  31. package/src/rules/implementation-returns-result.ts +1265 -95
  32. package/src/rules/incomplete-accessor-for-standard-op.ts +272 -0
  33. package/src/rules/incomplete-crud.ts +580 -0
  34. package/src/rules/index.ts +219 -18
  35. package/src/rules/intent-propagation.ts +127 -0
  36. package/src/rules/layer-field-name-drift.ts +96 -0
  37. package/src/rules/metadata.ts +654 -0
  38. package/src/rules/missing-reconcile.ts +98 -0
  39. package/src/rules/missing-visibility.ts +110 -0
  40. package/src/rules/no-destructured-compose.ts +192 -0
  41. package/src/rules/no-dev-permit-in-source.ts +99 -0
  42. package/src/rules/no-direct-implementation-call.ts +7 -7
  43. package/src/rules/no-legacy-layer-imports.ts +211 -0
  44. package/src/rules/no-native-error-result.ts +111 -0
  45. package/src/rules/no-redundant-result-error-wrap.ts +331 -0
  46. package/src/rules/no-retired-cross-vocabulary.ts +194 -0
  47. package/src/rules/no-sync-result-assumption.ts +1134 -99
  48. package/src/rules/no-throw-in-detour-recover.ts +225 -0
  49. package/src/rules/no-throw-in-implementation.ts +10 -9
  50. package/src/rules/no-top-level-surface.ts +389 -0
  51. package/src/rules/on-references-exist.ts +194 -0
  52. package/src/rules/orphaned-signal.ts +150 -0
  53. package/src/rules/owner-projection-parity.ts +146 -0
  54. package/src/rules/permit-governance.ts +25 -0
  55. package/src/rules/public-export-example-coverage.ts +553 -0
  56. package/src/rules/public-internal-deep-imports.ts +517 -0
  57. package/src/rules/public-output-schema.ts +29 -0
  58. package/src/rules/public-union-output-discriminants.ts +150 -0
  59. package/src/rules/read-intent-fires.ts +187 -0
  60. package/src/rules/reference-exists.ts +98 -0
  61. package/src/rules/registry-names.ts +145 -0
  62. package/src/rules/resolved-import-boundary.ts +146 -0
  63. package/src/rules/resource-declarations.ts +704 -0
  64. package/src/rules/resource-exists.ts +179 -0
  65. package/src/rules/resource-id-grammar.ts +65 -0
  66. package/src/rules/resource-mock-coverage.ts +115 -0
  67. package/src/rules/scan.ts +38 -25
  68. package/src/rules/scheduled-destroy-intent.ts +44 -0
  69. package/src/rules/signal-graph-coaching.ts +191 -0
  70. package/src/rules/specs.ts +9 -5
  71. package/src/rules/static-resource-accessor-preference.ts +657 -0
  72. package/src/rules/surface-facet-coherence.ts +370 -0
  73. package/src/rules/trail-versioning-source.ts +1094 -0
  74. package/src/rules/trail-versioning-topo.ts +172 -0
  75. package/src/rules/types.ts +270 -6
  76. package/src/rules/unmaterialized-activation-source.ts +84 -0
  77. package/src/rules/unreachable-detour-shadowing.ts +344 -0
  78. package/src/rules/valid-describe-refs.ts +160 -32
  79. package/src/rules/valid-detour-contract.ts +78 -0
  80. package/src/rules/warden-export-symmetry.ts +533 -0
  81. package/src/rules/warden-rules-use-ast.ts +996 -0
  82. package/src/rules/webhook-route-collision.ts +243 -0
  83. package/src/trails/activation-orphan.trail.ts +84 -0
  84. package/src/trails/circular-refs.trail.ts +29 -0
  85. package/src/trails/composes-declarations.trail.ts +22 -0
  86. package/src/trails/context-no-surface-types.trail.ts +21 -0
  87. package/src/trails/contour-exists.trail.ts +21 -0
  88. package/src/trails/dead-internal-trail.trail.ts +26 -0
  89. package/src/trails/deprecation-without-guidance.trail.ts +21 -0
  90. package/src/trails/draft-file-marking.trail.ts +16 -0
  91. package/src/trails/draft-visible-debt.trail.ts +16 -0
  92. package/src/trails/error-mapping-completeness.trail.ts +29 -0
  93. package/src/trails/example-valid.trail.ts +25 -0
  94. package/src/trails/fires-declarations.trail.ts +23 -0
  95. package/src/trails/fork-without-preserved-blaze.trail.ts +31 -0
  96. package/src/trails/implementation-returns-result.trail.ts +20 -0
  97. package/src/trails/incomplete-accessor-for-standard-op.trail.ts +76 -0
  98. package/src/trails/incomplete-crud.trail.ts +39 -0
  99. package/src/trails/index.ts +78 -0
  100. package/src/trails/intent-propagation.trail.ts +30 -0
  101. package/src/trails/layer-field-name-drift.trail.ts +39 -0
  102. package/src/trails/marker-schema-unsupported.trail.ts +23 -0
  103. package/src/trails/missing-reconcile.trail.ts +33 -0
  104. package/src/trails/missing-visibility.trail.ts +22 -0
  105. package/src/trails/no-destructured-compose.trail.ts +44 -0
  106. package/src/trails/no-dev-permit-in-source.trail.ts +16 -0
  107. package/src/trails/no-direct-implementation-call.trail.ts +16 -0
  108. package/src/trails/no-legacy-layer-imports.trail.ts +41 -0
  109. package/src/trails/no-native-error-result.trail.ts +18 -0
  110. package/src/trails/no-redundant-result-error-wrap.trail.ts +55 -0
  111. package/src/trails/no-retired-cross-vocabulary.trail.ts +42 -0
  112. package/src/trails/no-sync-result-assumption.trail.ts +19 -0
  113. package/src/trails/no-throw-in-detour-recover.trail.ts +24 -0
  114. package/src/trails/no-throw-in-implementation.trail.ts +20 -0
  115. package/src/trails/no-top-level-surface.trail.ts +43 -0
  116. package/src/trails/on-references-exist.trail.ts +21 -0
  117. package/src/trails/orphaned-signal.trail.ts +36 -0
  118. package/src/trails/owner-projection-parity.trail.ts +26 -0
  119. package/src/trails/pending-force.trail.ts +21 -0
  120. package/src/trails/permit-governance.trail.ts +51 -0
  121. package/src/trails/prefer-schema-inference.trail.ts +21 -0
  122. package/src/trails/public-export-example-coverage.trail.ts +16 -0
  123. package/src/trails/public-internal-deep-imports.trail.ts +94 -0
  124. package/src/trails/public-output-schema.trail.ts +55 -0
  125. package/src/trails/public-union-output-discriminants.trail.ts +33 -0
  126. package/src/trails/read-intent-fires.trail.ts +20 -0
  127. package/src/trails/reference-exists.trail.ts +25 -0
  128. package/src/trails/resolved-import-boundary.trail.ts +109 -0
  129. package/src/trails/resource-declarations.trail.ts +25 -0
  130. package/src/trails/resource-exists.trail.ts +27 -0
  131. package/src/trails/resource-id-grammar.trail.ts +39 -0
  132. package/src/trails/resource-mock-coverage.trail.ts +40 -0
  133. package/src/trails/run.ts +162 -0
  134. package/src/trails/scheduled-destroy-intent.trail.ts +56 -0
  135. package/src/trails/schema.ts +194 -0
  136. package/src/trails/signal-graph-coaching.trail.ts +77 -0
  137. package/src/trails/static-resource-accessor-preference.trail.ts +25 -0
  138. package/src/trails/surface-facet-coherence.trail.ts +25 -0
  139. package/src/trails/topo.ts +6 -0
  140. package/src/trails/unmaterialized-activation-source.trail.ts +72 -0
  141. package/src/trails/unreachable-detour-shadowing.trail.ts +45 -0
  142. package/src/trails/valid-describe-refs.trail.ts +18 -0
  143. package/src/trails/valid-detour-contract.trail.ts +71 -0
  144. package/src/trails/version-gap.trail.ts +35 -0
  145. package/src/trails/version-pinned-compose.trail.ts +23 -0
  146. package/src/trails/version-without-examples.trail.ts +38 -0
  147. package/src/trails/warden-export-symmetry.trail.ts +16 -0
  148. package/src/trails/warden-rules-use-ast.trail.ts +45 -0
  149. package/src/trails/webhook-route-collision.trail.ts +50 -0
  150. package/src/trails/wrap-rule.ts +213 -0
  151. package/src/workspaces.ts +238 -0
  152. package/.turbo/turbo-build.log +0 -1
  153. package/.turbo/turbo-lint.log +0 -3
  154. package/.turbo/turbo-typecheck.log +0 -1
  155. package/dist/cli.d.ts +0 -46
  156. package/dist/cli.d.ts.map +0 -1
  157. package/dist/cli.js +0 -221
  158. package/dist/cli.js.map +0 -1
  159. package/dist/drift.d.ts +0 -26
  160. package/dist/drift.d.ts.map +0 -1
  161. package/dist/drift.js +0 -27
  162. package/dist/drift.js.map +0 -1
  163. package/dist/formatters.d.ts +0 -29
  164. package/dist/formatters.d.ts.map +0 -1
  165. package/dist/formatters.js +0 -87
  166. package/dist/formatters.js.map +0 -1
  167. package/dist/index.d.ts +0 -26
  168. package/dist/index.d.ts.map +0 -1
  169. package/dist/index.js +0 -26
  170. package/dist/index.js.map +0 -1
  171. package/dist/rules/ast.d.ts +0 -41
  172. package/dist/rules/ast.d.ts.map +0 -1
  173. package/dist/rules/ast.js +0 -163
  174. package/dist/rules/ast.js.map +0 -1
  175. package/dist/rules/context-no-surface-types.d.ts +0 -12
  176. package/dist/rules/context-no-surface-types.d.ts.map +0 -1
  177. package/dist/rules/context-no-surface-types.js +0 -96
  178. package/dist/rules/context-no-surface-types.js.map +0 -1
  179. package/dist/rules/implementation-returns-result.d.ts +0 -13
  180. package/dist/rules/implementation-returns-result.d.ts.map +0 -1
  181. package/dist/rules/implementation-returns-result.js +0 -231
  182. package/dist/rules/implementation-returns-result.js.map +0 -1
  183. package/dist/rules/index.d.ts +0 -22
  184. package/dist/rules/index.d.ts.map +0 -1
  185. package/dist/rules/index.js +0 -41
  186. package/dist/rules/index.js.map +0 -1
  187. package/dist/rules/no-direct-impl-in-route.d.ts +0 -12
  188. package/dist/rules/no-direct-impl-in-route.d.ts.map +0 -1
  189. package/dist/rules/no-direct-impl-in-route.js +0 -46
  190. package/dist/rules/no-direct-impl-in-route.js.map +0 -1
  191. package/dist/rules/no-direct-implementation-call.d.ts +0 -12
  192. package/dist/rules/no-direct-implementation-call.d.ts.map +0 -1
  193. package/dist/rules/no-direct-implementation-call.js +0 -39
  194. package/dist/rules/no-direct-implementation-call.js.map +0 -1
  195. package/dist/rules/no-sync-result-assumption.d.ts +0 -6
  196. package/dist/rules/no-sync-result-assumption.d.ts.map +0 -1
  197. package/dist/rules/no-sync-result-assumption.js +0 -98
  198. package/dist/rules/no-sync-result-assumption.js.map +0 -1
  199. package/dist/rules/no-throw-in-detour-target.d.ts +0 -12
  200. package/dist/rules/no-throw-in-detour-target.d.ts.map +0 -1
  201. package/dist/rules/no-throw-in-detour-target.js +0 -87
  202. package/dist/rules/no-throw-in-detour-target.js.map +0 -1
  203. package/dist/rules/no-throw-in-implementation.d.ts +0 -9
  204. package/dist/rules/no-throw-in-implementation.d.ts.map +0 -1
  205. package/dist/rules/no-throw-in-implementation.js +0 -34
  206. package/dist/rules/no-throw-in-implementation.js.map +0 -1
  207. package/dist/rules/prefer-schema-inference.d.ts +0 -7
  208. package/dist/rules/prefer-schema-inference.d.ts.map +0 -1
  209. package/dist/rules/prefer-schema-inference.js +0 -86
  210. package/dist/rules/prefer-schema-inference.js.map +0 -1
  211. package/dist/rules/scan.d.ts +0 -8
  212. package/dist/rules/scan.d.ts.map +0 -1
  213. package/dist/rules/scan.js +0 -32
  214. package/dist/rules/scan.js.map +0 -1
  215. package/dist/rules/specs.d.ts +0 -29
  216. package/dist/rules/specs.d.ts.map +0 -1
  217. package/dist/rules/specs.js +0 -192
  218. package/dist/rules/specs.js.map +0 -1
  219. package/dist/rules/structure.d.ts +0 -13
  220. package/dist/rules/structure.d.ts.map +0 -1
  221. package/dist/rules/structure.js +0 -142
  222. package/dist/rules/structure.js.map +0 -1
  223. package/dist/rules/types.d.ts +0 -52
  224. package/dist/rules/types.d.ts.map +0 -1
  225. package/dist/rules/types.js +0 -2
  226. package/dist/rules/types.js.map +0 -1
  227. package/dist/rules/valid-describe-refs.d.ts +0 -7
  228. package/dist/rules/valid-describe-refs.d.ts.map +0 -1
  229. package/dist/rules/valid-describe-refs.js +0 -51
  230. package/dist/rules/valid-describe-refs.js.map +0 -1
  231. package/dist/rules/valid-detour-refs.d.ts +0 -6
  232. package/dist/rules/valid-detour-refs.d.ts.map +0 -1
  233. package/dist/rules/valid-detour-refs.js +0 -116
  234. package/dist/rules/valid-detour-refs.js.map +0 -1
  235. package/src/__tests__/cli.test.ts +0 -198
  236. package/src/__tests__/drift.test.ts +0 -74
  237. package/src/__tests__/formatters.test.ts +0 -157
  238. package/src/__tests__/implementation-returns-result.test.ts +0 -75
  239. package/src/__tests__/no-direct-implementation-call.test.ts +0 -83
  240. package/src/__tests__/no-sync-result-assumption.test.ts +0 -85
  241. package/src/__tests__/no-throw-in-detour-target.test.ts +0 -78
  242. package/src/__tests__/prefer-schema-inference.test.ts +0 -84
  243. package/src/__tests__/rules.test.ts +0 -188
  244. package/src/__tests__/valid-describe-refs.test.ts +0 -60
  245. package/src/rules/no-direct-impl-in-route.ts +0 -77
  246. package/src/rules/no-throw-in-detour-target.ts +0 -150
  247. package/src/rules/valid-detour-refs.ts +0 -187
  248. package/tsconfig.json +0 -9
  249. package/tsconfig.tsbuildinfo +0 -1
@@ -1,142 +0,0 @@
1
- const createState = () => ({
2
- braceDepth: 0,
3
- bracketDepth: 0,
4
- escaped: false,
5
- parenDepth: 0,
6
- quoteMode: null,
7
- });
8
- const enterQuote = (ch) => {
9
- if (ch === "'" || ch === '"' || ch === '`') {
10
- return ch;
11
- }
12
- return null;
13
- };
14
- const clearEscape = (state) => {
15
- if (!state.escaped) {
16
- return false;
17
- }
18
- state.escaped = false;
19
- return true;
20
- };
21
- const beginEscape = (state, ch) => {
22
- if (ch !== '\\') {
23
- return false;
24
- }
25
- state.escaped = true;
26
- return true;
27
- };
28
- const closeQuote = (state, ch) => {
29
- if (ch === state.quoteMode) {
30
- state.quoteMode = null;
31
- }
32
- };
33
- const updateQuotedState = (state, ch) => {
34
- if (state.quoteMode === null) {
35
- return false;
36
- }
37
- if (clearEscape(state)) {
38
- return true;
39
- }
40
- if (beginEscape(state, ch)) {
41
- return true;
42
- }
43
- closeQuote(state, ch);
44
- return true;
45
- };
46
- const STRUCTURAL_DELTAS = {
47
- '(': ['parenDepth', 1],
48
- ')': ['parenDepth', -1],
49
- '[': ['bracketDepth', 1],
50
- ']': ['bracketDepth', -1],
51
- '{': ['braceDepth', 1],
52
- '}': ['braceDepth', -1],
53
- };
54
- const updateStructuralDepth = (state, ch) => {
55
- if (!(ch in STRUCTURAL_DELTAS)) {
56
- return;
57
- }
58
- const delta = STRUCTURAL_DELTAS[ch];
59
- const [key, amount] = delta;
60
- state[key] += amount;
61
- };
62
- const isTopLevel = (state) => state.braceDepth === 0 &&
63
- state.bracketDepth === 0 &&
64
- state.parenDepth === 0 &&
65
- state.quoteMode === null;
66
- const scanCharacter = (state, ch) => {
67
- if (updateQuotedState(state, ch)) {
68
- return;
69
- }
70
- const nextQuoteMode = enterQuote(ch);
71
- if (nextQuoteMode !== null) {
72
- state.quoteMode = nextQuoteMode;
73
- return;
74
- }
75
- updateStructuralDepth(state, ch);
76
- };
77
- const isBalancedOpener = (ch) => ch === '{' || ch === '[' || ch === '(';
78
- const appendBalancedCharacter = (sourceText, state, index, text) => {
79
- const ch = sourceText[index];
80
- if (!ch) {
81
- return text;
82
- }
83
- scanCharacter(state, ch);
84
- return `${text}${ch}`;
85
- };
86
- export const captureBalanced = (sourceText, startIndex) => {
87
- if (!isBalancedOpener(sourceText[startIndex])) {
88
- return null;
89
- }
90
- const state = createState();
91
- let text = '';
92
- for (let index = startIndex; index < sourceText.length; index += 1) {
93
- text = appendBalancedCharacter(sourceText, state, index, text);
94
- if (index > startIndex && isTopLevel(state)) {
95
- return { end: index, text };
96
- }
97
- }
98
- return null;
99
- };
100
- export const lineNumberAt = (sourceText, startIndex) => sourceText.slice(0, startIndex).split('\n').length;
101
- const createSplitEntry = (sourceText, startIndex, endIndex) => {
102
- const raw = sourceText.slice(startIndex, endIndex);
103
- const firstContent = raw.search(/\S/);
104
- if (firstContent === -1) {
105
- return null;
106
- }
107
- const trailingWhitespace = raw.match(/\s*$/)?.[0].length ?? 0;
108
- const trimmedEnd = raw.length - trailingWhitespace;
109
- return {
110
- start: startIndex + firstContent,
111
- text: raw.slice(firstContent, trimmedEnd),
112
- };
113
- };
114
- const pushSplitEntry = (entries, sourceText, startIndex, endIndex) => {
115
- const entry = createSplitEntry(sourceText, startIndex, endIndex);
116
- if (entry !== null) {
117
- entries.push(entry);
118
- }
119
- };
120
- const processSplitCharacter = (entries, sourceText, state, entryStart, index) => {
121
- const ch = sourceText[index];
122
- if (!ch) {
123
- return entryStart;
124
- }
125
- if (ch === ',' && isTopLevel(state)) {
126
- pushSplitEntry(entries, sourceText, entryStart, index);
127
- return index + 1;
128
- }
129
- scanCharacter(state, ch);
130
- return entryStart;
131
- };
132
- export const splitTopLevelEntriesWithOffsets = (sourceText) => {
133
- const entries = [];
134
- const state = createState();
135
- let entryStart = 0;
136
- for (let index = 0; index < sourceText.length; index += 1) {
137
- entryStart = processSplitCharacter(entries, sourceText, state, entryStart, index);
138
- }
139
- pushSplitEntry(entries, sourceText, entryStart, sourceText.length);
140
- return entries;
141
- };
142
- //# sourceMappingURL=structure.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"structure.js","sourceRoot":"","sources":["../../src/rules/structure.ts"],"names":[],"mappings":"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"}
@@ -1,52 +0,0 @@
1
- /**
2
- * Severity level for warden diagnostics.
3
- */
4
- export type WardenSeverity = 'error' | 'warn';
5
- /**
6
- * A single diagnostic reported by a warden rule.
7
- */
8
- export interface WardenDiagnostic {
9
- /** Rule identifier, e.g. "no-throw-in-implementation" */
10
- readonly rule: string;
11
- /** Severity level */
12
- readonly severity: WardenSeverity;
13
- /** Human-readable message describing the violation */
14
- readonly message: string;
15
- /** 1-based line number where the violation was detected */
16
- readonly line: number;
17
- /** File path that was analyzed */
18
- readonly filePath: string;
19
- }
20
- /**
21
- * A warden rule is a function that analyzes source code and returns diagnostics.
22
- *
23
- * Rules use string/regex analysis (not full AST parsing) to detect patterns
24
- * that violate Trails conventions.
25
- */
26
- export interface WardenRule {
27
- /** Unique rule identifier */
28
- readonly name: string;
29
- /** Default severity */
30
- readonly severity: WardenSeverity;
31
- /** Human-readable description of what the rule enforces */
32
- readonly description: string;
33
- /** Run the rule against source code and return any diagnostics */
34
- readonly check: (sourceCode: string, filePath: string) => readonly WardenDiagnostic[];
35
- }
36
- /**
37
- * Options for cross-file rules that need knowledge of all trail IDs in a project.
38
- */
39
- export interface ProjectContext {
40
- /** All known trail IDs in the project */
41
- readonly knownTrailIds: ReadonlySet<string>;
42
- /** All trail IDs referenced as detour targets across the project */
43
- readonly detourTargetTrailIds?: ReadonlySet<string>;
44
- }
45
- /**
46
- * A project-aware rule that requires knowledge of all trail IDs.
47
- */
48
- export interface ProjectAwareWardenRule extends WardenRule {
49
- /** Run the rule with project-level context */
50
- readonly checkWithContext: (sourceCode: string, filePath: string, context: ProjectContext) => readonly WardenDiagnostic[];
51
- }
52
- //# sourceMappingURL=types.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":"AAAA;;GAEG;AACH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,CAAC;AAE9C;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,yDAAyD;IACzD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,qBAAqB;IACrB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,sDAAsD;IACtD,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAC;IACzB,2DAA2D;IAC3D,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,kCAAkC;IAClC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAC;CAC3B;AAED;;;;;GAKG;AACH,MAAM,WAAW,UAAU;IACzB,6BAA6B;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IACtB,uBAAuB;IACvB,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,2DAA2D;IAC3D,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,kEAAkE;IAClE,QAAQ,CAAC,KAAK,EAAE,CACd,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,KACb,SAAS,gBAAgB,EAAE,CAAC;CAClC;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,yCAAyC;IACzC,QAAQ,CAAC,aAAa,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;IAC5C,oEAAoE;IACpE,QAAQ,CAAC,oBAAoB,CAAC,EAAE,WAAW,CAAC,MAAM,CAAC,CAAC;CACrD;AAED;;GAEG;AACH,MAAM,WAAW,sBAAuB,SAAQ,UAAU;IACxD,8CAA8C;IAC9C,QAAQ,CAAC,gBAAgB,EAAE,CACzB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,cAAc,KACpB,SAAS,gBAAgB,EAAE,CAAC;CAClC"}
@@ -1,2 +0,0 @@
1
- export {};
2
- //# sourceMappingURL=types.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/rules/types.ts"],"names":[],"mappings":""}
@@ -1,7 +0,0 @@
1
- import type { ProjectAwareWardenRule } from './types.js';
2
- /**
3
- * Warns when @see references inside Zod .describe() strings point at unknown
4
- * trails.
5
- */
6
- export declare const validDescribeRefs: ProjectAwareWardenRule;
7
- //# sourceMappingURL=valid-describe-refs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"valid-describe-refs.d.ts","sourceRoot":"","sources":["../../src/rules/valid-describe-refs.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAsEpB;;;GAGG;AACH,eAAO,MAAM,iBAAiB,EAAE,sBAe/B,CAAC"}
@@ -1,51 +0,0 @@
1
- import { isTestFile } from './scan.js';
2
- import { collectTrailIds, parseStringLiteral } from './specs.js';
3
- import { captureBalanced, lineNumberAt } from './structure.js';
4
- const DESCRIBE_PATTERN = /\.describe\s*\(/g;
5
- const SEE_PATTERN = /@see\s+([A-Za-z0-9_.-]+)/g;
6
- const describeTextAt = (sourceCode, matchIndex) => {
7
- const openParen = sourceCode.indexOf('(', matchIndex);
8
- if (openParen === -1) {
9
- return null;
10
- }
11
- return captureBalanced(sourceCode, openParen)?.text.slice(1, -1) ?? null;
12
- };
13
- const refsInDescription = (description, line) => [...description.matchAll(SEE_PATTERN)].flatMap((see) => see[1] ? [{ line, ref: see[1] }] : []);
14
- const refsForDescribe = (sourceCode, matchIndex) => {
15
- const args = describeTextAt(sourceCode, matchIndex);
16
- const description = args ? parseStringLiteral(args) : null;
17
- return description === null
18
- ? []
19
- : refsInDescription(description, lineNumberAt(sourceCode, matchIndex));
20
- };
21
- const collectDescribeRefs = (sourceCode) => [...sourceCode.matchAll(DESCRIBE_PATTERN)].flatMap((match) => match.index === undefined ? [] : refsForDescribe(sourceCode, match.index));
22
- const checkDescribeRefs = (sourceCode, filePath, knownTrailIds) => {
23
- if (isTestFile(filePath)) {
24
- return [];
25
- }
26
- return collectDescribeRefs(sourceCode)
27
- .filter(({ ref }) => !knownTrailIds.has(ref))
28
- .map(({ line, ref }) => ({
29
- filePath,
30
- line,
31
- message: `@see reference "${ref}" does not resolve to a defined trail.`,
32
- rule: 'valid-describe-refs',
33
- severity: 'warn',
34
- }));
35
- };
36
- /**
37
- * Warns when @see references inside Zod .describe() strings point at unknown
38
- * trails.
39
- */
40
- export const validDescribeRefs = {
41
- check(sourceCode, filePath) {
42
- return checkDescribeRefs(sourceCode, filePath, collectTrailIds(sourceCode));
43
- },
44
- checkWithContext(sourceCode, filePath, context) {
45
- return checkDescribeRefs(sourceCode, filePath, context.knownTrailIds);
46
- },
47
- description: 'Ensure @see tags inside schema .describe() strings reference defined trails.',
48
- name: 'valid-describe-refs',
49
- severity: 'warn',
50
- };
51
- //# sourceMappingURL=valid-describe-refs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"valid-describe-refs.js","sourceRoot":"","sources":["../../src/rules/valid-describe-refs.ts"],"names":[],"mappings":"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"}
@@ -1,6 +0,0 @@
1
- import type { ProjectAwareWardenRule } from './types.js';
2
- /**
3
- * Checks that all trail IDs referenced in `detours` declarations exist.
4
- */
5
- export declare const validDetourRefs: ProjectAwareWardenRule;
6
- //# sourceMappingURL=valid-detour-refs.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"valid-detour-refs.d.ts","sourceRoot":"","sources":["../../src/rules/valid-detour-refs.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EACV,sBAAsB,EAGvB,MAAM,YAAY,CAAC;AAoKpB;;GAEG;AACH,eAAO,MAAM,eAAe,EAAE,sBAc7B,CAAC"}
@@ -1,116 +0,0 @@
1
- import { collectTrailIds } from './specs.js';
2
- const trackBraces = (line, state) => {
3
- for (const ch of line) {
4
- if (ch === '{') {
5
- state.depth += 1;
6
- state.found = true;
7
- }
8
- if (ch === '}') {
9
- state.depth -= 1;
10
- }
11
- }
12
- };
13
- const collectArrayText = (lines, start) => {
14
- let text = '';
15
- for (let k = start; k < lines.length && k < start + 20; k += 1) {
16
- const line = lines[k];
17
- if (!line) {
18
- continue;
19
- }
20
- text += `${line}\n`;
21
- if (text.includes(']')) {
22
- break;
23
- }
24
- }
25
- return text;
26
- };
27
- const findMissingDetourTargets = (text, knownIds) => {
28
- const missing = [];
29
- for (const m of text.matchAll(/target\s*:\s*["'`]([^"'`]+)["'`]/g)) {
30
- const [, id] = m;
31
- if (id && !knownIds.has(id)) {
32
- missing.push(id);
33
- }
34
- }
35
- return missing;
36
- };
37
- const findMissingPlainDetours = (text, knownIds) => {
38
- const missing = [];
39
- const cleaned = text.replaceAll(/target\s*:\s*["'`][^"'`]+["'`]/g, '');
40
- for (const m of cleaned.matchAll(/["'`]([^"'`]+)["'`]/g)) {
41
- const [, id] = m;
42
- if (id && id.includes('.') && !knownIds.has(id)) {
43
- missing.push(id);
44
- }
45
- }
46
- return missing;
47
- };
48
- const findAllMissingDetours = (text, knownIds) => [
49
- ...findMissingDetourTargets(text, knownIds),
50
- ...findMissingPlainDetours(text, knownIds),
51
- ];
52
- const addMissingDetourDiagnostics = (specLine, j, lines, trailId, lineNum, filePath, knownIds, diagnostics) => {
53
- if (!/\bdetours\s*:/.test(specLine)) {
54
- return;
55
- }
56
- for (const targetId of findAllMissingDetours(collectArrayText(lines, j), knownIds)) {
57
- diagnostics.push({
58
- filePath,
59
- line: lineNum,
60
- message: `Trail "${trailId}" has detour targeting "${targetId}" which is not defined.`,
61
- rule: 'valid-detour-refs',
62
- severity: 'error',
63
- });
64
- }
65
- };
66
- const scanTrailDetours = (lines, startIndex, trailId, filePath, knownIds, diagnostics) => {
67
- const braceState = { depth: 0, found: false };
68
- for (let j = startIndex; j < lines.length && j < startIndex + 200; j += 1) {
69
- const specLine = lines[j];
70
- if (!specLine) {
71
- continue;
72
- }
73
- trackBraces(specLine, braceState);
74
- addMissingDetourDiagnostics(specLine, j, lines, trailId, startIndex + 1, filePath, knownIds, diagnostics);
75
- if (braceState.found && braceState.depth <= 0) {
76
- break;
77
- }
78
- }
79
- };
80
- const processLine = (line, i, lines, filePath, knownIds, diagnostics) => {
81
- const trailMatch = line.match(/\btrail\s*\(\s*["'`]([^"'`]+)["'`]/);
82
- if (!trailMatch) {
83
- return;
84
- }
85
- const [, trailId] = trailMatch;
86
- if (!trailId) {
87
- return;
88
- }
89
- scanTrailDetours(lines, i, trailId, filePath, knownIds, diagnostics);
90
- };
91
- const checkDetourRefs = (sourceCode, filePath, knownIds) => {
92
- const diagnostics = [];
93
- const lines = sourceCode.split('\n');
94
- for (let i = 0; i < lines.length; i += 1) {
95
- const line = lines[i];
96
- if (line) {
97
- processLine(line, i, lines, filePath, knownIds, diagnostics);
98
- }
99
- }
100
- return diagnostics;
101
- };
102
- /**
103
- * Checks that all trail IDs referenced in `detours` declarations exist.
104
- */
105
- export const validDetourRefs = {
106
- check(sourceCode, filePath) {
107
- return checkDetourRefs(sourceCode, filePath, collectTrailIds(sourceCode));
108
- },
109
- checkWithContext(sourceCode, filePath, context) {
110
- return checkDetourRefs(sourceCode, filePath, context.knownTrailIds);
111
- },
112
- description: 'Ensure all detour target trail IDs reference defined trails.',
113
- name: 'valid-detour-refs',
114
- severity: 'error',
115
- };
116
- //# sourceMappingURL=valid-detour-refs.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"valid-detour-refs.js","sourceRoot":"","sources":["../../src/rules/valid-detour-refs.ts"],"names":[],"mappings":"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"}
@@ -1,198 +0,0 @@
1
- import { describe, expect, test } from 'bun:test';
2
- import { mkdirSync, rmSync, writeFileSync } from 'node:fs';
3
- import { tmpdir } from 'node:os';
4
- import { join } from 'node:path';
5
-
6
- import { formatWardenReport, runWarden } from '../cli.js';
7
-
8
- const makeTempDir = (): string => {
9
- const dir = join(
10
- tmpdir(),
11
- `warden-test-${Date.now()}-${Math.random().toString(36).slice(2)}`
12
- );
13
- mkdirSync(dir, { recursive: true });
14
- return dir;
15
- };
16
-
17
- describe('runWarden', () => {
18
- test('produces a report with diagnostics for bad code', async () => {
19
- const dir = makeTempDir();
20
- try {
21
- writeFileSync(
22
- join(dir, 'bad.ts'),
23
- `trail("entity.show", {
24
- implementation: async (input, ctx) => {
25
- throw new Error("boom");
26
- }
27
- })`
28
- );
29
-
30
- const report = await runWarden({ rootDir: dir });
31
- expect(report.errorCount).toBeGreaterThan(0);
32
- expect(report.passed).toBe(false);
33
- } finally {
34
- rmSync(dir, { force: true, recursive: true });
35
- }
36
- });
37
-
38
- test('passes for clean code', async () => {
39
- const dir = makeTempDir();
40
- try {
41
- writeFileSync(
42
- join(dir, 'good.ts'),
43
- `trail("entity.show", {
44
- implementation: async (input, ctx) => {
45
- return Result.ok(data);
46
- }
47
- })`
48
- );
49
-
50
- const report = await runWarden({ rootDir: dir });
51
- expect(report.errorCount).toBe(0);
52
- expect(report.passed).toBe(true);
53
- } finally {
54
- rmSync(dir, { force: true, recursive: true });
55
- }
56
- });
57
-
58
- test('lintOnly skips drift check', async () => {
59
- const dir = makeTempDir();
60
- try {
61
- writeFileSync(join(dir, 'empty.ts'), 'export {}');
62
- const report = await runWarden({ lintOnly: true, rootDir: dir });
63
- expect(report.drift).toBeNull();
64
- } finally {
65
- rmSync(dir, { force: true, recursive: true });
66
- }
67
- });
68
-
69
- test('driftOnly skips lint', async () => {
70
- const dir = makeTempDir();
71
- try {
72
- // Even with bad code, driftOnly should produce 0 diagnostics
73
- writeFileSync(
74
- join(dir, 'bad.ts'),
75
- `trail("x", { implementation: async () => { throw new Error("x"); } })`
76
- );
77
- const report = await runWarden({ driftOnly: true, rootDir: dir });
78
- expect(report.diagnostics.length).toBe(0);
79
- expect(report.drift).not.toBeNull();
80
- } finally {
81
- rmSync(dir, { force: true, recursive: true });
82
- }
83
- });
84
-
85
- test('uses project context for detour references across files', async () => {
86
- const dir = makeTempDir();
87
- try {
88
- writeFileSync(
89
- join(dir, 'show.ts'),
90
- `trail("entity.show", {
91
- detours: { NotFoundError: ["entity.search"] },
92
- implementation: async (input, ctx) => {
93
- return Result.ok(data);
94
- }
95
- })`
96
- );
97
- writeFileSync(
98
- join(dir, 'search.ts'),
99
- `trail("entity.search", {
100
- implementation: async (input, ctx) => {
101
- return Result.ok(data);
102
- }
103
- })`
104
- );
105
-
106
- const report = await runWarden({ rootDir: dir });
107
- const detourRefErrors = report.diagnostics.filter(
108
- (diagnostic) => diagnostic.rule === 'valid-detour-refs'
109
- );
110
-
111
- expect(detourRefErrors).toHaveLength(0);
112
- } finally {
113
- rmSync(dir, { force: true, recursive: true });
114
- }
115
- });
116
-
117
- test('flags throws in detour targets declared in another file', async () => {
118
- const dir = makeTempDir();
119
- try {
120
- writeFileSync(
121
- join(dir, 'show.ts'),
122
- `trail("entity.show", {
123
- detours: { NotFoundError: ["entity.search"] },
124
- implementation: async (input, ctx) => {
125
- return Result.ok(data);
126
- }
127
- })`
128
- );
129
- writeFileSync(
130
- join(dir, 'search.ts'),
131
- `trail("entity.search", {
132
- implementation: async (input, ctx) => {
133
- throw new Error("boom");
134
- }
135
- })`
136
- );
137
-
138
- const report = await runWarden({ rootDir: dir });
139
- const detourThrowRules = report.diagnostics.filter(
140
- (diagnostic) => diagnostic.rule === 'no-throw-in-detour-target'
141
- );
142
-
143
- expect(detourThrowRules).toHaveLength(1);
144
- expect(detourThrowRules[0]?.message).toContain('entity.search');
145
- } finally {
146
- rmSync(dir, { force: true, recursive: true });
147
- }
148
- });
149
- });
150
-
151
- describe('formatWardenReport', () => {
152
- test('formats a clean report', () => {
153
- const output = formatWardenReport({
154
- diagnostics: [],
155
- drift: { committedHash: null, currentHash: 'stub', stale: false },
156
- errorCount: 0,
157
- passed: true,
158
- warnCount: 0,
159
- });
160
- expect(output).toContain('Warden Report');
161
- expect(output).toContain('Lint: clean');
162
- expect(output).toContain('Drift: clean');
163
- expect(output).toContain('Result: PASS');
164
- });
165
-
166
- test('formats a report with errors', () => {
167
- const output = formatWardenReport({
168
- diagnostics: [
169
- {
170
- filePath: 'src/trails/entity.ts',
171
- line: 3,
172
- message: 'Do not throw inside implementation.',
173
- rule: 'no-throw-in-implementation',
174
- severity: 'error',
175
- },
176
- ],
177
- drift: { committedHash: null, currentHash: 'stub', stale: false },
178
- errorCount: 1,
179
- passed: false,
180
- warnCount: 0,
181
- });
182
- expect(output).toContain('1 errors');
183
- expect(output).toContain('Result: FAIL');
184
- expect(output).toContain('entity.ts:3');
185
- });
186
-
187
- test('formats a report with stale drift', () => {
188
- const output = formatWardenReport({
189
- diagnostics: [],
190
- drift: { committedHash: 'abc', currentHash: 'def', stale: true },
191
- errorCount: 0,
192
- passed: false,
193
- warnCount: 0,
194
- });
195
- expect(output).toContain('surface.lock is stale');
196
- expect(output).toContain('Result: FAIL');
197
- });
198
- });