@shivaedev/quality 0.23.0 → 0.24.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 (272) hide show
  1. package/CHANGELOG.md +7 -0
  2. package/README.md +4 -0
  3. package/dist/baseline/compare.d.ts +2 -2
  4. package/dist/baseline/compare.d.ts.map +1 -1
  5. package/dist/baseline/compare.js +5 -3
  6. package/dist/baseline/compare.js.map +1 -1
  7. package/dist/baseline/format.d.ts +5 -5
  8. package/dist/baseline/format.d.ts.map +1 -1
  9. package/dist/baseline/format.js +23 -13
  10. package/dist/baseline/format.js.map +1 -1
  11. package/dist/baseline/legacy.d.ts +2 -2
  12. package/dist/baseline/legacy.d.ts.map +1 -1
  13. package/dist/baseline/legacy.js +4 -4
  14. package/dist/baseline/legacy.js.map +1 -1
  15. package/dist/baseline/rewrite.d.ts +1 -1
  16. package/dist/baseline/rewrite.d.ts.map +1 -1
  17. package/dist/baseline/rewrite.js +2 -2
  18. package/dist/baseline/rewrite.js.map +1 -1
  19. package/dist/baseline/update.d.ts +2 -2
  20. package/dist/baseline/update.d.ts.map +1 -1
  21. package/dist/baseline/update.js +24 -18
  22. package/dist/baseline/update.js.map +1 -1
  23. package/dist/cli/args.d.ts +1 -1
  24. package/dist/cli/args.d.ts.map +1 -1
  25. package/dist/cli/args.js +15 -9
  26. package/dist/cli/args.js.map +1 -1
  27. package/dist/cli/baseline.d.ts +1 -1
  28. package/dist/cli/baseline.d.ts.map +1 -1
  29. package/dist/cli/baseline.js +10 -6
  30. package/dist/cli/baseline.js.map +1 -1
  31. package/dist/cli/fix.d.ts +2 -2
  32. package/dist/cli/fix.d.ts.map +1 -1
  33. package/dist/cli/fix.js +34 -40
  34. package/dist/cli/fix.js.map +1 -1
  35. package/dist/cli/lint.d.ts +1 -1
  36. package/dist/cli/lint.d.ts.map +1 -1
  37. package/dist/cli/lint.js +1 -1
  38. package/dist/cli/lint.js.map +1 -1
  39. package/dist/cli/migrate.d.ts.map +1 -1
  40. package/dist/cli/migrate.js +1 -1
  41. package/dist/cli/migrate.js.map +1 -1
  42. package/dist/cli/run-main.js +2 -2
  43. package/dist/cli/run-main.js.map +1 -1
  44. package/dist/cli/shrink.d.ts +2 -2
  45. package/dist/cli/shrink.d.ts.map +1 -1
  46. package/dist/cli/shrink.js +9 -3
  47. package/dist/cli/shrink.js.map +1 -1
  48. package/dist/config/decode.d.ts +1 -1
  49. package/dist/config/decode.d.ts.map +1 -1
  50. package/dist/config/decode.js +13 -9
  51. package/dist/config/decode.js.map +1 -1
  52. package/dist/config/load.d.ts.map +1 -1
  53. package/dist/config/load.js +26 -20
  54. package/dist/config/load.js.map +1 -1
  55. package/dist/config/resolve.d.ts +22 -2
  56. package/dist/config/resolve.d.ts.map +1 -1
  57. package/dist/config/resolve.js +18 -10
  58. package/dist/config/resolve.js.map +1 -1
  59. package/dist/config.d.ts +1 -1
  60. package/dist/config.d.ts.map +1 -1
  61. package/dist/config.js +3 -1
  62. package/dist/config.js.map +1 -1
  63. package/dist/decoded.d.ts +2 -2
  64. package/dist/decoded.d.ts.map +1 -1
  65. package/dist/decoded.js +7 -5
  66. package/dist/decoded.js.map +1 -1
  67. package/dist/engine/baseline-file.d.ts +1 -1
  68. package/dist/engine/baseline-file.d.ts.map +1 -1
  69. package/dist/engine/baseline-file.js +4 -2
  70. package/dist/engine/baseline-file.js.map +1 -1
  71. package/dist/engine/evaluate.d.ts +2 -2
  72. package/dist/engine/evaluate.d.ts.map +1 -1
  73. package/dist/engine/evaluate.js +5 -3
  74. package/dist/engine/evaluate.js.map +1 -1
  75. package/dist/engine/run-rules.d.ts +1 -1
  76. package/dist/engine/run-rules.d.ts.map +1 -1
  77. package/dist/engine/run-rules.js +24 -14
  78. package/dist/engine/run-rules.js.map +1 -1
  79. package/dist/engine/session.d.ts.map +1 -1
  80. package/dist/engine/session.js +8 -4
  81. package/dist/engine/session.js.map +1 -1
  82. package/dist/engine/violation.d.ts +7 -7
  83. package/dist/engine/violation.d.ts.map +1 -1
  84. package/dist/engine/violation.js +22 -10
  85. package/dist/engine/violation.js.map +1 -1
  86. package/dist/exceptions/registry.d.ts +2 -2
  87. package/dist/exceptions/registry.d.ts.map +1 -1
  88. package/dist/exceptions/registry.js +10 -6
  89. package/dist/exceptions/registry.js.map +1 -1
  90. package/dist/git/base.d.ts +1 -2
  91. package/dist/git/base.d.ts.map +1 -1
  92. package/dist/git/base.js +22 -10
  93. package/dist/git/base.js.map +1 -1
  94. package/dist/git/command.d.ts +2 -2
  95. package/dist/git/command.d.ts.map +1 -1
  96. package/dist/git/command.js +13 -9
  97. package/dist/git/command.js.map +1 -1
  98. package/dist/git/history.d.ts +1 -1
  99. package/dist/git/history.d.ts.map +1 -1
  100. package/dist/git/history.js +5 -3
  101. package/dist/git/history.js.map +1 -1
  102. package/dist/inventory/collect.d.ts +1 -1
  103. package/dist/inventory/collect.d.ts.map +1 -1
  104. package/dist/inventory/collect.js +7 -5
  105. package/dist/inventory/collect.js.map +1 -1
  106. package/dist/inventory/filesystem.d.ts +1 -1
  107. package/dist/inventory/filesystem.d.ts.map +1 -1
  108. package/dist/inventory/filesystem.js +11 -7
  109. package/dist/inventory/filesystem.js.map +1 -1
  110. package/dist/inventory/ignore-scope.d.ts +4 -4
  111. package/dist/inventory/ignore-scope.d.ts.map +1 -1
  112. package/dist/inventory/ignore-scope.js +18 -9
  113. package/dist/inventory/ignore-scope.js.map +1 -1
  114. package/dist/manifests/sorted.d.ts +1 -1
  115. package/dist/manifests/sorted.d.ts.map +1 -1
  116. package/dist/manifests/sorted.js +14 -16
  117. package/dist/manifests/sorted.js.map +1 -1
  118. package/dist/report/plural.d.ts +1 -1
  119. package/dist/report/plural.d.ts.map +1 -1
  120. package/dist/report/plural.js +3 -1
  121. package/dist/report/plural.js.map +1 -1
  122. package/dist/report/render.d.ts +1 -1
  123. package/dist/report/render.d.ts.map +1 -1
  124. package/dist/report/render.js +29 -21
  125. package/dist/report/render.js.map +1 -1
  126. package/dist/report/stale.d.ts +1 -1
  127. package/dist/report/stale.d.ts.map +1 -1
  128. package/dist/report/stale.js +18 -8
  129. package/dist/report/stale.js.map +1 -1
  130. package/dist/rule.d.ts +13 -13
  131. package/dist/rule.d.ts.map +1 -1
  132. package/dist/rule.js +10 -8
  133. package/dist/rule.js.map +1 -1
  134. package/dist/rules/built-in.d.ts +1 -1
  135. package/dist/rules/built-in.d.ts.map +1 -1
  136. package/dist/rules/built-in.js +2 -0
  137. package/dist/rules/built-in.js.map +1 -1
  138. package/dist/rules/comments/kinds.d.ts +4 -4
  139. package/dist/rules/comments/kinds.d.ts.map +1 -1
  140. package/dist/rules/comments/kinds.js +16 -8
  141. package/dist/rules/comments/kinds.js.map +1 -1
  142. package/dist/rules/comments/max-per-file.d.ts.map +1 -1
  143. package/dist/rules/comments/max-per-file.js +13 -9
  144. package/dist/rules/comments/max-per-file.js.map +1 -1
  145. package/dist/rules/comments/pattern-rule.d.ts +1 -1
  146. package/dist/rules/comments/pattern-rule.d.ts.map +1 -1
  147. package/dist/rules/comments/pattern-rule.js +12 -10
  148. package/dist/rules/comments/pattern-rule.js.map +1 -1
  149. package/dist/rules/comments/scan.d.ts +3 -3
  150. package/dist/rules/comments/scan.d.ts.map +1 -1
  151. package/dist/rules/comments/scan.js +23 -19
  152. package/dist/rules/comments/scan.js.map +1 -1
  153. package/dist/rules/max-lines.d.ts.map +1 -1
  154. package/dist/rules/max-lines.js +12 -10
  155. package/dist/rules/max-lines.js.map +1 -1
  156. package/dist/rules/stories/origins.d.ts +10 -0
  157. package/dist/rules/stories/origins.d.ts.map +1 -0
  158. package/dist/rules/stories/origins.js +129 -0
  159. package/dist/rules/stories/origins.js.map +1 -0
  160. package/dist/rules/stories/prerequisites.d.ts +4 -0
  161. package/dist/rules/stories/prerequisites.d.ts.map +1 -0
  162. package/dist/rules/stories/prerequisites.js +32 -0
  163. package/dist/rules/stories/prerequisites.js.map +1 -0
  164. package/dist/rules/stories/program.d.ts +5 -0
  165. package/dist/rules/stories/program.d.ts.map +1 -0
  166. package/dist/rules/stories/program.js +22 -0
  167. package/dist/rules/stories/program.js.map +1 -0
  168. package/dist/rules/stories/specs.d.ts +2 -0
  169. package/dist/rules/stories/specs.d.ts.map +1 -0
  170. package/dist/rules/stories/specs.js +80 -0
  171. package/dist/rules/stories/specs.js.map +1 -0
  172. package/dist/rules/suppressions/biome/configs.d.ts +1 -1
  173. package/dist/rules/suppressions/biome/configs.d.ts.map +1 -1
  174. package/dist/rules/suppressions/biome/configs.js +23 -17
  175. package/dist/rules/suppressions/biome/configs.js.map +1 -1
  176. package/dist/rules/suppressions/biome/declarations.d.ts +4 -4
  177. package/dist/rules/suppressions/biome/declarations.d.ts.map +1 -1
  178. package/dist/rules/suppressions/biome/declarations.js +15 -7
  179. package/dist/rules/suppressions/biome/declarations.js.map +1 -1
  180. package/dist/rules/suppressions/biome/json.d.ts +6 -6
  181. package/dist/rules/suppressions/biome/json.d.ts.map +1 -1
  182. package/dist/rules/suppressions/biome/json.js +27 -13
  183. package/dist/rules/suppressions/biome/json.js.map +1 -1
  184. package/dist/rules/suppressions/biome/resolve.d.ts +1 -1
  185. package/dist/rules/suppressions/biome/resolve.d.ts.map +1 -1
  186. package/dist/rules/suppressions/biome/resolve.js +23 -17
  187. package/dist/rules/suppressions/biome/resolve.js.map +1 -1
  188. package/dist/rules/suppressions/biome/weakenings.d.ts +1 -1
  189. package/dist/rules/suppressions/biome/weakenings.d.ts.map +1 -1
  190. package/dist/rules/suppressions/biome/weakenings.js +78 -52
  191. package/dist/rules/suppressions/biome/weakenings.js.map +1 -1
  192. package/dist/rules/suppressions/biome-overrides.d.ts.map +1 -1
  193. package/dist/rules/suppressions/biome-overrides.js +45 -33
  194. package/dist/rules/suppressions/biome-overrides.js.map +1 -1
  195. package/dist/rules/suppressions/directives.d.ts +1 -1
  196. package/dist/rules/suppressions/directives.d.ts.map +1 -1
  197. package/dist/rules/suppressions/directives.js +5 -3
  198. package/dist/rules/suppressions/directives.js.map +1 -1
  199. package/dist/rules/suppressions/no-double-cast.d.ts.map +1 -1
  200. package/dist/rules/suppressions/no-double-cast.js +14 -10
  201. package/dist/rules/suppressions/no-double-cast.js.map +1 -1
  202. package/dist/rules/suppressions/no-inline.d.ts.map +1 -1
  203. package/dist/rules/suppressions/no-inline.js +8 -6
  204. package/dist/rules/suppressions/no-inline.js.map +1 -1
  205. package/dist/rules/suppressions/stylesheet-comments.d.ts +1 -1
  206. package/dist/rules/suppressions/stylesheet-comments.d.ts.map +1 -1
  207. package/dist/rules/suppressions/stylesheet-comments.js +11 -5
  208. package/dist/rules/suppressions/stylesheet-comments.js.map +1 -1
  209. package/dist/rules/syntax.d.ts +1 -1
  210. package/dist/rules/syntax.d.ts.map +1 -1
  211. package/dist/rules/syntax.js +2 -2
  212. package/dist/rules/syntax.js.map +1 -1
  213. package/dist/standard-schema.d.ts +6 -6
  214. package/dist/standard-schema.d.ts.map +1 -1
  215. package/docs/modules.md +2 -0
  216. package/package.json +1 -1
  217. package/src/baseline/compare.ts +5 -3
  218. package/src/baseline/format.ts +17 -10
  219. package/src/baseline/legacy.ts +4 -4
  220. package/src/baseline/rewrite.ts +2 -2
  221. package/src/baseline/update.ts +20 -16
  222. package/src/cli/args.ts +15 -10
  223. package/src/cli/baseline.ts +36 -35
  224. package/src/cli/fix.ts +39 -42
  225. package/src/cli/lint.ts +17 -19
  226. package/src/cli/migrate.ts +20 -21
  227. package/src/cli/run-main.ts +2 -2
  228. package/src/cli/shrink.ts +11 -8
  229. package/src/config/decode.ts +15 -10
  230. package/src/config/load.ts +44 -37
  231. package/src/config/resolve.ts +32 -27
  232. package/src/config.ts +3 -1
  233. package/src/decoded.ts +5 -4
  234. package/src/engine/baseline-file.ts +14 -12
  235. package/src/engine/evaluate.ts +6 -5
  236. package/src/engine/run-rules.ts +21 -13
  237. package/src/engine/session.ts +32 -25
  238. package/src/engine/violation.ts +22 -11
  239. package/src/exceptions/registry.ts +10 -8
  240. package/src/git/base.ts +45 -37
  241. package/src/git/command.ts +6 -4
  242. package/src/git/history.ts +5 -4
  243. package/src/inventory/collect.ts +39 -34
  244. package/src/inventory/filesystem.ts +38 -30
  245. package/src/inventory/ignore-scope.ts +20 -10
  246. package/src/manifests/sorted.ts +18 -18
  247. package/src/report/plural.ts +3 -1
  248. package/src/report/render.ts +23 -18
  249. package/src/report/stale.ts +33 -25
  250. package/src/rule.ts +25 -19
  251. package/src/rules/built-in.ts +2 -0
  252. package/src/rules/comments/kinds.ts +16 -9
  253. package/src/rules/comments/max-per-file.ts +15 -11
  254. package/src/rules/comments/pattern-rule.ts +5 -4
  255. package/src/rules/comments/scan.ts +18 -15
  256. package/src/rules/max-lines.ts +3 -2
  257. package/src/rules/stories/origins.ts +147 -0
  258. package/src/rules/stories/prerequisites.ts +37 -0
  259. package/src/rules/stories/program.ts +29 -0
  260. package/src/rules/stories/specs.ts +93 -0
  261. package/src/rules/suppressions/biome/configs.ts +23 -17
  262. package/src/rules/suppressions/biome/declarations.ts +15 -10
  263. package/src/rules/suppressions/biome/json.ts +25 -13
  264. package/src/rules/suppressions/biome/resolve.ts +23 -18
  265. package/src/rules/suppressions/biome/weakenings.ts +60 -41
  266. package/src/rules/suppressions/biome-overrides.ts +32 -22
  267. package/src/rules/suppressions/directives.ts +5 -4
  268. package/src/rules/suppressions/no-double-cast.ts +14 -10
  269. package/src/rules/suppressions/no-inline.ts +5 -4
  270. package/src/rules/suppressions/stylesheet-comments.ts +11 -6
  271. package/src/rules/syntax.ts +2 -2
  272. package/src/standard-schema.ts +4 -4
package/docs/modules.md CHANGED
@@ -182,6 +182,8 @@ A module link opens its source. Type and value declarations with the same name a
182
182
  | [rules/built-in.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/built-in.ts) | `builtInRules` |
183
183
  | [rules/manifests-sorted.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/manifests-sorted.ts) | `manifestsSorted` |
184
184
  | [rules/max-lines.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/max-lines.ts) | `maxLines` |
185
+ | [rules/maxDepth.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/maxDepth.ts) | `maxDepth` |
186
+ | [rules/noBarrel.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/noBarrel.ts) | `noBarrel` |
185
187
  | [rules/syntax.ts](https://github.com/ShivaeDev/platform/blob/main/packages/quality/src/rules/syntax.ts) | `parse` |
186
188
 
187
189
  ## rules/comments
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@shivaedev/quality",
3
- "version": "0.23.0",
3
+ "version": "0.24.0",
4
4
  "description": "Repository quality gate with typed rules, a baseline of existing debt and a registry of reasoned exceptions",
5
5
  "homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/quality#readme",
6
6
  "bugs": {
@@ -19,9 +19,11 @@ export interface BaselineCheck {
19
19
  readonly stale: readonly StaleBaselineEntry[];
20
20
  }
21
21
 
22
- export const countOf = (violations: readonly Violation[]): number => violations.reduce((total, violation) => total + (violation.count ?? 1), 0);
22
+ export function countOf(violations: readonly Violation[]): number {
23
+ return violations.reduce((total, violation) => total + (violation.count ?? 1), 0);
24
+ }
23
25
 
24
- export const applyBaseline = (violations: readonly Violation[], entries: readonly BaselineEntry[], rules: RuleIndex): BaselineCheck => {
26
+ export function applyBaseline(violations: readonly Violation[], entries: readonly BaselineEntry[], rules: RuleIndex): BaselineCheck {
25
27
  const groups = groupBy(violations, (violation) => keyOf(violation.rule, violation.file));
26
28
  const covered = new Set<string>();
27
29
  const regressions: Regression[] = [];
@@ -49,4 +51,4 @@ export const applyBaseline = (violations: readonly Violation[], entries: readonl
49
51
  }
50
52
  const kept = violations.filter((violation) => !covered.has(keyOf(violation.rule, violation.file)));
51
53
  return { baselined: violations.length - kept.length, kept, loose, regressions, stale };
52
- };
54
+ }
@@ -16,18 +16,22 @@ export interface BaselineEntry {
16
16
  readonly rule: string;
17
17
  }
18
18
 
19
- const codepoints = (left: string, right: string): number => (left < right ? -1 : Number(left > right));
19
+ function codepoints(left: string, right: string): number {
20
+ return left < right ? -1 : Number(left > right);
21
+ }
20
22
 
21
- export const byPathAndRule = (left: BaselineEntry, right: BaselineEntry): number =>
22
- codepoints(left.file, right.file) || codepoints(left.rule, right.rule);
23
+ export function byPathAndRule(left: BaselineEntry, right: BaselineEntry): number {
24
+ return codepoints(left.file, right.file) || codepoints(left.rule, right.rule);
25
+ }
23
26
 
24
- export const linesOf = (raw: string | undefined): ReadonlyArray<{ readonly line: number; readonly text: string }> =>
25
- (raw ?? "")
27
+ export function linesOf(raw: string | undefined): ReadonlyArray<{ readonly line: number; readonly text: string }> {
28
+ return (raw ?? "")
26
29
  .split("\n")
27
30
  .map((text, index) => ({ line: index + 1, text }))
28
31
  .filter((row) => row.text.trim() !== "");
32
+ }
29
33
 
30
- export const decodeBaseline = async (raw: string | undefined): Promise<Decoded<readonly BaselineEntry[]>> => {
34
+ export async function decodeBaseline(raw: string | undefined): Promise<Decoded<readonly BaselineEntry[]>> {
31
35
  const issues: string[] = [];
32
36
  const entries: BaselineEntry[] = [];
33
37
  const seen = new Set<string>();
@@ -45,14 +49,17 @@ export const decodeBaseline = async (raw: string | undefined): Promise<Decoded<r
45
49
  entries.push({ ...stored, file: path });
46
50
  }
47
51
  return issues.length === 0 ? { _tag: "Valid", value: entries } : { _tag: "Invalid", issues };
48
- };
52
+ }
49
53
 
50
54
  const LINE_KEYS = ["path", "rule", "count"];
51
55
 
52
- export const encodeEntry = (entry: BaselineEntry): string => JSON.stringify({ count: entry.count, path: entry.file, rule: entry.rule }, LINE_KEYS);
56
+ export function encodeEntry(entry: BaselineEntry): string {
57
+ return JSON.stringify({ count: entry.count, path: entry.file, rule: entry.rule }, LINE_KEYS);
58
+ }
53
59
 
54
- export const encodeBaseline = (entries: readonly BaselineEntry[]): string =>
55
- [...entries]
60
+ export function encodeBaseline(entries: readonly BaselineEntry[]): string {
61
+ return [...entries]
56
62
  .sort(byPathAndRule)
57
63
  .map((entry) => `${encodeEntry(entry)}\n`)
58
64
  .join("");
65
+ }
@@ -19,7 +19,7 @@ export interface LegacyEntry extends BaselineEntry {
19
19
  readonly measure?: number | undefined;
20
20
  }
21
21
 
22
- export const decodeLegacyBaseline = async (raw: string): Promise<Decoded<readonly LegacyEntry[]>> => {
22
+ export async function decodeLegacyBaseline(raw: string): Promise<Decoded<readonly LegacyEntry[]>> {
23
23
  const decoded = await decodeWith(standard, raw);
24
24
  if (decoded._tag === "Invalid") {
25
25
  return decoded;
@@ -28,9 +28,9 @@ export const decodeLegacyBaseline = async (raw: string): Promise<Decoded<readonl
28
28
  Object.entries(files).map(([file, stored]) => ({ ...stored, file, rule })),
29
29
  );
30
30
  return { _tag: "Valid", value: entries };
31
- };
31
+ }
32
32
 
33
- export const convertLegacy = (legacy: readonly LegacyEntry[], violations: readonly Violation[]): readonly BaselineEntry[] => {
33
+ export function convertLegacy(legacy: readonly LegacyEntry[], violations: readonly Violation[]): readonly BaselineEntry[] {
34
34
  const current = groupBy(violations, (violation) => keyOf(violation.rule, violation.file));
35
35
  return legacy.flatMap(({ count, file, measure, rule }) => {
36
36
  if (measure === undefined) {
@@ -41,4 +41,4 @@ export const convertLegacy = (legacy: readonly LegacyEntry[], violations: readon
41
41
  const converted = threshold === undefined ? countOf(group) : Math.ceil(measure - threshold);
42
42
  return converted > 0 ? [{ count: converted, file, rule }] : [];
43
43
  });
44
- };
44
+ }
@@ -7,7 +7,7 @@ interface Row {
7
7
  }
8
8
 
9
9
  // An untouched entry keeps its exact line and a new one goes before the first line that sorts after it, so two branches conflict only on the same or neighbouring entries.
10
- export const rewriteBaseline = (raw: string | undefined, before: readonly BaselineEntry[], after: readonly BaselineEntry[]): string => {
10
+ export function rewriteBaseline(raw: string | undefined, before: readonly BaselineEntry[], after: readonly BaselineEntry[]): string {
11
11
  const wanted = new Map(after.map((entry) => [keyOf(entry.rule, entry.file), entry]));
12
12
  const lines = linesOf(raw);
13
13
  const rows: Row[] = before.flatMap((old, index) => {
@@ -21,4 +21,4 @@ export const rewriteBaseline = (raw: string | undefined, before: readonly Baseli
21
21
  rows.splice(at === -1 ? rows.length : at, 0, { entry, text: encodeEntry(entry) });
22
22
  }
23
23
  return rows.map((row) => `${row.text}\n`).join("");
24
- };
24
+ }
@@ -13,8 +13,8 @@ export interface Pruned {
13
13
  readonly removed: number;
14
14
  }
15
15
 
16
- const record = (violations: readonly Violation[]): readonly BaselineEntry[] =>
17
- [...groupBy(violations, (violation) => keyOf(violation.rule, violation.file)).values()].flatMap((group) => {
16
+ function record(violations: readonly Violation[]): readonly BaselineEntry[] {
17
+ return [...groupBy(violations, (violation) => keyOf(violation.rule, violation.file)).values()].flatMap((group) => {
18
18
  const first = group[0];
19
19
  if (first === undefined) {
20
20
  return [];
@@ -22,21 +22,22 @@ const record = (violations: readonly Violation[]): readonly BaselineEntry[] =>
22
22
  const count = countOf(group);
23
23
  return count > 0 ? [{ count, file: first.file, rule: first.rule }] : [];
24
24
  });
25
+ }
25
26
 
26
- const refusal = (id: string, index: RuleIndex): readonly string[] => {
27
+ function refusal(id: string, index: RuleIndex): readonly string[] {
27
28
  const level = levelOf(index, id);
28
29
  if (level === undefined) {
29
30
  return [`${id}: no built-in or local rule has this id.`];
30
31
  }
31
32
  return level === "error" ? [] : [`${id}: the rule is ${level}. Set it to error before baselining it.`];
32
- };
33
+ }
33
34
 
34
- export const adopt = (
35
+ export function adopt(
35
36
  existing: readonly BaselineEntry[] | undefined,
36
37
  rules: readonly string[],
37
38
  violations: readonly Violation[],
38
39
  index: RuleIndex,
39
- ): Adoption => {
40
+ ): Adoption {
40
41
  if (existing !== undefined && rules.length === 0) {
41
42
  return { _tag: "Refused", reasons: ["a baseline exists. Record a rule with --rule <id>, or drop fixed debt with prune."] };
42
43
  }
@@ -44,38 +45,41 @@ export const adopt = (
44
45
  if (reasons.length > 0) {
45
46
  return { _tag: "Refused", reasons };
46
47
  }
47
- const named = (rule: string): boolean => rules.some((name) => covers(name, rule));
48
+ function named(rule: string): boolean {
49
+ return rules.some((name) => covers(name, rule));
50
+ }
48
51
  const kept = (existing ?? []).filter((entry) => !named(entry.rule));
49
52
  const adopted = violations.filter((violation) => violation.level === "error" && (rules.length === 0 || named(violation.rule)));
50
53
  const added = record(adopted);
51
54
  return { _tag: "Adopted", added: added.length, entries: [...kept, ...added], replaced: (existing ?? []).length - kept.length };
52
- };
55
+ }
53
56
 
54
57
  export interface Scope {
55
58
  readonly files?: ReadonlySet<string> | undefined;
56
59
  readonly moves: ReadonlyMap<string, string>;
57
60
  }
58
61
 
59
- const inScope = (entry: BaselineEntry, scope: Scope): boolean =>
60
- scope.files === undefined || scope.files.has(entry.file) || scope.moves.has(entry.file);
62
+ function inScope(entry: BaselineEntry, scope: Scope): boolean {
63
+ return scope.files === undefined || scope.files.has(entry.file) || scope.moves.has(entry.file);
64
+ }
61
65
 
62
- const destination = (
66
+ function destination(
63
67
  before: BaselineEntry,
64
68
  current: ReadonlyMap<string, BaselineEntry>,
65
69
  moves: ReadonlyMap<string, string>,
66
70
  taken: ReadonlySet<string>,
67
- ) => {
71
+ ) {
68
72
  const to = moves.get(before.file);
69
73
  const key = to === undefined ? undefined : keyOf(before.rule, to);
70
74
  return key === undefined || taken.has(key) ? undefined : current.get(key);
71
- };
75
+ }
72
76
 
73
- export const prune = (
77
+ export function prune(
74
78
  existing: readonly BaselineEntry[],
75
79
  violations: readonly Violation[],
76
80
  index: RuleIndex,
77
81
  scope: Scope = { moves: new Map() },
78
- ): Pruned => {
82
+ ): Pruned {
79
83
  const current = new Map(record(violations).map((entry) => [keyOf(entry.rule, entry.file), entry]));
80
84
  const taken = new Set(existing.map((entry) => keyOf(entry.rule, entry.file)));
81
85
  let moved = 0;
@@ -97,4 +101,4 @@ export const prune = (
97
101
  moved,
98
102
  removed: existing.length - kept.length,
99
103
  };
100
- };
104
+ }
package/src/cli/args.ts CHANGED
@@ -31,7 +31,9 @@ const OPTIONS = {
31
31
  warnings: { type: "string" },
32
32
  } as const;
33
33
 
34
- const usage = (problem: string): Parsed => ({ _tag: "Usage", problem });
34
+ function usage(problem: string): Parsed {
35
+ return { _tag: "Usage", problem };
36
+ }
35
37
 
36
38
  const SUBCOMMANDS: Readonly<Record<string, string>> = {
37
39
  baseline: "baseline takes write, prune, tighten or migrate.",
@@ -39,7 +41,9 @@ const SUBCOMMANDS: Readonly<Record<string, string>> = {
39
41
  hooks: "hooks takes install, uninstall or pre-commit.",
40
42
  };
41
43
 
42
- const parsed = (command: Command): Parsed => ({ _tag: "Parsed", command });
44
+ function parsed(command: Command): Parsed {
45
+ return { _tag: "Parsed", command };
46
+ }
43
47
 
44
48
  type Values = ReturnType<typeof parseArgs<{ options: typeof OPTIONS; allowPositionals: true }>>["values"];
45
49
 
@@ -60,16 +64,17 @@ const ACCEPTS: Readonly<Record<string, readonly Option[]>> = {
60
64
  lint: ["warnings"],
61
65
  };
62
66
 
63
- const misplaced = (name: string, values: Values): string | undefined => {
67
+ function misplaced(name: string, values: Values): string | undefined {
64
68
  const option = COMMAND_OPTIONS.find((key) => values[key] !== undefined && !(ACCEPTS[name] ?? []).includes(key));
65
69
  const owners = Object.keys(ACCEPTS).filter((owner) => option !== undefined && (ACCEPTS[owner] ?? []).includes(option));
66
70
  return option === undefined ? undefined : `--${option} applies only to ${owners.join(" and ")}.`;
67
- };
71
+ }
68
72
 
69
- const ref = (against: string | undefined, command: Command): Parsed =>
70
- against?.startsWith("-") === true ? usage(`--against takes a git ref, not "${against}".`) : parsed(command);
73
+ function ref(against: string | undefined, command: Command): Parsed {
74
+ return against?.startsWith("-") === true ? usage(`--against takes a git ref, not "${against}".`) : parsed(command);
75
+ }
71
76
 
72
- const commandFor = (name: string, values: Values): Parsed => {
77
+ function commandFor(name: string, values: Values): Parsed {
73
78
  const config = values.config;
74
79
  switch (name) {
75
80
  case "lint": {
@@ -97,9 +102,9 @@ const commandFor = (name: string, values: Values): Parsed => {
97
102
  default:
98
103
  return parsed({ _tag: "BaselineMigrate", config, from: values.from });
99
104
  }
100
- };
105
+ }
101
106
 
102
- export const parseCommand = (args: readonly string[]): Parsed => {
107
+ export function parseCommand(args: readonly string[]): Parsed {
103
108
  const result = Result.try({
104
109
  catch: (error) => (error instanceof Error ? error.message : String(error)),
105
110
  try: () => parseArgs({ allowPositionals: true, args: [...args], options: OPTIONS, strict: true }),
@@ -122,4 +127,4 @@ export const parseCommand = (args: readonly string[]): Parsed => {
122
127
  }
123
128
  const problem = misplaced(name, values);
124
129
  return problem === undefined ? commandFor(name, values) : usage(problem);
125
- };
130
+ }
@@ -9,57 +9,58 @@ import { SetupFailure } from "#failure.ts";
9
9
  import { writeText } from "#inventory/filesystem.ts";
10
10
  import { plural } from "#report/plural.ts";
11
11
 
12
- const save = (session: Session, entries: readonly BaselineEntry[]): Effect.Effect<void, SetupFailure, FileSystem.FileSystem> =>
13
- Effect.mapError(
12
+ function save(session: Session, entries: readonly BaselineEntry[]): Effect.Effect<void, SetupFailure, FileSystem.FileSystem> {
13
+ return Effect.mapError(
14
14
  writeText(join(session.config.root, session.config.baseline), rewriteBaseline(session.baseline.raw, session.baseline.entries, entries)),
15
15
  (failure) => new SetupFailure({ message: failure.message }),
16
16
  );
17
+ }
17
18
 
18
- const unregistered = (session: Session) => applyRegistry(session.violations, session.registry, session.config).kept;
19
+ function unregistered(session: Session) {
20
+ return applyRegistry(session.violations, session.registry, session.config).kept;
21
+ }
19
22
 
20
- export const writeBaseline = (
23
+ export const writeBaseline = Effect.fn("Cli.writeBaseline")(function* (
21
24
  cwd: string,
22
25
  config: string | undefined,
23
26
  rules: readonly string[],
24
- ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem> =>
25
- Effect.gen(function* () {
26
- const session = yield* openSession(cwd, config);
27
- const existing = session.baseline.raw === undefined ? undefined : session.baseline.entries;
28
- const adoption = adopt(existing, rules, unregistered(session), session.config);
29
- if (adoption._tag === "Refused") {
30
- return yield* new SetupFailure({ message: `baseline write refused:\n${adoption.reasons.map((reason) => ` - ${reason}`).join("\n")}` });
31
- }
32
- if (adoption.added === 0 && adoption.replaced === 0) {
33
- return yield* Console.log(`quality: no error-level violations to record; ${session.config.baseline} is unchanged.`);
34
- }
35
- yield* save(session, adoption.entries);
36
- const replaced = adoption.replaced > 0 ? `, replacing ${plural(adoption.replaced, "entry", "entries")}` : "";
37
- yield* Console.log(`quality: recorded ${plural(adoption.added, "entry", "entries")} in ${session.config.baseline}${replaced}.`);
38
- });
27
+ ): Effect.fn.Return<void, SetupFailure, FileSystem.FileSystem> {
28
+ const session = yield* openSession(cwd, config);
29
+ const existing = session.baseline.raw === undefined ? undefined : session.baseline.entries;
30
+ const adoption = adopt(existing, rules, unregistered(session), session.config);
31
+ if (adoption._tag === "Refused") {
32
+ return yield* new SetupFailure({ message: `baseline write refused:\n${adoption.reasons.map((reason) => ` - ${reason}`).join("\n")}` });
33
+ }
34
+ if (adoption.added === 0 && adoption.replaced === 0) {
35
+ return yield* Console.log(`quality: no error-level violations to record; ${session.config.baseline} is unchanged.`);
36
+ }
37
+ yield* save(session, adoption.entries);
38
+ const replaced = adoption.replaced > 0 ? `, replacing ${plural(adoption.replaced, "entry", "entries")}` : "";
39
+ yield* Console.log(`quality: recorded ${plural(adoption.added, "entry", "entries")} in ${session.config.baseline}${replaced}.`);
40
+ });
39
41
 
40
- const changes = (pruned: Pruned): string => {
42
+ function changes(pruned: Pruned): string {
41
43
  const parts = [
42
44
  `removed ${plural(pruned.removed, "entry", "entries")}`,
43
45
  `lowered ${plural(pruned.lowered, "entry", "entries")}`,
44
46
  ...(pruned.moved > 0 ? [`carried ${plural(pruned.moved, "entry", "entries")} to moved files`] : []),
45
47
  ];
46
48
  return `${parts.slice(0, -1).join(", ")} and ${parts.at(-1)}`;
47
- };
49
+ }
48
50
 
49
- export const shrinkBaseline = <TRequirements>(
51
+ export const shrinkBaseline = Effect.fn("Cli.shrinkBaseline")(function* <TRequirements>(
50
52
  cwd: string,
51
53
  config: string | undefined,
52
54
  scopeOf: (session: Session) => Effect.Effect<Scope, SetupFailure, TRequirements>,
53
- ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem | TRequirements> =>
54
- Effect.gen(function* () {
55
- const session = yield* openSession(cwd, config);
56
- if (session.baseline.raw === undefined) {
57
- return yield* Console.log(`quality: no baseline at ${session.config.baseline}; nothing to lower.`);
58
- }
59
- const pruned = prune(session.baseline.entries, unregistered(session), session.config, yield* scopeOf(session));
60
- if (pruned.removed === 0 && pruned.lowered === 0 && pruned.moved === 0) {
61
- return yield* Console.log(`quality: ${session.config.baseline} is current.`);
62
- }
63
- yield* save(session, pruned.entries);
64
- yield* Console.log(`quality: ${changes(pruned)} in ${session.config.baseline}.`);
65
- });
55
+ ): Effect.fn.Return<void, SetupFailure, FileSystem.FileSystem | TRequirements> {
56
+ const session = yield* openSession(cwd, config);
57
+ if (session.baseline.raw === undefined) {
58
+ return yield* Console.log(`quality: no baseline at ${session.config.baseline}; nothing to lower.`);
59
+ }
60
+ const pruned = prune(session.baseline.entries, unregistered(session), session.config, yield* scopeOf(session));
61
+ if (pruned.removed === 0 && pruned.lowered === 0 && pruned.moved === 0) {
62
+ return yield* Console.log(`quality: ${session.config.baseline} is current.`);
63
+ }
64
+ yield* save(session, pruned.entries);
65
+ yield* Console.log(`quality: ${changes(pruned)} in ${session.config.baseline}.`);
66
+ });
package/src/cli/fix.ts CHANGED
@@ -62,24 +62,22 @@ function biomePasses(root: string, exceptions: readonly ExceptionDeclaration[]):
62
62
  ];
63
63
  }
64
64
 
65
- function round<TFailure, TRequirements>(
65
+ const round = Effect.fn("Cli.round")(function* <TFailure, TRequirements>(
66
66
  passes: readonly Pass<TFailure, TRequirements>[],
67
67
  index: number,
68
68
  afterEachPass: Effect.Effect<void, TFailure, TRequirements>,
69
- ): Effect.Effect<number, TFailure, TRequirements> {
70
- return Effect.gen(function* () {
71
- let total = 0;
72
- const parts: string[] = [];
73
- for (const pass of passes) {
74
- const changed = yield* pass.run;
75
- total += changed;
76
- parts.push(`${plural(changed, "file")} ${pass.label}`);
77
- yield* afterEachPass;
78
- }
79
- yield* Console.log(`quality: Biome round ${index} rewrote ${parts.join(" and ")}.`);
80
- return total;
81
- });
82
- }
69
+ ): Effect.fn.Return<number, TFailure, TRequirements> {
70
+ let total = 0;
71
+ const parts: string[] = [];
72
+ for (const pass of passes) {
73
+ const changed = yield* pass.run;
74
+ total += changed;
75
+ parts.push(`${plural(changed, "file")} ${pass.label}`);
76
+ yield* afterEachPass;
77
+ }
78
+ yield* Console.log(`quality: Biome round ${index} rewrote ${parts.join(" and ")}.`);
79
+ return total;
80
+ });
83
81
 
84
82
  function changedBetween(before: ReadonlyMap<string, string>, after: ReadonlyMap<string, string>): readonly string[] {
85
83
  return [...new Set([...before.keys(), ...after.keys()])].filter((path) => before.get(path) !== after.get(path));
@@ -100,36 +98,35 @@ function unsettled(changed: ReadonlySet<string>): SetupFailure {
100
98
  });
101
99
  }
102
100
 
103
- export function settle<TFailure, TRequirements>({
101
+ export const settle = Effect.fn("Cli.settle")(function* <TFailure, TRequirements>({
104
102
  passes,
105
103
  snapshot,
106
- }: Settling<TFailure, TRequirements>): Effect.Effect<void, TFailure | SetupFailure, TRequirements> {
107
- return Effect.gen(function* () {
108
- for (let index = 1; index < MAX_FIX_ROUNDS; index += 1) {
109
- if ((yield* round(passes, index, Effect.void)) === 0) {
110
- return;
111
- }
112
- }
113
- const changed = new Set<string>();
114
- let previous = yield* snapshot;
115
- const record = Effect.map(snapshot, (current) => {
116
- for (const path of changedBetween(previous, current)) {
117
- changed.add(path);
118
- }
119
- previous = current;
120
- });
121
- if ((yield* round(passes, MAX_FIX_ROUNDS, record)) === 0) {
104
+ }: Settling<TFailure, TRequirements>): Effect.fn.Return<void, TFailure | SetupFailure, TRequirements> {
105
+ for (let index = 1; index < MAX_FIX_ROUNDS; index += 1) {
106
+ if ((yield* round(passes, index, Effect.void)) === 0) {
122
107
  return;
123
108
  }
124
- return yield* unsettled(changed);
109
+ }
110
+ const changed = new Set<string>();
111
+ let previous = yield* snapshot;
112
+ const record = Effect.map(snapshot, (current) => {
113
+ for (const path of changedBetween(previous, current)) {
114
+ changed.add(path);
115
+ }
116
+ previous = current;
125
117
  });
126
- }
118
+ if ((yield* round(passes, MAX_FIX_ROUNDS, record)) === 0) {
119
+ return;
120
+ }
121
+ return yield* unsettled(changed);
122
+ });
127
123
 
128
- export function fix(cwd: string, config: string | undefined): Effect.Effect<void, SetupFailure, FileSystem.FileSystem> {
129
- return Effect.gen(function* () {
130
- const { root, exceptions } = yield* loadConfig(cwd, config);
131
- const sorted = yield* Effect.mapError(sortManifests(root), (failure) => new SetupFailure({ message: failure.message }));
132
- yield* Console.log(`quality: sort-package-json rewrote ${plural(sorted, "manifest")}.`);
133
- yield* settle({ passes: biomePasses(root, exceptions), snapshot: snapshotOf(root) });
134
- });
135
- }
124
+ export const fix = Effect.fn("Cli.fix")(function* (
125
+ cwd: string,
126
+ config: string | undefined,
127
+ ): Effect.fn.Return<void, SetupFailure, FileSystem.FileSystem> {
128
+ const { root, exceptions } = yield* loadConfig(cwd, config);
129
+ const sorted = yield* Effect.mapError(sortManifests(root), (failure) => new SetupFailure({ message: failure.message }));
130
+ yield* Console.log(`quality: sort-package-json rewrote ${plural(sorted, "manifest")}.`);
131
+ yield* settle({ passes: biomePasses(root, exceptions), snapshot: snapshotOf(root) });
132
+ });
package/src/cli/lint.ts CHANGED
@@ -5,25 +5,23 @@ import { openSession } from "#engine/session.ts";
5
5
  import { GateFailed, type SetupFailure } from "#failure.ts";
6
6
  import { render, type WarningDetail } from "#report/render.ts";
7
7
 
8
- export const lint = (
8
+ export const lint = Effect.fn("Cli.lint")(function* (
9
9
  cwd: string,
10
10
  config: string | undefined,
11
11
  warnings: WarningDetail,
12
- ): Effect.Effect<void, SetupFailure | GateFailed, FileSystem.FileSystem> =>
13
- Effect.gen(function* () {
14
- const session = yield* openSession(cwd, config);
15
- const outcome = evaluate(session.violations, session.registry, session.baseline.entries, session.config);
16
- yield* Console.log(
17
- render(outcome, {
18
- baseline: session.config.baseline,
19
- checked: session.inventory.sources.length,
20
- descriptions: new Map(session.config.active.map((rule) => [rule.id, rule.description])),
21
- registry:
22
- session.config.exceptions.length === 0 ? session.config.registry : `${relative(session.config.root, session.config.file)} exceptions`,
23
- warnings,
24
- }),
25
- );
26
- if (!passes(outcome)) {
27
- return yield* new GateFailed();
28
- }
29
- });
12
+ ): Effect.fn.Return<void, SetupFailure | GateFailed, FileSystem.FileSystem> {
13
+ const session = yield* openSession(cwd, config);
14
+ const outcome = evaluate(session.violations, session.registry, session.baseline.entries, session.config);
15
+ yield* Console.log(
16
+ render(outcome, {
17
+ baseline: session.config.baseline,
18
+ checked: session.inventory.sources.length,
19
+ descriptions: new Map(session.config.active.map((rule) => [rule.id, rule.description])),
20
+ registry: session.config.exceptions.length === 0 ? session.config.registry : `${relative(session.config.root, session.config.file)} exceptions`,
21
+ warnings,
22
+ }),
23
+ );
24
+ if (!passes(outcome)) {
25
+ return yield* new GateFailed();
26
+ }
27
+ });
@@ -10,27 +10,26 @@ import { SetupFailure } from "#failure.ts";
10
10
  import { writeText } from "#inventory/filesystem.ts";
11
11
  import { plural } from "#report/plural.ts";
12
12
 
13
- export const migrateBaseline = (
13
+ export const migrateBaseline = Effect.fn("Cli.migrateBaseline")(function* (
14
14
  cwd: string,
15
15
  configPath: string | undefined,
16
16
  from: string | undefined,
17
- ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem> =>
18
- Effect.gen(function* () {
19
- const config = yield* loadConfig(cwd, configPath);
20
- const source = from ?? LEGACY_BASELINE;
21
- if (source === config.baseline || (yield* readInput(config.root, config.baseline)) !== undefined) {
22
- return yield* new SetupFailure({ message: `${config.baseline} already exists. Migrate into a baseline file that does not exist yet.` });
23
- }
24
- const raw = yield* readInput(config.root, source);
25
- if (raw === undefined) {
26
- return yield* new SetupFailure({ message: `no baseline at ${source} to migrate. Name it with --from <file>.` });
27
- }
28
- const legacy = yield* validOrFail(source, yield* Effect.promise(() => decodeLegacyBaseline(raw)));
29
- const entries = convertLegacy(legacy, (yield* scan(config)).violations);
30
- const fs = yield* FileSystem.FileSystem;
31
- const written = Effect.andThen(writeText(join(config.root, config.baseline), encodeBaseline(entries)), fs.remove(join(config.root, source)));
32
- yield* Effect.mapError(written, (failure) => new SetupFailure({ message: failure.message }));
33
- const fixed = legacy.length - entries.length;
34
- const dropped = fixed > 0 ? `, dropping ${plural(fixed, "fixed entry", "fixed entries")}` : "";
35
- yield* Console.log(`quality: moved ${plural(entries.length, "entry", "entries")} from ${source} to ${config.baseline}${dropped}.`);
36
- });
17
+ ): Effect.fn.Return<void, SetupFailure, FileSystem.FileSystem> {
18
+ const config = yield* loadConfig(cwd, configPath);
19
+ const source = from ?? LEGACY_BASELINE;
20
+ if (source === config.baseline || (yield* readInput(config.root, config.baseline)) !== undefined) {
21
+ return yield* new SetupFailure({ message: `${config.baseline} already exists. Migrate into a baseline file that does not exist yet.` });
22
+ }
23
+ const raw = yield* readInput(config.root, source);
24
+ if (raw === undefined) {
25
+ return yield* new SetupFailure({ message: `no baseline at ${source} to migrate. Name it with --from <file>.` });
26
+ }
27
+ const legacy = yield* validOrFail(source, yield* Effect.promise(() => decodeLegacyBaseline(raw)));
28
+ const entries = convertLegacy(legacy, (yield* scan(config)).violations);
29
+ const fs = yield* FileSystem.FileSystem;
30
+ const written = Effect.andThen(writeText(join(config.root, config.baseline), encodeBaseline(entries)), fs.remove(join(config.root, source)));
31
+ yield* Effect.mapError(written, (failure) => new SetupFailure({ message: failure.message }));
32
+ const fixed = legacy.length - entries.length;
33
+ const dropped = fixed > 0 ? `, dropping ${plural(fixed, "fixed entry", "fixed entries")}` : "";
34
+ yield* Console.log(`quality: moved ${plural(entries.length, "entry", "entries")} from ${source} to ${config.baseline}${dropped}.`);
35
+ });
@@ -30,9 +30,9 @@ export function exitCode(exit: Exit.Exit<unknown, unknown>): number {
30
30
  return Cause.hasInterruptsOnly(exit.cause) ? INTERRUPTED : exitCodeOf(Cause.squash(exit.cause));
31
31
  }
32
32
 
33
- const teardown: Runtime.Teardown = (exit, onExit) => {
33
+ function teardown(exit: Parameters<Runtime.Teardown>[0], onExit: Parameters<Runtime.Teardown>[1]): void {
34
34
  process.stdout.write("", () => process.stderr.write("", () => onExit(exitCode(exit))));
35
- };
35
+ }
36
36
 
37
37
  function isClosedPipe(error: unknown): boolean {
38
38
  return error instanceof Error && "code" in error && error.code === "EPIPE";
package/src/cli/shrink.ts CHANGED
@@ -6,8 +6,8 @@ import type { Git } from "#git/command.ts";
6
6
  import { changesSince } from "#git/history.ts";
7
7
  import { shrinkBaseline } from "./baseline.ts";
8
8
 
9
- const followedMoves = (root: string, against: string | undefined): Effect.Effect<Scope, SetupFailure, Git> =>
10
- resolveBase(root, against).pipe(
9
+ function followedMoves(root: string, against: string | undefined): Effect.Effect<Scope, SetupFailure, Git> {
10
+ return resolveBase(root, against).pipe(
11
11
  Effect.flatMap((base) => changesSince(root, [base.commit])),
12
12
  Effect.map((changes): Scope => ({ moves: changes.moves })),
13
13
  Effect.catchIf(
@@ -15,17 +15,20 @@ const followedMoves = (root: string, against: string | undefined): Effect.Effect
15
15
  (failure) => Effect.as(Console.error(`quality: moved files are not followed: ${failure.message}`), { moves: new Map() }),
16
16
  ),
17
17
  );
18
+ }
18
19
 
19
- export const pruneBaseline = (
20
+ export function pruneBaseline(
20
21
  cwd: string,
21
22
  config: string | undefined,
22
23
  against: string | undefined,
23
- ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem | Git> =>
24
- shrinkBaseline(cwd, config, (session) => followedMoves(session.config.root, against));
24
+ ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem | Git> {
25
+ return shrinkBaseline(cwd, config, (session) => followedMoves(session.config.root, against));
26
+ }
25
27
 
26
- export const tightenBaseline = (
28
+ export function tightenBaseline(
27
29
  cwd: string,
28
30
  config: string | undefined,
29
31
  staged: boolean,
30
- ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem | Git> =>
31
- shrinkBaseline(cwd, config, (session) => changesSince(session.config.root, staged ? ["--cached"] : ["HEAD"]));
32
+ ): Effect.Effect<void, SetupFailure, FileSystem.FileSystem | Git> {
33
+ return shrinkBaseline(cwd, config, (session) => changesSince(session.config.root, staged ? ["--cached"] : ["HEAD"]));
34
+ }