@agentvibes/guardrails 0.1.0

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 (260) hide show
  1. package/README.md +239 -0
  2. package/candidates/README.md +30 -0
  3. package/candidates/r10-as-cast.yml +24 -0
  4. package/candidates/r1d-scattered-numeric-const-in-component.yml +13 -0
  5. package/candidates/r2-helper-fn-in-tsx.yml +22 -0
  6. package/candidates/r3-hooks-outside-layout.yml +21 -0
  7. package/candidates/r6-jsx-comment-smell.yml +14 -0
  8. package/candidates/r7-raw-hsl-outside-tokens.yml +17 -0
  9. package/candidates/r8-inline-style-prop.yml +13 -0
  10. package/candidates/r9-optional-store-arg.yml +24 -0
  11. package/configs/biome.json +96 -0
  12. package/configs/tsconfig.base.json +21 -0
  13. package/dist/astGrep.d.ts +16 -0
  14. package/dist/astGrep.js +48 -0
  15. package/dist/astGrep.js.map +1 -0
  16. package/dist/cli.d.ts +2 -0
  17. package/dist/cli.js +138 -0
  18. package/dist/cli.js.map +1 -0
  19. package/dist/deploy.d.ts +1 -0
  20. package/dist/deploy.js +34 -0
  21. package/dist/deploy.js.map +1 -0
  22. package/dist/doctor.d.ts +6 -0
  23. package/dist/doctor.js +102 -0
  24. package/dist/doctor.js.map +1 -0
  25. package/dist/fileWalk.d.ts +2 -0
  26. package/dist/fileWalk.js +45 -0
  27. package/dist/fileWalk.js.map +1 -0
  28. package/dist/findings.d.ts +12 -0
  29. package/dist/findings.js +8 -0
  30. package/dist/findings.js.map +1 -0
  31. package/dist/gateRed.d.ts +1 -0
  32. package/dist/gateRed.js +93 -0
  33. package/dist/gateRed.js.map +1 -0
  34. package/dist/gitDiff.d.ts +18 -0
  35. package/dist/gitDiff.js +90 -0
  36. package/dist/gitDiff.js.map +1 -0
  37. package/dist/hookPostedit.d.ts +1 -0
  38. package/dist/hookPostedit.js +117 -0
  39. package/dist/hookPostedit.js.map +1 -0
  40. package/dist/hookStop.d.ts +1 -0
  41. package/dist/hookStop.js +56 -0
  42. package/dist/hookStop.js.map +1 -0
  43. package/dist/hookStopTest.d.ts +1 -0
  44. package/dist/hookStopTest.js +71 -0
  45. package/dist/hookStopTest.js.map +1 -0
  46. package/dist/init.d.ts +24 -0
  47. package/dist/init.js +172 -0
  48. package/dist/init.js.map +1 -0
  49. package/dist/initTest.d.ts +1 -0
  50. package/dist/initTest.js +88 -0
  51. package/dist/initTest.js.map +1 -0
  52. package/dist/iterate.d.ts +9 -0
  53. package/dist/iterate.js +79 -0
  54. package/dist/iterate.js.map +1 -0
  55. package/dist/iterateTest.d.ts +1 -0
  56. package/dist/iterateTest.js +91 -0
  57. package/dist/iterateTest.js.map +1 -0
  58. package/dist/leakPatterns.d.ts +5 -0
  59. package/dist/leakPatterns.js +22 -0
  60. package/dist/leakPatterns.js.map +1 -0
  61. package/dist/leaks.d.ts +8 -0
  62. package/dist/leaks.js +211 -0
  63. package/dist/leaks.js.map +1 -0
  64. package/dist/leaksRed.d.ts +1 -0
  65. package/dist/leaksRed.js +62 -0
  66. package/dist/leaksRed.js.map +1 -0
  67. package/dist/metrics.d.ts +10 -0
  68. package/dist/metrics.js +113 -0
  69. package/dist/metrics.js.map +1 -0
  70. package/dist/metricsAggregate.d.ts +5 -0
  71. package/dist/metricsAggregate.js +78 -0
  72. package/dist/metricsAggregate.js.map +1 -0
  73. package/dist/metricsBaseline.d.ts +21 -0
  74. package/dist/metricsBaseline.js +88 -0
  75. package/dist/metricsBaseline.js.map +1 -0
  76. package/dist/metricsCollect.d.ts +8 -0
  77. package/dist/metricsCollect.js +295 -0
  78. package/dist/metricsCollect.js.map +1 -0
  79. package/dist/metricsCycle.d.ts +1 -0
  80. package/dist/metricsCycle.js +79 -0
  81. package/dist/metricsCycle.js.map +1 -0
  82. package/dist/metricsTypes.d.ts +102 -0
  83. package/dist/metricsTypes.js +2 -0
  84. package/dist/metricsTypes.js.map +1 -0
  85. package/dist/packagePaths.d.ts +7 -0
  86. package/dist/packagePaths.js +11 -0
  87. package/dist/packagePaths.js.map +1 -0
  88. package/dist/pluginApi.d.ts +24 -0
  89. package/dist/pluginApi.js +12 -0
  90. package/dist/pluginApi.js.map +1 -0
  91. package/dist/pluginResolve.d.ts +6 -0
  92. package/dist/pluginResolve.js +48 -0
  93. package/dist/pluginResolve.js.map +1 -0
  94. package/dist/screenScope.d.ts +21 -0
  95. package/dist/screenScope.js +81 -0
  96. package/dist/screenScope.js.map +1 -0
  97. package/dist/screenScopeTest.d.ts +1 -0
  98. package/dist/screenScopeTest.js +116 -0
  99. package/dist/screenScopeTest.js.map +1 -0
  100. package/dist/severity.d.ts +9 -0
  101. package/dist/severity.js +62 -0
  102. package/dist/severity.js.map +1 -0
  103. package/dist/severityTest.d.ts +1 -0
  104. package/dist/severityTest.js +63 -0
  105. package/dist/severityTest.js.map +1 -0
  106. package/dist/sourceLines.d.ts +9 -0
  107. package/dist/sourceLines.js +52 -0
  108. package/dist/sourceLines.js.map +1 -0
  109. package/dist/structure.d.ts +2 -0
  110. package/dist/structure.js +98 -0
  111. package/dist/structure.js.map +1 -0
  112. package/dist/testRules.d.ts +1 -0
  113. package/dist/testRules.js +285 -0
  114. package/dist/testRules.js.map +1 -0
  115. package/dist/textGrep.d.ts +2 -0
  116. package/dist/textGrep.js +52 -0
  117. package/dist/textGrep.js.map +1 -0
  118. package/dist/tomlTable.d.ts +2 -0
  119. package/dist/tomlTable.js +26 -0
  120. package/dist/tomlTable.js.map +1 -0
  121. package/dist/toolResolve.d.ts +18 -0
  122. package/dist/toolResolve.js +50 -0
  123. package/dist/toolResolve.js.map +1 -0
  124. package/dist/verify.d.ts +3 -0
  125. package/dist/verify.js +49 -0
  126. package/dist/verify.js.map +1 -0
  127. package/dist/verifyDiff.d.ts +18 -0
  128. package/dist/verifyDiff.js +126 -0
  129. package/dist/verifyDiff.js.map +1 -0
  130. package/dist/workspaces.d.ts +6 -0
  131. package/dist/workspaces.js +84 -0
  132. package/dist/workspaces.js.map +1 -0
  133. package/mise.toml +9 -0
  134. package/package.json +62 -0
  135. package/rules/__fixtures__/as-any-escape/bad.ts +8 -0
  136. package/rules/__fixtures__/as-any-escape/good.ts +14 -0
  137. package/rules/__fixtures__/catch-empty/bad.ts +7 -0
  138. package/rules/__fixtures__/catch-empty/good.ts +14 -0
  139. package/rules/__fixtures__/direct-store-import/bad.tsx +23 -0
  140. package/rules/__fixtures__/direct-store-import/good.tsx +34 -0
  141. package/rules/__fixtures__/direct-store-import/showcase/ignored.tsx +9 -0
  142. package/rules/__fixtures__/discriminator-ternary/bad.tsx +10 -0
  143. package/rules/__fixtures__/discriminator-ternary/good.tsx +23 -0
  144. package/rules/__fixtures__/hardcoded-url-in-component/components/bad.tsx +8 -0
  145. package/rules/__fixtures__/hardcoded-url-in-component/components/good.tsx +14 -0
  146. package/rules/__fixtures__/inline-map-row/bad.tsx +72 -0
  147. package/rules/__fixtures__/inline-map-row/good.tsx +51 -0
  148. package/rules/__fixtures__/instanceof-map-set/bad.ts +7 -0
  149. package/rules/__fixtures__/instanceof-map-set/good.ts +8 -0
  150. package/rules/__fixtures__/literal-union-in-component/components/bad.ts +8 -0
  151. package/rules/__fixtures__/literal-union-in-component/components/good.ts +23 -0
  152. package/rules/__fixtures__/missing-observer/bad.tsx +66 -0
  153. package/rules/__fixtures__/missing-observer/good.tsx +69 -0
  154. package/rules/__fixtures__/no-local-kit-clone/bad.ts +30 -0
  155. package/rules/__fixtures__/no-local-kit-clone/bad.tsx +30 -0
  156. package/rules/__fixtures__/no-local-kit-clone/good.ts +31 -0
  157. package/rules/__fixtures__/no-local-kit-clone/good.tsx +31 -0
  158. package/rules/__fixtures__/non-exhaustive-match/bad.ts +8 -0
  159. package/rules/__fixtures__/non-exhaustive-match/good.ts +14 -0
  160. package/rules/__fixtures__/page-store-bare-usememo/bad.ts +15 -0
  161. package/rules/__fixtures__/page-store-bare-usememo/bad.tsx +13 -0
  162. package/rules/__fixtures__/page-store-bare-usememo/good.ts +17 -0
  163. package/rules/__fixtures__/page-store-bare-usememo/good.tsx +14 -0
  164. package/rules/__fixtures__/screen-file-styling/bad.screen.tsx +10 -0
  165. package/rules/__fixtures__/screen-file-styling/good.screen.tsx +8 -0
  166. package/rules/__fixtures__/state-loading-boolean-shape/bad.ts +36 -0
  167. package/rules/__fixtures__/state-loading-boolean-shape/bad.tsx +36 -0
  168. package/rules/__fixtures__/state-loading-boolean-shape/good.ts +44 -0
  169. package/rules/__fixtures__/state-loading-boolean-shape/good.tsx +44 -0
  170. package/rules/__fixtures__/store-async-method/bad.ts +37 -0
  171. package/rules/__fixtures__/store-async-method/bad.tsx +37 -0
  172. package/rules/__fixtures__/store-async-method/good.ts +73 -0
  173. package/rules/__fixtures__/store-async-method/good.tsx +73 -0
  174. package/rules/__fixtures__/store-context-provider/bad.ts +16 -0
  175. package/rules/__fixtures__/store-context-provider/bad.tsx +24 -0
  176. package/rules/__fixtures__/store-context-provider/good.ts +13 -0
  177. package/rules/__fixtures__/store-context-provider/good.tsx +11 -0
  178. package/rules/__fixtures__/store-delegation-getter/bad.ts +30 -0
  179. package/rules/__fixtures__/store-delegation-getter/bad.tsx +30 -0
  180. package/rules/__fixtures__/store-delegation-getter/good.ts +65 -0
  181. package/rules/__fixtures__/store-delegation-getter/good.tsx +65 -0
  182. package/rules/__fixtures__/store-new-map/bad.ts +22 -0
  183. package/rules/__fixtures__/store-new-map/bad.tsx +22 -0
  184. package/rules/__fixtures__/store-new-map/good.ts +41 -0
  185. package/rules/__fixtures__/store-new-map/good.tsx +41 -0
  186. package/rules/__fixtures__/store-no-runinaction/bad.ts +67 -0
  187. package/rules/__fixtures__/store-no-runinaction/bad.tsx +67 -0
  188. package/rules/__fixtures__/store-no-runinaction/good.ts +39 -0
  189. package/rules/__fixtures__/store-no-runinaction/good.tsx +39 -0
  190. package/rules/__fixtures__/store-no-setinterval-poll/bad.ts +19 -0
  191. package/rules/__fixtures__/store-no-setinterval-poll/bad.tsx +19 -0
  192. package/rules/__fixtures__/store-no-setinterval-poll/good.ts +29 -0
  193. package/rules/__fixtures__/store-no-setinterval-poll/good.tsx +29 -0
  194. package/rules/__fixtures__/ts-pattern-dangling-match/bad.ts +20 -0
  195. package/rules/__fixtures__/ts-pattern-dangling-match/good.ts +35 -0
  196. package/rules/__fixtures__/ui-imports-app-store/src/ui/bad.tsx +13 -0
  197. package/rules/__fixtures__/ui-imports-app-store/src/ui/good.tsx +23 -0
  198. package/rules/__fixtures__/view-file-logic/bad.view.tsx +16 -0
  199. package/rules/__fixtures__/view-file-logic/good.view.tsx +7 -0
  200. package/rules/__fixtures__/view-imports-store/bad.view.tsx +13 -0
  201. package/rules/__fixtures__/view-imports-store/good.view.tsx +23 -0
  202. package/rules/__fixtures__/zod-optional-nullable/bad.ts +10 -0
  203. package/rules/__fixtures__/zod-optional-nullable/bad.tsx +17 -0
  204. package/rules/__fixtures__/zod-optional-nullable/good.ts +16 -0
  205. package/rules/__fixtures__/zod-optional-nullable/good.tsx +20 -0
  206. package/rules/as-any-escape-tsx.yml +53 -0
  207. package/rules/as-any-escape.yml +29 -0
  208. package/rules/catch-empty-tsx.yml +55 -0
  209. package/rules/catch-empty.yml +31 -0
  210. package/rules/classname-not-composed.yml +28 -0
  211. package/rules/classname-visual-identity.yml +34 -0
  212. package/rules/demo-mode-by-default-ts.yml +76 -0
  213. package/rules/demo-mode-by-default.yml +54 -0
  214. package/rules/direct-store-import.yml +118 -0
  215. package/rules/discriminator-ternary.yml +70 -0
  216. package/rules/hardcoded-url-in-component.yml +44 -0
  217. package/rules/inline-map-row.yml +107 -0
  218. package/rules/instanceof-map-set-tsx.yml +46 -0
  219. package/rules/instanceof-map-set.yml +22 -0
  220. package/rules/json-roundtrip.yml +9 -0
  221. package/rules/jsx-cond-and.yml +16 -0
  222. package/rules/jsx-ternary.yml +35 -0
  223. package/rules/kind-if-without-match.yml +13 -0
  224. package/rules/literal-union-in-component.yml +71 -0
  225. package/rules/match-bool-to-null.yml +15 -0
  226. package/rules/missing-observer.yml +189 -0
  227. package/rules/mobx-effect-observable-dep.yml +23 -0
  228. package/rules/mobx-effect-store-write.yml +21 -0
  229. package/rules/mobx-usestate-from-store.yml +20 -0
  230. package/rules/no-local-kit-clone-tsx.yml +104 -0
  231. package/rules/no-local-kit-clone.yml +93 -0
  232. package/rules/non-exhaustive-match.yml +34 -0
  233. package/rules/page-store-bare-usememo-tsx.yml +47 -0
  234. package/rules/page-store-bare-usememo.yml +43 -0
  235. package/rules/screen-file-styling.yml +29 -0
  236. package/rules/silent-default-return.yml +17 -0
  237. package/rules/state-loading-boolean-shape-tsx.yml +102 -0
  238. package/rules/state-loading-boolean-shape.yml +91 -0
  239. package/rules/store-async-method-tsx.yml +108 -0
  240. package/rules/store-async-method.yml +98 -0
  241. package/rules/store-context-provider-tsx.yml +68 -0
  242. package/rules/store-context-provider.yml +78 -0
  243. package/rules/store-delegation-getter-tsx.yml +104 -0
  244. package/rules/store-delegation-getter.yml +93 -0
  245. package/rules/store-new-map-tsx.yml +84 -0
  246. package/rules/store-new-map.yml +73 -0
  247. package/rules/store-no-runinaction-tsx.yml +71 -0
  248. package/rules/store-no-runinaction.yml +60 -0
  249. package/rules/store-no-setinterval-poll-tsx.yml +62 -0
  250. package/rules/store-no-setinterval-poll.yml +51 -0
  251. package/rules/ts-pattern-dangling-match-tsx.yml +41 -0
  252. package/rules/ts-pattern-dangling-match.yml +63 -0
  253. package/rules/ui-imports-app-store.yml +49 -0
  254. package/rules/view-file-logic.yml +53 -0
  255. package/rules/view-imports-store.yml +64 -0
  256. package/rules/zod-optional-nullable-tsx.yml +56 -0
  257. package/rules/zod-optional-nullable.yml +29 -0
  258. package/sgconfig.yml +8 -0
  259. package/structure/rules/component-decl.yml +48 -0
  260. package/structure/sgconfig.yml +7 -0
@@ -0,0 +1,62 @@
1
+ import { readdirSync, readFileSync } from "node:fs";
2
+ import { join } from "node:path";
3
+ import { rulesDir } from "./packagePaths.js";
4
+ import { readTomlTable } from "./tomlTable.js";
5
+ // Per-repo severity RAISE — `[severity]` in .agentvibes/project.toml:
6
+ //
7
+ // [severity]
8
+ // zod-optional-nullable = "error"
9
+ //
10
+ // RAISE-ONLY by design: adoption must never weaken a gate (ratchet-first), so
11
+ // a repo that held a rule at error before adopting the canon keeps it there —
12
+ // but the reverse direction is refused: downgrades already have sanctioned
13
+ // homes (warn-tier biome deviations; `[verify] exclude` for vendored trees;
14
+ // per-line ast-grep-ignore with a written reason), and a quiet [severity]
15
+ // downgrade would be a gate-weakening bypass of all three. The raise reaches
16
+ // ast-grep as its native `--error=<rule-id>` flag, so a repo-local fork of the
17
+ // rule (same id, different severity — a silent drift the README forbids) is
18
+ // never needed.
19
+ export class SeverityConfigError extends Error {
20
+ }
21
+ /** id -> canonical severity, parsed once from the bundled rule files. */
22
+ function canonSeverities() {
23
+ const map = new Map();
24
+ for (const f of readdirSync(rulesDir)) {
25
+ if (!f.endsWith(".yml"))
26
+ continue;
27
+ const text = readFileSync(join(rulesDir, f), "utf8");
28
+ const id = text.match(/^id:\s*(\S+)/m)?.[1];
29
+ const severity = text.match(/^severity:\s*(\S+)/m)?.[1];
30
+ if (id !== undefined && severity !== undefined)
31
+ map.set(id, severity);
32
+ }
33
+ return map;
34
+ }
35
+ /**
36
+ * ast-grep CLI args implementing the repo's [severity] raises; [] when none.
37
+ * Throws SeverityConfigError on an unknown rule id or a non-raise target —
38
+ * a config the gate cannot honour must fail loudly (exit 2), never be
39
+ * silently dropped.
40
+ */
41
+ export function severityRaiseArgs(cwd) {
42
+ const table = readTomlTable(join(cwd, ".agentvibes", "project.toml"), "severity");
43
+ const entries = Object.entries(table);
44
+ if (entries.length === 0)
45
+ return [];
46
+ const canon = canonSeverities();
47
+ const args = [];
48
+ for (const [ruleId, target] of entries) {
49
+ const current = canon.get(ruleId);
50
+ if (current === undefined) {
51
+ throw new SeverityConfigError(`[severity] names unknown rule '${ruleId}' — not in the bundled canon (repo-local extras keep their own severity in their own yml).`);
52
+ }
53
+ if (target !== "error") {
54
+ throw new SeverityConfigError(`[severity] ${ruleId} = "${target}" — only raises to "error" are allowed. Downgrade paths: a warn-tier deviation in biome config, [verify] exclude for vendored trees, or a justified per-line ast-grep-ignore.`);
55
+ }
56
+ if (current === "error")
57
+ continue;
58
+ args.push(`--error=${ruleId}`);
59
+ }
60
+ return args;
61
+ }
62
+ //# sourceMappingURL=severity.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severity.js","sourceRoot":"","sources":["../src/severity.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,QAAQ,EAAE,MAAM,mBAAmB,CAAC;AAC7C,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAE/C,sEAAsE;AACtE,EAAE;AACF,eAAe;AACf,oCAAoC;AACpC,EAAE;AACF,8EAA8E;AAC9E,8EAA8E;AAC9E,2EAA2E;AAC3E,4EAA4E;AAC5E,0EAA0E;AAC1E,6EAA6E;AAC7E,+EAA+E;AAC/E,4EAA4E;AAC5E,gBAAgB;AAEhB,MAAM,OAAO,mBAAoB,SAAQ,KAAK;CAAG;AAEjD,yEAAyE;AACzE,SAAS,eAAe;IACtB,MAAM,GAAG,GAAG,IAAI,GAAG,EAAkB,CAAC;IACtC,KAAK,MAAM,CAAC,IAAI,WAAW,CAAC,QAAQ,CAAC,EAAE,CAAC;QACtC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,SAAS;QAClC,MAAM,IAAI,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,EAAE,CAAC,CAAC,EAAE,MAAM,CAAC,CAAC;QACrD,MAAM,EAAE,GAAG,IAAI,CAAC,KAAK,CAAC,eAAe,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QAC5C,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;QACxD,IAAI,EAAE,KAAK,SAAS,IAAI,QAAQ,KAAK,SAAS;YAAE,GAAG,CAAC,GAAG,CAAC,EAAE,EAAE,QAAQ,CAAC,CAAC;IACxE,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,GAAW;IAC3C,MAAM,KAAK,GAAG,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,cAAc,CAAC,EAAE,UAAU,CAAC,CAAC;IAClF,MAAM,OAAO,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC;IACtC,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,MAAM,KAAK,GAAG,eAAe,EAAE,CAAC;IAChC,MAAM,IAAI,GAAa,EAAE,CAAC;IAC1B,KAAK,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;QACvC,MAAM,OAAO,GAAG,KAAK,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAClC,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAC1B,MAAM,IAAI,mBAAmB,CAC3B,kCAAkC,MAAM,4FAA4F,CACrI,CAAC;QACJ,CAAC;QACD,IAAI,MAAM,KAAK,OAAO,EAAE,CAAC;YACvB,MAAM,IAAI,mBAAmB,CAC3B,cAAc,MAAM,OAAO,MAAM,+KAA+K,CACjN,CAAC;QACJ,CAAC;QACD,IAAI,OAAO,KAAK,OAAO;YAAE,SAAS;QAClC,IAAI,CAAC,IAAI,CAAC,WAAW,MAAM,EAAE,CAAC,CAAC;IACjC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,63 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
3
+ import { tmpdir } from "node:os";
4
+ import { join } from "node:path";
5
+ import { packageRoot } from "./packagePaths.js";
6
+ // Fixtures for the [severity] raise. Three directions, all executed:
7
+ // 1. without a raise, a warning-tier finding does not gate verify (exit 0)
8
+ // 2. with `zod-optional-nullable = "error"`, the SAME code gates (exit 1)
9
+ // and the finding reports at error severity
10
+ // 3. a downgrade attempt (or unknown rule id) is refused loudly (exit 2) —
11
+ // a config the gate cannot honour must never be silently dropped
12
+ const ZOD_BAD = 'import { z } from "zod";\nexport const s = z.object({ a: z.string().optional().nullable() });\n';
13
+ function verify(cwd) {
14
+ const res = spawnSync("node", [join(packageRoot, "dist", "cli.js"), "verify", "schema.ts"], {
15
+ cwd,
16
+ encoding: "utf8",
17
+ });
18
+ if (res.error)
19
+ throw res.error;
20
+ return { status: res.status ?? -1, out: `${res.stdout}${res.stderr}` };
21
+ }
22
+ function expectStep(step, ok, detail) {
23
+ if (!ok) {
24
+ console.error(`FAIL severity: ${step}\n${detail}`);
25
+ return false;
26
+ }
27
+ console.log(` ok severity: ${step}`);
28
+ return true;
29
+ }
30
+ function main() {
31
+ const dir = mkdtempSync(join(tmpdir(), "guardrails-severity-"));
32
+ try {
33
+ writeFileSync(join(dir, "schema.ts"), ZOD_BAD);
34
+ const plain = verify(dir);
35
+ if (!expectStep("warning-tier finding alone does not gate (exit 0)", plain.status === 0 && plain.out.includes("warning[zod-optional-nullable]"), plain.out)) {
36
+ return 1;
37
+ }
38
+ mkdirSync(join(dir, ".agentvibes"));
39
+ const toml = join(dir, ".agentvibes", "project.toml");
40
+ writeFileSync(toml, '[severity]\n"zod-optional-nullable" = "error"\n');
41
+ const raised = verify(dir);
42
+ if (!expectStep("raised rule gates the same code (exit 1, error severity)", raised.status === 1 && raised.out.includes("error[zod-optional-nullable]"), raised.out)) {
43
+ return 1;
44
+ }
45
+ writeFileSync(toml, '[severity]\n"as-any-escape" = "warning"\n');
46
+ const downgrade = verify(dir);
47
+ if (!expectStep("downgrade attempt refused (exit 2)", downgrade.status === 2 && downgrade.out.includes("only raises"), downgrade.out)) {
48
+ return 1;
49
+ }
50
+ writeFileSync(toml, '[severity]\n"no-such-rule" = "error"\n');
51
+ const unknown = verify(dir);
52
+ if (!expectStep("unknown rule id refused (exit 2)", unknown.status === 2 && unknown.out.includes("unknown rule"), unknown.out)) {
53
+ return 1;
54
+ }
55
+ console.log("severity-raise fixtures passed");
56
+ return 0;
57
+ }
58
+ finally {
59
+ rmSync(dir, { recursive: true, force: true });
60
+ }
61
+ }
62
+ process.exit(main());
63
+ //# sourceMappingURL=severityTest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"severityTest.js","sourceRoot":"","sources":["../src/severityTest.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,oBAAoB,CAAC;AAC/C,OAAO,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AACxE,OAAO,EAAE,MAAM,EAAE,MAAM,SAAS,CAAC;AACjC,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,WAAW,EAAE,MAAM,mBAAmB,CAAC;AAEhD,qEAAqE;AACrE,6EAA6E;AAC7E,4EAA4E;AAC5E,iDAAiD;AACjD,6EAA6E;AAC7E,sEAAsE;AAEtE,MAAM,OAAO,GACX,iGAAiG,CAAC;AAEpG,SAAS,MAAM,CAAC,GAAW;IACzB,MAAM,GAAG,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,WAAW,EAAE,MAAM,EAAE,QAAQ,CAAC,EAAE,QAAQ,EAAE,WAAW,CAAC,EAAE;QAC1F,GAAG;QACH,QAAQ,EAAE,MAAM;KACjB,CAAC,CAAC;IACH,IAAI,GAAG,CAAC,KAAK;QAAE,MAAM,GAAG,CAAC,KAAK,CAAC;IAC/B,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,IAAI,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,GAAG,CAAC,MAAM,GAAG,GAAG,CAAC,MAAM,EAAE,EAAE,CAAC;AACzE,CAAC;AAED,SAAS,UAAU,CAAC,IAAY,EAAE,EAAW,EAAE,MAAc;IAC3D,IAAI,CAAC,EAAE,EAAE,CAAC;QACR,OAAO,CAAC,KAAK,CAAC,kBAAkB,IAAI,KAAK,MAAM,EAAE,CAAC,CAAC;QACnD,OAAO,KAAK,CAAC;IACf,CAAC;IACD,OAAO,CAAC,GAAG,CAAC,mBAAmB,IAAI,EAAE,CAAC,CAAC;IACvC,OAAO,IAAI,CAAC;AACd,CAAC;AAED,SAAS,IAAI;IACX,MAAM,GAAG,GAAG,WAAW,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,sBAAsB,CAAC,CAAC,CAAC;IAChE,IAAI,CAAC;QACH,aAAa,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,OAAO,CAAC,CAAC;QAE/C,MAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC1B,IACE,CAAC,UAAU,CACT,mDAAmD,EACnD,KAAK,CAAC,MAAM,KAAK,CAAC,IAAI,KAAK,CAAC,GAAG,CAAC,QAAQ,CAAC,gCAAgC,CAAC,EAC1E,KAAK,CAAC,GAAG,CACV,EACD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,aAAa,CAAC,CAAC,CAAC;QACpC,MAAM,IAAI,GAAG,IAAI,CAAC,GAAG,EAAE,aAAa,EAAE,cAAc,CAAC,CAAC;QACtD,aAAa,CAAC,IAAI,EAAE,iDAAiD,CAAC,CAAC;QACvE,MAAM,MAAM,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC3B,IACE,CAAC,UAAU,CACT,0DAA0D,EAC1D,MAAM,CAAC,MAAM,KAAK,CAAC,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC,8BAA8B,CAAC,EAC1E,MAAM,CAAC,GAAG,CACX,EACD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,aAAa,CAAC,IAAI,EAAE,2CAA2C,CAAC,CAAC;QACjE,MAAM,SAAS,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC9B,IACE,CAAC,UAAU,CACT,oCAAoC,EACpC,SAAS,CAAC,MAAM,KAAK,CAAC,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,CAAC,aAAa,CAAC,EAC/D,SAAS,CAAC,GAAG,CACd,EACD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,aAAa,CAAC,IAAI,EAAE,wCAAwC,CAAC,CAAC;QAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;QAC5B,IACE,CAAC,UAAU,CACT,kCAAkC,EAClC,OAAO,CAAC,MAAM,KAAK,CAAC,IAAI,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,cAAc,CAAC,EAC5D,OAAO,CAAC,GAAG,CACZ,EACD,CAAC;YACD,OAAO,CAAC,CAAC;QACX,CAAC;QAED,OAAO,CAAC,GAAG,CAAC,gCAAgC,CAAC,CAAC;QAC9C,OAAO,CAAC,CAAC;IACX,CAAC;YAAS,CAAC;QACT,MAAM,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAChD,CAAC;AACH,CAAC;AAED,OAAO,CAAC,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC"}
@@ -0,0 +1,9 @@
1
+ export type LineKind = "code" | "blank" | "comment";
2
+ /**
3
+ * Line classifier for the LOC metrics. Heuristic on purpose: a `/*` inside a
4
+ * string literal will be misread as opening a comment — acceptable noise for a
5
+ * trend metric, and the same trade every cloc-style counter makes.
6
+ */
7
+ export declare function classifyLines(text: string): LineKind[];
8
+ /** Count `code` lines within a 1-based inclusive line range. */
9
+ export declare function codeLinesInRange(kinds: LineKind[], startLine: number, endLine: number): number;
@@ -0,0 +1,52 @@
1
+ /**
2
+ * Line classifier for the LOC metrics. Heuristic on purpose: a `/*` inside a
3
+ * string literal will be misread as opening a comment — acceptable noise for a
4
+ * trend metric, and the same trade every cloc-style counter makes.
5
+ */
6
+ export function classifyLines(text) {
7
+ const kinds = [];
8
+ let inBlock = false;
9
+ for (const raw of text.split("\n")) {
10
+ const line = raw.trim();
11
+ if (inBlock) {
12
+ kinds.push("comment");
13
+ const close = line.indexOf("*/");
14
+ if (close >= 0 && line.slice(close + 2).trim() !== "") {
15
+ kinds[kinds.length - 1] = "code";
16
+ }
17
+ if (close >= 0)
18
+ inBlock = false;
19
+ continue;
20
+ }
21
+ if (line === "") {
22
+ kinds.push("blank");
23
+ continue;
24
+ }
25
+ if (line.startsWith("//")) {
26
+ kinds.push("comment");
27
+ continue;
28
+ }
29
+ if (line.startsWith("/*")) {
30
+ kinds.push("comment");
31
+ if (!line.includes("*/"))
32
+ inBlock = true;
33
+ else if (line.slice(line.indexOf("*/") + 2).trim() !== "")
34
+ kinds[kinds.length - 1] = "code";
35
+ continue;
36
+ }
37
+ kinds.push("code");
38
+ if (line.includes("/*") && !line.slice(line.indexOf("/*")).includes("*/"))
39
+ inBlock = true;
40
+ }
41
+ return kinds;
42
+ }
43
+ /** Count `code` lines within a 1-based inclusive line range. */
44
+ export function codeLinesInRange(kinds, startLine, endLine) {
45
+ let n = 0;
46
+ for (let i = startLine - 1; i < endLine && i < kinds.length; i++) {
47
+ if (kinds[i] === "code")
48
+ n++;
49
+ }
50
+ return n;
51
+ }
52
+ //# sourceMappingURL=sourceLines.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"sourceLines.js","sourceRoot":"","sources":["../src/sourceLines.ts"],"names":[],"mappings":"AAEA;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,MAAM,KAAK,GAAe,EAAE,CAAC;IAC7B,IAAI,OAAO,GAAG,KAAK,CAAC;IACpB,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,EAAE,CAAC;QACxB,IAAI,OAAO,EAAE,CAAC;YACZ,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC;YACjC,IAAI,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC;gBACtD,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;YACnC,CAAC;YACD,IAAI,KAAK,IAAI,CAAC;gBAAE,OAAO,GAAG,KAAK,CAAC;YAChC,SAAS;QACX,CAAC;QACD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAChB,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YACpB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,SAAS;QACX,CAAC;QACD,IAAI,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,EAAE,CAAC;YAC1B,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;YACtB,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC;gBAAE,OAAO,GAAG,IAAI,CAAC;iBACpC,IAAI,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE;gBAAE,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,GAAG,MAAM,CAAC;YAC5F,SAAS;QACX,CAAC;QACD,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACnB,IAAI,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC;YAAE,OAAO,GAAG,IAAI,CAAC;IAC5F,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,gEAAgE;AAChE,MAAM,UAAU,gBAAgB,CAAC,KAAiB,EAAE,SAAiB,EAAE,OAAe;IACpF,IAAI,CAAC,GAAG,CAAC,CAAC;IACV,KAAK,IAAI,CAAC,GAAG,SAAS,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,IAAI,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;QACjE,IAAI,KAAK,CAAC,CAAC,CAAC,KAAK,MAAM;YAAE,CAAC,EAAE,CAAC;IAC/B,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC"}
@@ -0,0 +1,2 @@
1
+ import type { Finding } from "./findings.js";
2
+ export declare function structureFindings(targets: string[]): Finding[];
@@ -0,0 +1,98 @@
1
+ import { readFileSync } from "node:fs";
2
+ import { basename, dirname } from "node:path";
3
+ import { scan } from "./astGrep.js";
4
+ import { structureConfig } from "./packagePaths.js";
5
+ // Ported from defensive-errors check-structure.sh: ast-grep cannot count
6
+ // matches per file or measure a node's line span in a rule, so this wraps the
7
+ // `component-decl` marker rule and synthesises three findings from the per-file
8
+ // grouping. Findings anchor at the component's DECLARATION line — that anchor
9
+ // is what makes the size rule a true ratchet under verify-diff: it gates
10
+ // components that are born too long, not existing ones someone edited inside.
11
+ //
12
+ // D2: components over 120 lines are errors, over 90 warnings.
13
+ // D3: strict one component per file.
14
+ const MAX_LINES = Number(process.env.GUARDRAILS_MAX_COMPONENT_LINES ?? process.env.DE_MAX_COMPONENT_LINES ?? 120);
15
+ const WARN_LINES = Number(process.env.GUARDRAILS_WARN_COMPONENT_LINES ?? process.env.DE_WARN_COMPONENT_LINES ?? 90);
16
+ const IGNORE_DIRECTIVE = "ast-grep-ignore";
17
+ /** Honours a suppression comment on the line directly above the declaration. */
18
+ function suppressed(file, line, rule) {
19
+ let prev;
20
+ try {
21
+ prev = readFileSync(file, "utf8").split("\n")[line - 2];
22
+ }
23
+ catch {
24
+ return false;
25
+ }
26
+ if (prev === undefined)
27
+ return false;
28
+ const dirAt = prev.indexOf(IGNORE_DIRECTIVE);
29
+ return dirAt >= 0 && prev.indexOf(rule, dirAt) > dirAt;
30
+ }
31
+ export function structureFindings(targets) {
32
+ const decls = scan(structureConfig, targets).filter((r) => r.ruleId === "component-decl");
33
+ const byFile = new Map();
34
+ for (const d of decls) {
35
+ const list = byFile.get(d.file) ?? [];
36
+ list.push(d);
37
+ byFile.set(d.file, list);
38
+ }
39
+ const findings = [];
40
+ for (const [file, list] of byFile) {
41
+ list.sort((a, b) => a.startLine - b.startLine);
42
+ let folderReported = false;
43
+ list.forEach((decl, idx) => {
44
+ const name = decl.metaText("N") ?? "?";
45
+ if (idx > 0 && !suppressed(file, decl.startLine, "react-multi-component")) {
46
+ findings.push({
47
+ rule: "react-multi-component",
48
+ severity: "error",
49
+ file,
50
+ line: decl.startLine,
51
+ message: `${name} is component #${idx + 1} in ${basename(file)} — one component per file. Move it to its own file next to this one and import it.`,
52
+ source: "structure",
53
+ });
54
+ // A file with parts belongs in a folder. Chained off multi-component on
55
+ // purpose: single cohesive components never need a folder, so the same
56
+ // signal drives both remediations.
57
+ const parent = basename(dirname(file));
58
+ if (!folderReported &&
59
+ (parent === "components" || parent === "pages" || parent === "src") &&
60
+ !suppressed(file, decl.startLine, "react-component-needs-folder")) {
61
+ folderReported = true;
62
+ findings.push({
63
+ rule: "react-component-needs-folder",
64
+ severity: "error",
65
+ file,
66
+ line: decl.startLine,
67
+ message: `${basename(file)} holds several components and sits directly in ${parent}/ — move the family into its own folder (entry file named after the folder, one file per component, no barrel index.ts).`,
68
+ source: "structure",
69
+ });
70
+ }
71
+ }
72
+ if (suppressed(file, decl.startLine, "react-component-too-long"))
73
+ return;
74
+ if (decl.spanLines > MAX_LINES) {
75
+ findings.push({
76
+ rule: "react-component-too-long",
77
+ severity: "error",
78
+ file,
79
+ line: decl.startLine,
80
+ message: `${name} spans ${decl.spanLines} lines (max ${MAX_LINES}). Split it — extract the list item, each section, and each state branch into their own components.`,
81
+ source: "structure",
82
+ });
83
+ }
84
+ else if (decl.spanLines > WARN_LINES) {
85
+ findings.push({
86
+ rule: "react-component-too-long",
87
+ severity: "warning",
88
+ file,
89
+ line: decl.startLine,
90
+ message: `${name} spans ${decl.spanLines} lines (warn over ${WARN_LINES}, max ${MAX_LINES}). Split it — extract the list item, each section, and each state branch into their own components.`,
91
+ source: "structure",
92
+ });
93
+ }
94
+ });
95
+ }
96
+ return findings;
97
+ }
98
+ //# sourceMappingURL=structure.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"structure.js","sourceRoot":"","sources":["../src/structure.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,285 @@
1
+ import { scan } from "./astGrep.js";
2
+ import { fixturesDir, rulesConfig } from "./packagePaths.js";
3
+ const EXPECTATIONS = [
4
+ {
5
+ rule: "missing-observer",
6
+ badSuffix: "missing-observer/bad.tsx",
7
+ hits: 9,
8
+ goodSuffix: "missing-observer/good.tsx",
9
+ },
10
+ {
11
+ rule: "inline-map-row",
12
+ badSuffix: "inline-map-row/bad.tsx",
13
+ hits: 6,
14
+ goodSuffix: "inline-map-row/good.tsx",
15
+ },
16
+ {
17
+ rule: "direct-store-import",
18
+ badSuffix: "direct-store-import/bad.tsx",
19
+ hits: 6,
20
+ goodSuffix: "direct-store-import/good.tsx",
21
+ },
22
+ {
23
+ rule: "view-imports-store",
24
+ badSuffix: "view-imports-store/bad.view.tsx",
25
+ hits: 5,
26
+ goodSuffix: "view-imports-store/good.view.tsx",
27
+ },
28
+ {
29
+ rule: "ui-imports-app-store",
30
+ badSuffix: "ui-imports-app-store/src/ui/bad.tsx",
31
+ hits: 5,
32
+ goodSuffix: "ui-imports-app-store/src/ui/good.tsx",
33
+ },
34
+ // wave 1: store rules. `typescript` and `tsx` are disjoint languages in
35
+ // ast-grep, so each twin is its own rule id and needs its own executed
36
+ // assertion — an unasserted twin is exactly the unexecuted rule the iron
37
+ // rule forbids.
38
+ {
39
+ rule: "store-no-runinaction",
40
+ badSuffix: "store-no-runinaction/bad.ts",
41
+ hits: 5,
42
+ goodSuffix: "store-no-runinaction/good.ts",
43
+ },
44
+ {
45
+ rule: "store-async-method",
46
+ badSuffix: "store-async-method/bad.ts",
47
+ hits: 4,
48
+ goodSuffix: "store-async-method/good.ts",
49
+ },
50
+ {
51
+ rule: "store-new-map",
52
+ badSuffix: "store-new-map/bad.ts",
53
+ hits: 4,
54
+ goodSuffix: "store-new-map/good.ts",
55
+ },
56
+ {
57
+ rule: "state-loading-boolean-shape",
58
+ badSuffix: "state-loading-boolean-shape/bad.ts",
59
+ hits: 5,
60
+ goodSuffix: "state-loading-boolean-shape/good.ts",
61
+ },
62
+ {
63
+ rule: "store-delegation-getter",
64
+ badSuffix: "store-delegation-getter/bad.ts",
65
+ hits: 4,
66
+ goodSuffix: "store-delegation-getter/good.ts",
67
+ },
68
+ {
69
+ rule: "no-local-kit-clone",
70
+ badSuffix: "no-local-kit-clone/bad.ts",
71
+ hits: 6,
72
+ goodSuffix: "no-local-kit-clone/good.ts",
73
+ },
74
+ {
75
+ rule: "store-no-setinterval-poll",
76
+ badSuffix: "store-no-setinterval-poll/bad.ts",
77
+ hits: 2,
78
+ goodSuffix: "store-no-setinterval-poll/good.ts",
79
+ },
80
+ {
81
+ rule: "store-no-runinaction-tsx",
82
+ badSuffix: "store-no-runinaction/bad.tsx",
83
+ hits: 5,
84
+ goodSuffix: "store-no-runinaction/good.tsx",
85
+ },
86
+ {
87
+ rule: "store-async-method-tsx",
88
+ badSuffix: "store-async-method/bad.tsx",
89
+ hits: 4,
90
+ goodSuffix: "store-async-method/good.tsx",
91
+ },
92
+ {
93
+ rule: "store-new-map-tsx",
94
+ badSuffix: "store-new-map/bad.tsx",
95
+ hits: 4,
96
+ goodSuffix: "store-new-map/good.tsx",
97
+ },
98
+ {
99
+ rule: "state-loading-boolean-shape-tsx",
100
+ badSuffix: "state-loading-boolean-shape/bad.tsx",
101
+ hits: 5,
102
+ goodSuffix: "state-loading-boolean-shape/good.tsx",
103
+ },
104
+ {
105
+ rule: "store-delegation-getter-tsx",
106
+ badSuffix: "store-delegation-getter/bad.tsx",
107
+ hits: 4,
108
+ goodSuffix: "store-delegation-getter/good.tsx",
109
+ },
110
+ {
111
+ rule: "no-local-kit-clone-tsx",
112
+ badSuffix: "no-local-kit-clone/bad.tsx",
113
+ hits: 6,
114
+ goodSuffix: "no-local-kit-clone/good.tsx",
115
+ },
116
+ {
117
+ rule: "store-no-setinterval-poll-tsx",
118
+ badSuffix: "store-no-setinterval-poll/bad.tsx",
119
+ hits: 2,
120
+ goodSuffix: "store-no-setinterval-poll/good.tsx",
121
+ },
122
+ // ── wave 2: rule-triage ───────────────────────────────────────────────
123
+ // Promoted from the two local collections.
124
+ {
125
+ rule: "ts-pattern-dangling-match",
126
+ badSuffix: "ts-pattern-dangling-match/bad.ts",
127
+ hits: 2,
128
+ goodSuffix: "ts-pattern-dangling-match/good.ts",
129
+ },
130
+ {
131
+ rule: "discriminator-ternary",
132
+ badSuffix: "discriminator-ternary/bad.tsx",
133
+ hits: 6,
134
+ goodSuffix: "discriminator-ternary/good.tsx",
135
+ },
136
+ {
137
+ rule: "literal-union-in-component",
138
+ badSuffix: "literal-union-in-component/components/bad.ts",
139
+ hits: 4,
140
+ goodSuffix: "literal-union-in-component/components/good.ts",
141
+ },
142
+ {
143
+ rule: "hardcoded-url-in-component",
144
+ badSuffix: "hardcoded-url-in-component/components/bad.tsx",
145
+ hits: 4,
146
+ goodSuffix: "hardcoded-url-in-component/components/good.tsx",
147
+ },
148
+ // Five canon rules whose bodies were replaced by the (strictly better)
149
+ // faceless implementations. These fixtures exist to pin the coverage the
150
+ // upgrade ADDED — every bad.ts here carries the edge cases the old body
151
+ // missed, so a revert cannot pass silently.
152
+ {
153
+ rule: "as-any-escape",
154
+ badSuffix: "as-any-escape/bad.ts",
155
+ hits: 4,
156
+ goodSuffix: "as-any-escape/good.ts",
157
+ },
158
+ {
159
+ rule: "catch-empty",
160
+ badSuffix: "catch-empty/bad.ts",
161
+ hits: 4,
162
+ goodSuffix: "catch-empty/good.ts",
163
+ },
164
+ {
165
+ rule: "instanceof-map-set",
166
+ badSuffix: "instanceof-map-set/bad.ts",
167
+ hits: 4,
168
+ goodSuffix: "instanceof-map-set/good.ts",
169
+ },
170
+ {
171
+ rule: "zod-optional-nullable",
172
+ badSuffix: "zod-optional-nullable/bad.ts",
173
+ hits: 6,
174
+ goodSuffix: "zod-optional-nullable/good.ts",
175
+ },
176
+ {
177
+ rule: "zod-optional-nullable-tsx",
178
+ badSuffix: "zod-optional-nullable/bad.tsx",
179
+ hits: 6,
180
+ goodSuffix: "zod-optional-nullable/good.tsx",
181
+ },
182
+ {
183
+ rule: "non-exhaustive-match",
184
+ badSuffix: "non-exhaustive-match/bad.ts",
185
+ hits: 2,
186
+ goodSuffix: "non-exhaustive-match/good.ts",
187
+ },
188
+ {
189
+ rule: "store-context-provider",
190
+ badSuffix: "store-context-provider/bad.ts",
191
+ hits: 4,
192
+ goodSuffix: "store-context-provider/good.ts",
193
+ },
194
+ {
195
+ rule: "store-context-provider-tsx",
196
+ badSuffix: "store-context-provider/bad.tsx",
197
+ hits: 5,
198
+ goodSuffix: "store-context-provider/good.tsx",
199
+ },
200
+ {
201
+ rule: "page-store-bare-usememo",
202
+ badSuffix: "page-store-bare-usememo/bad.ts",
203
+ hits: 2,
204
+ goodSuffix: "page-store-bare-usememo/good.ts",
205
+ },
206
+ {
207
+ rule: "page-store-bare-usememo-tsx",
208
+ badSuffix: "page-store-bare-usememo/bad.tsx",
209
+ hits: 2,
210
+ goodSuffix: "page-store-bare-usememo/good.tsx",
211
+ },
212
+ {
213
+ rule: "view-file-logic",
214
+ badSuffix: "view-file-logic/bad.view.tsx",
215
+ hits: 3,
216
+ goodSuffix: "view-file-logic/good.view.tsx",
217
+ },
218
+ {
219
+ rule: "screen-file-styling",
220
+ badSuffix: "screen-file-styling/bad.screen.tsx",
221
+ hits: 3,
222
+ goodSuffix: "screen-file-styling/good.screen.tsx",
223
+ },
224
+ ];
225
+ // A file that is deliberately out of scope — same offending code as the bad
226
+ // fixture, sitting where an `ignores:` glob excludes it. Pins the glob: drop
227
+ // the ignore and this starts reporting.
228
+ const EXPECT_ZERO = [
229
+ {
230
+ rule: "direct-store-import",
231
+ suffix: "direct-store-import/showcase/ignored.tsx",
232
+ why: "showcase/ is an ignores: glob",
233
+ },
234
+ ];
235
+ function main() {
236
+ const rows = scan(rulesConfig, [fixturesDir]);
237
+ const count = (rule, suffix) => rows.filter((r) => r.ruleId === rule && r.file.endsWith(suffix)).length;
238
+ let fail = false;
239
+ console.log("== ast-grep rule fixtures ==");
240
+ for (const e of EXPECTATIONS) {
241
+ const gotBad = count(e.rule, e.badSuffix);
242
+ const gotGood = count(e.rule, e.goodSuffix);
243
+ if (gotBad === 0) {
244
+ // The failure this harness exists to make loud: silence is NOT a pass.
245
+ console.log(`FAIL ${e.rule}: 0 hits on ${e.badSuffix} — rule did not load, its files: glob excluded the fixture, or it matches nothing`);
246
+ fail = true;
247
+ }
248
+ else if (gotBad !== e.hits) {
249
+ console.log(`FAIL ${e.rule}: ${e.badSuffix} expected ${e.hits} hits, got ${gotBad}`);
250
+ fail = true;
251
+ }
252
+ else {
253
+ console.log(` ok ${e.rule}: ${e.badSuffix} → ${gotBad} hits (expected ${e.hits})`);
254
+ }
255
+ if (gotGood !== 0) {
256
+ console.log(`FAIL ${e.rule}: ${e.goodSuffix} expected 0 hits, got ${gotGood} (false positives)`);
257
+ for (const r of rows.filter((x) => x.ruleId === e.rule && x.file.endsWith(e.goodSuffix))) {
258
+ console.log(` ${r.file}:${r.startLine}`);
259
+ }
260
+ fail = true;
261
+ }
262
+ else {
263
+ console.log(` ok ${e.rule}: ${e.goodSuffix} → 0 hits`);
264
+ }
265
+ }
266
+ for (const z of EXPECT_ZERO) {
267
+ const got = count(z.rule, z.suffix);
268
+ if (got !== 0) {
269
+ console.log(`FAIL ${z.rule}: ${z.suffix} expected 0 hits (${z.why}), got ${got}`);
270
+ fail = true;
271
+ }
272
+ else {
273
+ console.log(` ok ${z.rule}: ${z.suffix} → 0 hits (${z.why})`);
274
+ }
275
+ }
276
+ console.log("");
277
+ if (fail) {
278
+ console.error("fixture assertions FAILED");
279
+ return 1;
280
+ }
281
+ console.log("all fixture assertions passed");
282
+ return 0;
283
+ }
284
+ process.exit(main());
285
+ //# sourceMappingURL=testRules.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testRules.js","sourceRoot":"","sources":["../src/testRules.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { Finding } from "./findings.js";
2
+ export declare function textGrepFindings(targets: string[]): Finding[];