@skastr0/pulsar-rs-pack 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 (189) hide show
  1. package/dist/cargo-metadata.d.ts +59 -0
  2. package/dist/cargo-metadata.d.ts.map +1 -0
  3. package/dist/cargo-metadata.js +162 -0
  4. package/dist/cargo-metadata.js.map +1 -0
  5. package/dist/index.d.ts +7 -0
  6. package/dist/index.d.ts.map +1 -0
  7. package/dist/index.js +7 -0
  8. package/dist/index.js.map +1 -0
  9. package/dist/lock-file.d.ts +20 -0
  10. package/dist/lock-file.d.ts.map +1 -0
  11. package/dist/lock-file.js +144 -0
  12. package/dist/lock-file.js.map +1 -0
  13. package/dist/pack.d.ts +6 -0
  14. package/dist/pack.d.ts.map +1 -0
  15. package/dist/pack.js +55 -0
  16. package/dist/pack.js.map +1 -0
  17. package/dist/project.d.ts +26 -0
  18. package/dist/project.d.ts.map +1 -0
  19. package/dist/project.js +172 -0
  20. package/dist/project.js.map +1 -0
  21. package/dist/rust-analysis-collect.d.ts +4 -0
  22. package/dist/rust-analysis-collect.d.ts.map +1 -0
  23. package/dist/rust-analysis-collect.js +84 -0
  24. package/dist/rust-analysis-collect.js.map +1 -0
  25. package/dist/rust-analysis-functions.d.ts +4 -0
  26. package/dist/rust-analysis-functions.d.ts.map +1 -0
  27. package/dist/rust-analysis-functions.js +140 -0
  28. package/dist/rust-analysis-functions.js.map +1 -0
  29. package/dist/rust-analysis-identifiers.d.ts +3 -0
  30. package/dist/rust-analysis-identifiers.d.ts.map +1 -0
  31. package/dist/rust-analysis-identifiers.js +5 -0
  32. package/dist/rust-analysis-identifiers.js.map +1 -0
  33. package/dist/rust-analysis-items.d.ts +4 -0
  34. package/dist/rust-analysis-items.d.ts.map +1 -0
  35. package/dist/rust-analysis-items.js +58 -0
  36. package/dist/rust-analysis-items.js.map +1 -0
  37. package/dist/rust-analysis-modules.d.ts +7 -0
  38. package/dist/rust-analysis-modules.d.ts.map +1 -0
  39. package/dist/rust-analysis-modules.js +52 -0
  40. package/dist/rust-analysis-modules.js.map +1 -0
  41. package/dist/rust-analysis-syntax.d.ts +12 -0
  42. package/dist/rust-analysis-syntax.d.ts.map +1 -0
  43. package/dist/rust-analysis-syntax.js +102 -0
  44. package/dist/rust-analysis-syntax.js.map +1 -0
  45. package/dist/rust-analysis-types.d.ts +109 -0
  46. package/dist/rust-analysis-types.d.ts.map +1 -0
  47. package/dist/rust-analysis-types.js +2 -0
  48. package/dist/rust-analysis-types.js.map +1 -0
  49. package/dist/rust-analysis-uses.d.ts +4 -0
  50. package/dist/rust-analysis-uses.d.ts.map +1 -0
  51. package/dist/rust-analysis-uses.js +63 -0
  52. package/dist/rust-analysis-uses.js.map +1 -0
  53. package/dist/rust-analysis.d.ts +5 -0
  54. package/dist/rust-analysis.d.ts.map +1 -0
  55. package/dist/rust-analysis.js +4 -0
  56. package/dist/rust-analysis.js.map +1 -0
  57. package/dist/signals/rs-ab-01-unused-pub.d.ts +29 -0
  58. package/dist/signals/rs-ab-01-unused-pub.d.ts.map +1 -0
  59. package/dist/signals/rs-ab-01-unused-pub.js +184 -0
  60. package/dist/signals/rs-ab-01-unused-pub.js.map +1 -0
  61. package/dist/signals/rs-ab-02-trait-object-depth.d.ts +26 -0
  62. package/dist/signals/rs-ab-02-trait-object-depth.d.ts.map +1 -0
  63. package/dist/signals/rs-ab-02-trait-object-depth.js +157 -0
  64. package/dist/signals/rs-ab-02-trait-object-depth.js.map +1 -0
  65. package/dist/signals/rs-ab-03-generic-proliferation.d.ts +28 -0
  66. package/dist/signals/rs-ab-03-generic-proliferation.d.ts.map +1 -0
  67. package/dist/signals/rs-ab-03-generic-proliferation.js +108 -0
  68. package/dist/signals/rs-ab-03-generic-proliferation.js.map +1 -0
  69. package/dist/signals/rs-ab-04-derive-density.d.ts +25 -0
  70. package/dist/signals/rs-ab-04-derive-density.d.ts.map +1 -0
  71. package/dist/signals/rs-ab-04-derive-density.js +101 -0
  72. package/dist/signals/rs-ab-04-derive-density.js.map +1 -0
  73. package/dist/signals/rs-ad-01-visibility-surface.d.ts +29 -0
  74. package/dist/signals/rs-ad-01-visibility-surface.d.ts.map +1 -0
  75. package/dist/signals/rs-ad-01-visibility-surface.js +129 -0
  76. package/dist/signals/rs-ad-01-visibility-surface.js.map +1 -0
  77. package/dist/signals/rs-ad-02-boundary-rules.d.ts +3 -0
  78. package/dist/signals/rs-ad-02-boundary-rules.d.ts.map +1 -0
  79. package/dist/signals/rs-ad-02-boundary-rules.js +26 -0
  80. package/dist/signals/rs-ad-02-boundary-rules.js.map +1 -0
  81. package/dist/signals/rs-ad-02-crate-analysis.d.ts +9 -0
  82. package/dist/signals/rs-ad-02-crate-analysis.d.ts.map +1 -0
  83. package/dist/signals/rs-ad-02-crate-analysis.js +117 -0
  84. package/dist/signals/rs-ad-02-crate-analysis.js.map +1 -0
  85. package/dist/signals/rs-ad-02-crate-boundaries.d.ts +6 -0
  86. package/dist/signals/rs-ad-02-crate-boundaries.d.ts.map +1 -0
  87. package/dist/signals/rs-ad-02-crate-boundaries.js +84 -0
  88. package/dist/signals/rs-ad-02-crate-boundaries.js.map +1 -0
  89. package/dist/signals/rs-ad-02-types.d.ts +26 -0
  90. package/dist/signals/rs-ad-02-types.d.ts.map +1 -0
  91. package/dist/signals/rs-ad-02-types.js +6 -0
  92. package/dist/signals/rs-ad-02-types.js.map +1 -0
  93. package/dist/signals/rs-ad-03-circular-crate-deps.d.ts +30 -0
  94. package/dist/signals/rs-ad-03-circular-crate-deps.d.ts.map +1 -0
  95. package/dist/signals/rs-ad-03-circular-crate-deps.js +185 -0
  96. package/dist/signals/rs-ad-03-circular-crate-deps.js.map +1 -0
  97. package/dist/signals/rs-de-01-trait-coupling.d.ts +43 -0
  98. package/dist/signals/rs-de-01-trait-coupling.d.ts.map +1 -0
  99. package/dist/signals/rs-de-01-trait-coupling.js +222 -0
  100. package/dist/signals/rs-de-01-trait-coupling.js.map +1 -0
  101. package/dist/signals/rs-de-02-dep-tree.d.ts +28 -0
  102. package/dist/signals/rs-de-02-dep-tree.d.ts.map +1 -0
  103. package/dist/signals/rs-de-02-dep-tree.js +173 -0
  104. package/dist/signals/rs-de-02-dep-tree.js.map +1 -0
  105. package/dist/signals/rs-de-03-feature-flags.d.ts +32 -0
  106. package/dist/signals/rs-de-03-feature-flags.d.ts.map +1 -0
  107. package/dist/signals/rs-de-03-feature-flags.js +139 -0
  108. package/dist/signals/rs-de-03-feature-flags.js.map +1 -0
  109. package/dist/signals/rs-de-04-fan-in-fan-out.d.ts +28 -0
  110. package/dist/signals/rs-de-04-fan-in-fan-out.d.ts.map +1 -0
  111. package/dist/signals/rs-de-04-fan-in-fan-out.js +109 -0
  112. package/dist/signals/rs-de-04-fan-in-fan-out.js.map +1 -0
  113. package/dist/signals/rs-ld-01-unsafe.d.ts +28 -0
  114. package/dist/signals/rs-ld-01-unsafe.d.ts.map +1 -0
  115. package/dist/signals/rs-ld-01-unsafe.js +116 -0
  116. package/dist/signals/rs-ld-01-unsafe.js.map +1 -0
  117. package/dist/signals/rs-ld-02-lifetimes.d.ts +30 -0
  118. package/dist/signals/rs-ld-02-lifetimes.d.ts.map +1 -0
  119. package/dist/signals/rs-ld-02-lifetimes.js +79 -0
  120. package/dist/signals/rs-ld-02-lifetimes.js.map +1 -0
  121. package/dist/signals/rs-ld-03-match-catch-all.d.ts +26 -0
  122. package/dist/signals/rs-ld-03-match-catch-all.d.ts.map +1 -0
  123. package/dist/signals/rs-ld-03-match-catch-all.js +68 -0
  124. package/dist/signals/rs-ld-03-match-catch-all.js.map +1 -0
  125. package/dist/signals/rs-ld-04-error-granularity.d.ts +25 -0
  126. package/dist/signals/rs-ld-04-error-granularity.d.ts.map +1 -0
  127. package/dist/signals/rs-ld-04-error-granularity.js +77 -0
  128. package/dist/signals/rs-ld-04-error-granularity.js.map +1 -0
  129. package/dist/signals/rs-ld-05-complexity.d.ts +26 -0
  130. package/dist/signals/rs-ld-05-complexity.d.ts.map +1 -0
  131. package/dist/signals/rs-ld-05-complexity.js +70 -0
  132. package/dist/signals/rs-ld-05-complexity.js.map +1 -0
  133. package/dist/signals/rs-ld-06-domain-terms.d.ts +29 -0
  134. package/dist/signals/rs-ld-06-domain-terms.d.ts.map +1 -0
  135. package/dist/signals/rs-ld-06-domain-terms.js +158 -0
  136. package/dist/signals/rs-ld-06-domain-terms.js.map +1 -0
  137. package/dist/signals/rs-rp-01-hotspots.d.ts +27 -0
  138. package/dist/signals/rs-rp-01-hotspots.d.ts.map +1 -0
  139. package/dist/signals/rs-rp-01-hotspots.js +110 -0
  140. package/dist/signals/rs-rp-01-hotspots.js.map +1 -0
  141. package/dist/signals/rs-rp-02-compile-time.d.ts +25 -0
  142. package/dist/signals/rs-rp-02-compile-time.d.ts.map +1 -0
  143. package/dist/signals/rs-rp-02-compile-time.js +177 -0
  144. package/dist/signals/rs-rp-02-compile-time.js.map +1 -0
  145. package/dist/signals/rs-rp-03-pr-size.d.ts +23 -0
  146. package/dist/signals/rs-rp-03-pr-size.d.ts.map +1 -0
  147. package/dist/signals/rs-rp-03-pr-size.js +160 -0
  148. package/dist/signals/rs-rp-03-pr-size.js.map +1 -0
  149. package/dist/signals/rs-sl-01-duplication.d.ts +28 -0
  150. package/dist/signals/rs-sl-01-duplication.d.ts.map +1 -0
  151. package/dist/signals/rs-sl-01-duplication.js +172 -0
  152. package/dist/signals/rs-sl-01-duplication.js.map +1 -0
  153. package/dist/signals/rs-sl-02-suppressions.d.ts +30 -0
  154. package/dist/signals/rs-sl-02-suppressions.d.ts.map +1 -0
  155. package/dist/signals/rs-sl-02-suppressions.js +176 -0
  156. package/dist/signals/rs-sl-02-suppressions.js.map +1 -0
  157. package/dist/signals/rs-sl-03-unwrap-expect.d.ts +22 -0
  158. package/dist/signals/rs-sl-03-unwrap-expect.d.ts.map +1 -0
  159. package/dist/signals/rs-sl-03-unwrap-expect.js +94 -0
  160. package/dist/signals/rs-sl-03-unwrap-expect.js.map +1 -0
  161. package/dist/signals/rs-sl-04-clone-abuse.d.ts +22 -0
  162. package/dist/signals/rs-sl-04-clone-abuse.d.ts.map +1 -0
  163. package/dist/signals/rs-sl-04-clone-abuse.js +115 -0
  164. package/dist/signals/rs-sl-04-clone-abuse.js.map +1 -0
  165. package/dist/signals/shared-globs.d.ts +4 -0
  166. package/dist/signals/shared-globs.d.ts.map +1 -0
  167. package/dist/signals/shared-globs.js +12 -0
  168. package/dist/signals/shared-globs.js.map +1 -0
  169. package/dist/signals/shared-record-guards.d.ts +4 -0
  170. package/dist/signals/shared-record-guards.d.ts.map +1 -0
  171. package/dist/signals/shared-record-guards.js +4 -0
  172. package/dist/signals/shared-record-guards.js.map +1 -0
  173. package/dist/signals/shared-rust-ast.d.ts +30 -0
  174. package/dist/signals/shared-rust-ast.d.ts.map +1 -0
  175. package/dist/signals/shared-rust-ast.js +78 -0
  176. package/dist/signals/shared-rust-ast.js.map +1 -0
  177. package/dist/signals/shared-rust-resolution.d.ts +10 -0
  178. package/dist/signals/shared-rust-resolution.d.ts.map +1 -0
  179. package/dist/signals/shared-rust-resolution.js +53 -0
  180. package/dist/signals/shared-rust-resolution.js.map +1 -0
  181. package/dist/signals/shared-threshold-score.d.ts +2 -0
  182. package/dist/signals/shared-threshold-score.d.ts.map +1 -0
  183. package/dist/signals/shared-threshold-score.js +6 -0
  184. package/dist/signals/shared-threshold-score.js.map +1 -0
  185. package/dist/syn-walker.d.ts +7 -0
  186. package/dist/syn-walker.d.ts.map +1 -0
  187. package/dist/syn-walker.js +61 -0
  188. package/dist/syn-walker.js.map +1 -0
  189. package/package.json +56 -0
@@ -0,0 +1,28 @@
1
+ import { type Signal } from "@skastr0/pulsar-core/signal";
2
+ import { Schema } from "effect";
3
+ import { RustProjectTag } from "../project.js";
4
+ declare const RsDe04Config: Schema.Struct<{
5
+ exclude_globs: Schema.Array$<typeof Schema.String>;
6
+ hub_fan_in_threshold: typeof Schema.Number;
7
+ hub_fan_out_threshold: typeof Schema.Number;
8
+ top_n_diagnostics: typeof Schema.Number;
9
+ }>;
10
+ type RsDe04Config = typeof RsDe04Config.Type;
11
+ interface RustModuleFan {
12
+ readonly module: string;
13
+ readonly file: string;
14
+ readonly fanIn: number;
15
+ readonly fanOut: number;
16
+ }
17
+ interface RsDe04Output {
18
+ readonly modules: ReadonlyArray<RustModuleFan>;
19
+ readonly byModule: ReadonlyMap<string, {
20
+ readonly fanIn: number;
21
+ readonly fanOut: number;
22
+ }>;
23
+ readonly hubs: ReadonlyArray<RustModuleFan>;
24
+ readonly analysisMode: "explicit-use-resolution";
25
+ }
26
+ export declare const RsDe04: Signal<RsDe04Config, RsDe04Output, RustProjectTag>;
27
+ export {};
28
+ //# sourceMappingURL=rs-de-04-fan-in-fan-out.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-de-04-fan-in-fan-out.d.ts","sourceRoot":"","sources":["../../src/signals/rs-de-04-fan-in-fan-out.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAEZ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAQ9C,QAAA,MAAM,YAAY;;;;;EAKhB,CAAA;AACF,KAAK,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAE5C,UAAU,aAAa;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;CACxB;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAC9C,QAAQ,CAAC,QAAQ,EAAE,WAAW,CAAC,MAAM,EAAE;QAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;IAC3F,QAAQ,CAAC,IAAI,EAAE,aAAa,CAAC,aAAa,CAAC,CAAA;IAC3C,QAAQ,CAAC,YAAY,EAAE,yBAAyB,CAAA;CACjD;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CA8FrE,CAAA"}
@@ -0,0 +1,109 @@
1
+ import { SignalComputeError, } from "@skastr0/pulsar-core/signal";
2
+ import { Effect, Schema } from "effect";
3
+ import { collectRustProjectFacts } from "../rust-analysis.js";
4
+ import { RustProjectTag } from "../project.js";
5
+ import { resolveCrateRelativePath, toLocalRelativeSegments, } from "./shared-rust-resolution.js";
6
+ import { DEFAULT_RUST_EXCLUDE_GLOBS } from "./shared-rust-ast.js";
7
+ import { isExcluded } from "./shared-globs.js";
8
+ const RsDe04Config = Schema.Struct({
9
+ exclude_globs: Schema.Array(Schema.String),
10
+ hub_fan_in_threshold: Schema.Number,
11
+ hub_fan_out_threshold: Schema.Number,
12
+ top_n_diagnostics: Schema.Number,
13
+ });
14
+ export const RsDe04 = {
15
+ id: "RS-DE-04-fan-in-fan-out",
16
+ title: "Fan-in/fan-out",
17
+ aliases: ["RS-DE-04"],
18
+ tier: 1,
19
+ category: "dependency-entropy",
20
+ kind: "structural",
21
+ configSchema: RsDe04Config,
22
+ defaultConfig: {
23
+ exclude_globs: [...DEFAULT_RUST_EXCLUDE_GLOBS],
24
+ hub_fan_in_threshold: 6,
25
+ hub_fan_out_threshold: 4,
26
+ top_n_diagnostics: 10,
27
+ },
28
+ inputs: [],
29
+ compute: (config) => Effect.gen(function* () {
30
+ const project = yield* RustProjectTag;
31
+ return yield* Effect.tryPromise({
32
+ try: async () => {
33
+ const facts = await collectRustProjectFacts(project);
34
+ const rootNamesByCrate = new Map();
35
+ for (const module of facts.modules) {
36
+ const bucket = rootNamesByCrate.get(module.crateName) ?? new Set();
37
+ const segments = module.relativeModulePath.split("::");
38
+ const root = segments[1];
39
+ if (segments[0] === "crate" && root !== undefined)
40
+ bucket.add(root);
41
+ rootNamesByCrate.set(module.crateName, bucket);
42
+ }
43
+ for (const item of facts.items) {
44
+ if (item.relativeModulePath !== "crate")
45
+ continue;
46
+ const bucket = rootNamesByCrate.get(item.crateName) ?? new Set();
47
+ bucket.add(item.name);
48
+ rootNamesByCrate.set(item.crateName, bucket);
49
+ }
50
+ const incoming = new Map();
51
+ const outgoing = new Map();
52
+ const modules = facts.modules.filter((module) => !isExcluded(module.file, config.exclude_globs));
53
+ for (const module of modules) {
54
+ incoming.set(module.modulePath, new Set());
55
+ outgoing.set(module.modulePath, new Set());
56
+ }
57
+ for (const useFact of facts.uses) {
58
+ if (isExcluded(useFact.file, config.exclude_globs))
59
+ continue;
60
+ const target = resolveLocalUseTarget(useFact, facts, rootNamesByCrate);
61
+ if (target === undefined || target === useFact.modulePath)
62
+ continue;
63
+ outgoing.get(useFact.modulePath)?.add(target);
64
+ incoming.get(target)?.add(useFact.modulePath);
65
+ }
66
+ const summaries = modules
67
+ .map((module) => ({
68
+ module: module.modulePath,
69
+ file: module.file,
70
+ fanIn: incoming.get(module.modulePath)?.size ?? 0,
71
+ fanOut: outgoing.get(module.modulePath)?.size ?? 0,
72
+ }))
73
+ .sort((left, right) => right.fanIn + right.fanOut - (left.fanIn + left.fanOut) || left.module.localeCompare(right.module));
74
+ return {
75
+ modules: summaries,
76
+ byModule: new Map(summaries.map((module) => [module.module, { fanIn: module.fanIn, fanOut: module.fanOut }])),
77
+ hubs: summaries.filter((module) => module.fanIn >= config.hub_fan_in_threshold &&
78
+ module.fanOut >= config.hub_fan_out_threshold),
79
+ analysisMode: "explicit-use-resolution",
80
+ };
81
+ },
82
+ catch: (cause) => new SignalComputeError({ signalId: "RS-DE-04-fan-in-fan-out", message: String(cause), cause }),
83
+ });
84
+ }),
85
+ score: (out) => {
86
+ if (out.modules.length === 0)
87
+ return 1;
88
+ return Math.max(0, 1 - (out.hubs.length / out.modules.length) * 3);
89
+ },
90
+ diagnose: (out) => out.hubs.slice(0, 10).map((module) => ({
91
+ severity: "warn",
92
+ message: `Module ${module.module} is a coupling hub (fanIn=${module.fanIn}, fanOut=${module.fanOut})`,
93
+ location: { file: module.file },
94
+ data: {
95
+ module: module.module,
96
+ fanIn: module.fanIn,
97
+ fanOut: module.fanOut,
98
+ analysisMode: out.analysisMode,
99
+ },
100
+ })),
101
+ };
102
+ const resolveLocalUseTarget = (useFact, facts, rootNamesByCrate) => {
103
+ const relativeSegments = toLocalRelativeSegments(useFact, rootNamesByCrate.get(useFact.crateName) ?? new Set());
104
+ if (relativeSegments === undefined)
105
+ return undefined;
106
+ const resolved = resolveCrateRelativePath(useFact.crateName, relativeSegments, facts);
107
+ return resolved?.item?.modulePath ?? resolved?.module?.modulePath;
108
+ };
109
+ //# sourceMappingURL=rs-de-04-fan-in-fan-out.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-de-04-fan-in-fan-out.js","sourceRoot":"","sources":["../../src/signals/rs-de-04-fan-in-fan-out.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import { type Signal } from "@skastr0/pulsar-core/signal";
2
+ import { Schema } from "effect";
3
+ import { RustProjectTag } from "../project.js";
4
+ declare const RsLd01Config: Schema.Struct<{
5
+ exclude_globs: Schema.Array$<typeof Schema.String>;
6
+ safe_only_modules: Schema.Array$<typeof Schema.String>;
7
+ top_n_diagnostics: typeof Schema.Number;
8
+ }>;
9
+ type RsLd01Config = typeof RsLd01Config.Type;
10
+ interface UnsafeModuleSummary {
11
+ readonly module: string;
12
+ readonly file: string;
13
+ readonly totalFunctions: number;
14
+ readonly unsafeBlockCount: number;
15
+ readonly unsafeFunctionCount: number;
16
+ readonly propagatingFunctionCount: number;
17
+ readonly unsafeDensity: number;
18
+ }
19
+ interface RsLd01Output {
20
+ readonly modules: ReadonlyArray<UnsafeModuleSummary>;
21
+ readonly totalUnsafeBlocks: number;
22
+ readonly totalUnsafeFunctions: number;
23
+ readonly safeOnlyViolations: ReadonlyArray<UnsafeModuleSummary>;
24
+ readonly propagationMode: "local-signature-only";
25
+ }
26
+ export declare const RsLd01: Signal<RsLd01Config, RsLd01Output, RustProjectTag>;
27
+ export {};
28
+ //# sourceMappingURL=rs-ld-01-unsafe.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-01-unsafe.d.ts","sourceRoot":"","sources":["../../src/signals/rs-ld-01-unsafe.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAEZ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C,QAAA,MAAM,YAAY;;;;EAIhB,CAAA;AACF,KAAK,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAE5C,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;IACjC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,QAAQ,CAAC,wBAAwB,EAAE,MAAM,CAAA;IACzC,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;CAC/B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IACpD,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;IAClC,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;IACrC,QAAQ,CAAC,kBAAkB,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAC/D,QAAQ,CAAC,eAAe,EAAE,sBAAsB,CAAA;CACjD;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CA8GrE,CAAA"}
@@ -0,0 +1,116 @@
1
+ import { SignalComputeError, } from "@skastr0/pulsar-core/signal";
2
+ import { Effect, Schema } from "effect";
3
+ import { collectRustProjectFacts } from "../rust-analysis.js";
4
+ import { RustProjectTag } from "../project.js";
5
+ import { isExcluded } from "./shared-globs.js";
6
+ const RsLd01Config = Schema.Struct({
7
+ exclude_globs: Schema.Array(Schema.String),
8
+ safe_only_modules: Schema.Array(Schema.String),
9
+ top_n_diagnostics: Schema.Number,
10
+ });
11
+ export const RsLd01 = {
12
+ id: "RS-LD-01-unsafe-code",
13
+ title: "Unsafe code",
14
+ aliases: ["RS-LD-01"],
15
+ tier: 1,
16
+ category: "legibility-decay",
17
+ kind: "legibility",
18
+ configSchema: RsLd01Config,
19
+ defaultConfig: {
20
+ exclude_globs: ["**/target/**", "**/tests/**", "**/examples/**", "**/benches/**"],
21
+ safe_only_modules: [],
22
+ top_n_diagnostics: 10,
23
+ },
24
+ inputs: [],
25
+ compute: (config) => Effect.gen(function* () {
26
+ const project = yield* RustProjectTag;
27
+ return yield* Effect.tryPromise({
28
+ try: async () => {
29
+ const facts = await collectRustProjectFacts(project);
30
+ const grouped = new Map();
31
+ for (const fn of facts.functions) {
32
+ if (isExcluded(fn.file, config.exclude_globs))
33
+ continue;
34
+ const current = grouped.get(fn.modulePath);
35
+ const next = current === undefined
36
+ ? {
37
+ module: fn.modulePath,
38
+ file: fn.file,
39
+ totalFunctions: 0,
40
+ unsafeBlockCount: 0,
41
+ unsafeFunctionCount: 0,
42
+ propagatingFunctionCount: 0,
43
+ unsafeDensity: 0,
44
+ }
45
+ : { ...current };
46
+ next.totalFunctions += 1;
47
+ next.unsafeBlockCount += fn.unsafeBlockCount;
48
+ if (fn.isUnsafeFn)
49
+ next.unsafeFunctionCount += 1;
50
+ if (isPropagatingUnsafe(fn))
51
+ next.propagatingFunctionCount += 1;
52
+ grouped.set(fn.modulePath, next);
53
+ }
54
+ const modules = [...grouped.values()]
55
+ .map((module) => ({
56
+ ...module,
57
+ unsafeDensity: module.totalFunctions === 0
58
+ ? 0
59
+ : (module.unsafeBlockCount + module.unsafeFunctionCount) / module.totalFunctions,
60
+ }))
61
+ .sort((a, b) => b.unsafeDensity - a.unsafeDensity || b.propagatingFunctionCount - a.propagatingFunctionCount);
62
+ return {
63
+ modules,
64
+ totalUnsafeBlocks: modules.reduce((sum, module) => sum + module.unsafeBlockCount, 0),
65
+ totalUnsafeFunctions: modules.reduce((sum, module) => sum + module.unsafeFunctionCount, 0),
66
+ safeOnlyViolations: modules.filter((module) => config.safe_only_modules.includes(module.module) &&
67
+ module.unsafeBlockCount + module.unsafeFunctionCount > 0),
68
+ propagationMode: "local-signature-only",
69
+ };
70
+ },
71
+ catch: (cause) => new SignalComputeError({ signalId: "RS-LD-01-unsafe-code", message: String(cause), cause }),
72
+ });
73
+ }),
74
+ score: (out) => {
75
+ if (out.safeOnlyViolations.length > 0)
76
+ return 0;
77
+ const totalFunctions = out.modules.reduce((sum, module) => sum + module.totalFunctions, 0);
78
+ if (totalFunctions === 0)
79
+ return 1;
80
+ const ratio = (out.totalUnsafeBlocks + out.totalUnsafeFunctions) / Math.max(1, totalFunctions);
81
+ return Math.max(0, 1 - ratio * 2);
82
+ },
83
+ diagnose: (out) => [
84
+ ...out.safeOnlyViolations.map((module) => ({
85
+ severity: "block",
86
+ message: `Unsafe usage in safe-only module ${module.module}`,
87
+ location: { file: module.file },
88
+ data: {
89
+ module: module.module,
90
+ unsafeBlockCount: module.unsafeBlockCount,
91
+ unsafeFunctionCount: module.unsafeFunctionCount,
92
+ },
93
+ })),
94
+ ...out.modules
95
+ .filter((module) => module.unsafeBlockCount + module.unsafeFunctionCount > 0)
96
+ .slice(0, 10)
97
+ .map((module) => ({
98
+ severity: "warn",
99
+ message: `Unsafe density in ${module.module}: ${(module.unsafeDensity * 100).toFixed(0)}% (${module.propagatingFunctionCount} propagating)`,
100
+ location: { file: module.file },
101
+ data: {
102
+ module: module.module,
103
+ unsafeDensity: module.unsafeDensity,
104
+ unsafeBlockCount: module.unsafeBlockCount,
105
+ unsafeFunctionCount: module.unsafeFunctionCount,
106
+ propagatingFunctionCount: module.propagatingFunctionCount,
107
+ propagationMode: out.propagationMode,
108
+ },
109
+ })),
110
+ ],
111
+ };
112
+ const isPropagatingUnsafe = (fn) => (fn.isUnsafeFn || fn.unsafeBlockCount > 0) &&
113
+ (fn.rawPointerParamCount > 0 ||
114
+ fn.rawPointerReturn ||
115
+ (fn.returnTypeText?.includes("&") ?? false));
116
+ //# sourceMappingURL=rs-ld-01-unsafe.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-01-unsafe.js","sourceRoot":"","sources":["../../src/signals/rs-ld-01-unsafe.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,30 @@
1
+ import { type DistributionalSummary, type Signal } from "@skastr0/pulsar-core/signal";
2
+ import { Schema } from "effect";
3
+ import { RustProjectTag } from "../project.js";
4
+ declare const RsLd02Config: Schema.Struct<{
5
+ exclude_globs: Schema.Array$<typeof Schema.String>;
6
+ max_lifetime_complexity: typeof Schema.Number;
7
+ top_n_diagnostics: typeof Schema.Number;
8
+ }>;
9
+ type RsLd02Config = typeof RsLd02Config.Type;
10
+ interface LifetimeComplexityFact {
11
+ readonly file: string;
12
+ readonly module: string;
13
+ readonly name: string;
14
+ readonly line: number;
15
+ readonly lifetimeParams: number;
16
+ readonly lifetimeBounds: number;
17
+ readonly inputPositions: number;
18
+ readonly outputPositions: number;
19
+ readonly constraintPositions: number;
20
+ readonly complexity: number;
21
+ }
22
+ interface RsLd02Output {
23
+ readonly functions: ReadonlyArray<LifetimeComplexityFact>;
24
+ readonly byFile: ReadonlyMap<string, DistributionalSummary>;
25
+ readonly overThresholdCount: number;
26
+ readonly totalFunctions: number;
27
+ }
28
+ export declare const RsLd02: Signal<RsLd02Config, RsLd02Output, RustProjectTag>;
29
+ export {};
30
+ //# sourceMappingURL=rs-ld-02-lifetimes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-02-lifetimes.d.ts","sourceRoot":"","sources":["../../src/signals/rs-ld-02-lifetimes.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,qBAAqB,EAC1B,KAAK,MAAM,EAGZ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAI9C,QAAA,MAAM,YAAY;;;;EAIhB,CAAA;AACF,KAAK,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAE5C,UAAU,sBAAsB;IAC9B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAA;IAChC,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;CAC5B;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,SAAS,EAAE,aAAa,CAAC,sBAAsB,CAAC,CAAA;IACzD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAA;IAC3D,QAAQ,CAAC,kBAAkB,EAAE,MAAM,CAAA;IACnC,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;CAChC;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CA0ErE,CAAA"}
@@ -0,0 +1,79 @@
1
+ import { SignalComputeError, summarize, } from "@skastr0/pulsar-core/signal";
2
+ import { Effect, Schema } from "effect";
3
+ import { collectRustProjectFacts } from "../rust-analysis.js";
4
+ import { RustProjectTag } from "../project.js";
5
+ import { isExcluded } from "./shared-globs.js";
6
+ import { scoreDoubleWeightedThresholdRatio } from "./shared-threshold-score.js";
7
+ const RsLd02Config = Schema.Struct({
8
+ exclude_globs: Schema.Array(Schema.String),
9
+ max_lifetime_complexity: Schema.Number,
10
+ top_n_diagnostics: Schema.Number,
11
+ });
12
+ export const RsLd02 = {
13
+ id: "RS-LD-02-lifetime-complexity",
14
+ title: "Lifetime complexity",
15
+ aliases: ["RS-LD-02"],
16
+ tier: 1,
17
+ category: "legibility-decay",
18
+ kind: "legibility",
19
+ configSchema: RsLd02Config,
20
+ defaultConfig: {
21
+ exclude_globs: ["**/target/**", "**/tests/**", "**/examples/**", "**/benches/**"],
22
+ max_lifetime_complexity: 4,
23
+ top_n_diagnostics: 10,
24
+ },
25
+ inputs: [],
26
+ compute: (config) => Effect.gen(function* () {
27
+ const project = yield* RustProjectTag;
28
+ return yield* Effect.tryPromise({
29
+ try: async () => {
30
+ const facts = await collectRustProjectFacts(project);
31
+ const functions = facts.functions
32
+ .filter((fn) => !isExcluded(fn.file, config.exclude_globs))
33
+ .map((fn) => ({
34
+ file: fn.file,
35
+ module: fn.modulePath,
36
+ name: fn.name,
37
+ line: fn.line,
38
+ lifetimeParams: fn.lifetimeParamCount,
39
+ lifetimeBounds: fn.lifetimeBoundCount,
40
+ inputPositions: fn.lifetimeInputCount,
41
+ outputPositions: fn.lifetimeOutputCount,
42
+ constraintPositions: fn.lifetimeConstraintCount,
43
+ complexity: fn.lifetimeParamCount +
44
+ fn.lifetimeBoundCount +
45
+ fn.lifetimeInputCount +
46
+ fn.lifetimeOutputCount +
47
+ fn.lifetimeConstraintCount,
48
+ }))
49
+ .filter((fn) => fn.complexity > 0)
50
+ .sort((a, b) => b.complexity - a.complexity || a.file.localeCompare(b.file));
51
+ const byFileValues = new Map();
52
+ for (const fn of functions) {
53
+ const bucket = byFileValues.get(fn.file) ?? [];
54
+ bucket.push(fn.complexity);
55
+ byFileValues.set(fn.file, bucket);
56
+ }
57
+ const byFile = new Map();
58
+ for (const [file, values] of byFileValues) {
59
+ byFile.set(file, summarize(values));
60
+ }
61
+ return {
62
+ functions,
63
+ byFile,
64
+ overThresholdCount: functions.filter((fn) => fn.complexity > config.max_lifetime_complexity).length,
65
+ totalFunctions: functions.length,
66
+ };
67
+ },
68
+ catch: (cause) => new SignalComputeError({ signalId: "RS-LD-02-lifetime-complexity", message: String(cause), cause }),
69
+ });
70
+ }),
71
+ score: (out) => scoreDoubleWeightedThresholdRatio(out.overThresholdCount, out.totalFunctions),
72
+ diagnose: (out) => out.functions.slice(0, 10).map((fn) => ({
73
+ severity: fn.complexity >= 5 ? "warn" : "info",
74
+ message: `Lifetime complexity in ${fn.name}: ${fn.complexity} (params:${fn.lifetimeParams}, bounds:${fn.lifetimeBounds}, in:${fn.inputPositions}, out:${fn.outputPositions})`,
75
+ location: { file: fn.file, line: fn.line },
76
+ data: { ...fn },
77
+ })),
78
+ };
79
+ //# sourceMappingURL=rs-ld-02-lifetimes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-02-lifetimes.js","sourceRoot":"","sources":["../../src/signals/rs-ld-02-lifetimes.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,kBAAkB,EAClB,SAAS,GACV,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,QAAQ,CAAA;AACvC,OAAO,EAAE,uBAAuB,EAAE,MAAM,qBAAqB,CAAA;AAC7D,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAC9C,OAAO,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAA;AAC9C,OAAO,EAAE,iCAAiC,EAAE,MAAM,6BAA6B,CAAA;AAE/E,MAAM,YAAY,GAAG,MAAM,CAAC,MAAM,CAAC;IACjC,aAAa,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC;IAC1C,uBAAuB,EAAE,MAAM,CAAC,MAAM;IACtC,iBAAiB,EAAE,MAAM,CAAC,MAAM;CACjC,CAAC,CAAA;AAuBF,MAAM,CAAC,MAAM,MAAM,GAAuD;IACxE,EAAE,EAAE,8BAA8B;IAClC,KAAK,EAAE,qBAAqB;IAC5B,OAAO,EAAE,CAAC,UAAU,CAAC;IACrB,IAAI,EAAE,CAAC;IACP,QAAQ,EAAE,kBAAkB;IAC5B,IAAI,EAAE,YAAY;IAClB,YAAY,EAAE,YAAY;IAC1B,aAAa,EAAE;QACb,aAAa,EAAE,CAAC,cAAc,EAAE,aAAa,EAAE,gBAAgB,EAAE,eAAe,CAAC;QACjF,uBAAuB,EAAE,CAAC;QAC1B,iBAAiB,EAAE,EAAE;KACtB;IACD,MAAM,EAAE,EAAE;IACV,OAAO,EAAE,CAAC,MAAM,EAAE,EAAE,CAClB,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAClB,MAAM,OAAO,GAAG,KAAK,CAAC,CAAC,cAAc,CAAA;QACrC,OAAO,KAAK,CAAC,CAAC,MAAM,CAAC,UAAU,CAAC;YAC9B,GAAG,EAAE,KAAK,IAA2B,EAAE;gBACrC,MAAM,KAAK,GAAG,MAAM,uBAAuB,CAAC,OAAO,CAAC,CAAA;gBACpD,MAAM,SAAS,GAAG,KAAK,CAAC,SAAS;qBAC9B,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC,UAAU,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,aAAa,CAAC,CAAC;qBAC1D,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;oBACZ,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,MAAM,EAAE,EAAE,CAAC,UAAU;oBACrB,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,IAAI,EAAE,EAAE,CAAC,IAAI;oBACb,cAAc,EAAE,EAAE,CAAC,kBAAkB;oBACrC,cAAc,EAAE,EAAE,CAAC,kBAAkB;oBACrC,cAAc,EAAE,EAAE,CAAC,kBAAkB;oBACrC,eAAe,EAAE,EAAE,CAAC,mBAAmB;oBACvC,mBAAmB,EAAE,EAAE,CAAC,uBAAuB;oBAC/C,UAAU,EACR,EAAE,CAAC,kBAAkB;wBACrB,EAAE,CAAC,kBAAkB;wBACrB,EAAE,CAAC,kBAAkB;wBACrB,EAAE,CAAC,mBAAmB;wBACtB,EAAE,CAAC,uBAAuB;iBAC7B,CAAC,CAAC;qBACF,MAAM,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,CAAC,CAAC;qBACjC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,UAAU,GAAG,CAAC,CAAC,UAAU,IAAI,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAA;gBAE9E,MAAM,YAAY,GAAG,IAAI,GAAG,EAAyB,CAAA;gBACrD,KAAK,MAAM,EAAE,IAAI,SAAS,EAAE,CAAC;oBAC3B,MAAM,MAAM,GAAG,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,EAAE,CAAA;oBAC9C,MAAM,CAAC,IAAI,CAAC,EAAE,CAAC,UAAU,CAAC,CAAA;oBAC1B,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,CAAC,CAAA;gBACnC,CAAC;gBACD,MAAM,MAAM,GAAG,IAAI,GAAG,EAAiC,CAAA;gBACvD,KAAK,MAAM,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,YAAY,EAAE,CAAC;oBAC1C,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,SAAS,CAAC,MAAM,CAAC,CAAC,CAAA;gBACrC,CAAC;gBAED,OAAO;oBACL,SAAS;oBACT,MAAM;oBACN,kBAAkB,EAAE,SAAS,CAAC,MAAM,CAClC,CAAC,EAAE,EAAE,EAAE,CAAC,EAAE,CAAC,UAAU,GAAG,MAAM,CAAC,uBAAuB,CACvD,CAAC,MAAM;oBACR,cAAc,EAAE,SAAS,CAAC,MAAM;iBACjC,CAAA;YACH,CAAC;YACD,KAAK,EAAE,CAAC,KAAK,EAAE,EAAE,CACf,IAAI,kBAAkB,CAAC,EAAE,QAAQ,EAAE,8BAA8B,EAAE,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,EAAE,KAAK,EAAE,CAAC;SACtG,CAAC,CAAA;IACJ,CAAC,CAAC;IACJ,KAAK,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,iCAAiC,CAAC,GAAG,CAAC,kBAAkB,EAAE,GAAG,CAAC,cAAc,CAAC;IAC7F,QAAQ,EAAE,CAAC,GAAG,EAA6B,EAAE,CAC3C,GAAG,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,GAAG,CAAC,CAAC,EAAE,EAAE,EAAE,CAAC,CAAC;QACtC,QAAQ,EAAE,EAAE,CAAC,UAAU,IAAI,CAAC,CAAC,CAAC,CAAE,MAAgB,CAAC,CAAC,CAAE,MAAgB;QACpE,OAAO,EAAE,0BAA0B,EAAE,CAAC,IAAI,KAAK,EAAE,CAAC,UAAU,YAAY,EAAE,CAAC,cAAc,YAAY,EAAE,CAAC,cAAc,QAAQ,EAAE,CAAC,cAAc,SAAS,EAAE,CAAC,eAAe,GAAG;QAC7K,QAAQ,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,CAAC,IAAI,EAAE;QAC1C,IAAI,EAAE,EAAE,GAAG,EAAE,EAAE;KAChB,CAAC,CAAC;CACN,CAAA"}
@@ -0,0 +1,26 @@
1
+ import { type Signal } from "@skastr0/pulsar-core/signal";
2
+ import { Schema } from "effect";
3
+ import { RustProjectTag } from "../project.js";
4
+ declare const RsLd03Config: Schema.Struct<{
5
+ exclude_globs: Schema.Array$<typeof Schema.String>;
6
+ core_logic_globs: Schema.Array$<typeof Schema.String>;
7
+ top_n_diagnostics: typeof Schema.Number;
8
+ }>;
9
+ type RsLd03Config = typeof RsLd03Config.Type;
10
+ interface MatchCatchAllSite {
11
+ readonly file: string;
12
+ readonly module: string;
13
+ readonly functionName: string;
14
+ readonly line: number;
15
+ readonly armCount: number;
16
+ readonly catchAllArmCount: number;
17
+ }
18
+ interface RsLd03Output {
19
+ readonly matchSites: ReadonlyArray<MatchCatchAllSite>;
20
+ readonly totalMatches: number;
21
+ readonly matchesWithCatchAll: number;
22
+ readonly totalCatchAllArms: number;
23
+ }
24
+ export declare const RsLd03: Signal<RsLd03Config, RsLd03Output, RustProjectTag>;
25
+ export {};
26
+ //# sourceMappingURL=rs-ld-03-match-catch-all.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-03-match-catch-all.d.ts","sourceRoot":"","sources":["../../src/signals/rs-ld-03-match-catch-all.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAEZ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C,QAAA,MAAM,YAAY;;;;EAIhB,CAAA;AACF,KAAK,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAE5C,UAAU,iBAAiB;IACzB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAA;CAClC;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,UAAU,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;IACrD,QAAQ,CAAC,YAAY,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,mBAAmB,EAAE,MAAM,CAAA;IACpC,QAAQ,CAAC,iBAAiB,EAAE,MAAM,CAAA;CACnC;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CA8DrE,CAAA"}
@@ -0,0 +1,68 @@
1
+ import { SignalComputeError, } from "@skastr0/pulsar-core/signal";
2
+ import { Effect, Schema } from "effect";
3
+ import { collectRustProjectFacts } from "../rust-analysis.js";
4
+ import { RustProjectTag } from "../project.js";
5
+ import { isExcluded, matchesAnyGlob } from "./shared-globs.js";
6
+ const RsLd03Config = Schema.Struct({
7
+ exclude_globs: Schema.Array(Schema.String),
8
+ core_logic_globs: Schema.Array(Schema.String),
9
+ top_n_diagnostics: Schema.Number,
10
+ });
11
+ export const RsLd03 = {
12
+ id: "RS-LD-03-match-catch-all",
13
+ title: "Match catch-all usage",
14
+ aliases: ["RS-LD-03"],
15
+ tier: 1,
16
+ category: "legibility-decay",
17
+ kind: "legibility",
18
+ configSchema: RsLd03Config,
19
+ defaultConfig: {
20
+ exclude_globs: ["**/target/**", "**/tests/**", "**/examples/**", "**/benches/**"],
21
+ core_logic_globs: [],
22
+ top_n_diagnostics: 10,
23
+ },
24
+ inputs: [],
25
+ compute: (config) => Effect.gen(function* () {
26
+ const project = yield* RustProjectTag;
27
+ return yield* Effect.tryPromise({
28
+ try: async () => {
29
+ const facts = await collectRustProjectFacts(project);
30
+ const matchSites = facts.matches
31
+ .filter((site) => !isExcluded(site.file, config.exclude_globs))
32
+ .filter((site) => config.core_logic_globs.length === 0 ||
33
+ matchesAnyGlob(site.file, config.core_logic_globs))
34
+ .map((site) => ({
35
+ file: site.file,
36
+ module: site.modulePath,
37
+ functionName: site.functionName,
38
+ line: site.line,
39
+ armCount: site.armCount,
40
+ catchAllArmCount: site.catchAllArmCount,
41
+ }))
42
+ .sort((a, b) => b.catchAllArmCount - a.catchAllArmCount || a.file.localeCompare(b.file));
43
+ return {
44
+ matchSites,
45
+ totalMatches: matchSites.length,
46
+ matchesWithCatchAll: matchSites.filter((site) => site.catchAllArmCount > 0).length,
47
+ totalCatchAllArms: matchSites.reduce((sum, site) => sum + site.catchAllArmCount, 0),
48
+ };
49
+ },
50
+ catch: (cause) => new SignalComputeError({ signalId: "RS-LD-03-match-catch-all", message: String(cause), cause }),
51
+ });
52
+ }),
53
+ score: (out) => {
54
+ if (out.totalMatches === 0)
55
+ return 1;
56
+ return Math.max(0, 1 - (out.matchesWithCatchAll / out.totalMatches) * 2);
57
+ },
58
+ diagnose: (out) => out.matchSites
59
+ .filter((site) => site.catchAllArmCount > 0)
60
+ .slice(0, 10)
61
+ .map((site) => ({
62
+ severity: "warn",
63
+ message: `Match in ${site.functionName} uses ${site.catchAllArmCount} catch-all arm(s)`,
64
+ location: { file: site.file, line: site.line },
65
+ data: { ...site },
66
+ })),
67
+ };
68
+ //# sourceMappingURL=rs-ld-03-match-catch-all.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-03-match-catch-all.js","sourceRoot":"","sources":["../../src/signals/rs-ld-03-match-catch-all.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import { type Signal } from "@skastr0/pulsar-core/signal";
2
+ import { Schema } from "effect";
3
+ import { RustProjectTag } from "../project.js";
4
+ declare const RsLd04Config: Schema.Struct<{
5
+ exclude_globs: Schema.Array$<typeof Schema.String>;
6
+ top_n_diagnostics: typeof Schema.Number;
7
+ }>;
8
+ type RsLd04Config = typeof RsLd04Config.Type;
9
+ interface BoundaryErrorSurface {
10
+ readonly file: string;
11
+ readonly module: string;
12
+ readonly name: string;
13
+ readonly line: number;
14
+ readonly errorType: string;
15
+ readonly classification: "granular" | "collapsed";
16
+ }
17
+ interface RsLd04Output {
18
+ readonly boundaryFunctions: ReadonlyArray<BoundaryErrorSurface>;
19
+ readonly granularCount: number;
20
+ readonly collapsedCount: number;
21
+ readonly totalBoundaryResults: number;
22
+ }
23
+ export declare const RsLd04: Signal<RsLd04Config, RsLd04Output, RustProjectTag>;
24
+ export {};
25
+ //# sourceMappingURL=rs-ld-04-error-granularity.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rs-ld-04-error-granularity.d.ts","sourceRoot":"","sources":["../../src/signals/rs-ld-04-error-granularity.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,KAAK,MAAM,EAEZ,MAAM,6BAA6B,CAAA;AACpC,OAAO,EAAU,MAAM,EAAE,MAAM,QAAQ,CAAA;AAEvC,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAA;AAG9C,QAAA,MAAM,YAAY;;;EAGhB,CAAA;AACF,KAAK,YAAY,GAAG,OAAO,YAAY,CAAC,IAAI,CAAA;AAE5C,UAAU,oBAAoB;IAC5B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAA;IACvB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,SAAS,EAAE,MAAM,CAAA;IAC1B,QAAQ,CAAC,cAAc,EAAE,UAAU,GAAG,WAAW,CAAA;CAClD;AAED,UAAU,YAAY;IACpB,QAAQ,CAAC,iBAAiB,EAAE,aAAa,CAAC,oBAAoB,CAAC,CAAA;IAC/D,QAAQ,CAAC,aAAa,EAAE,MAAM,CAAA;IAC9B,QAAQ,CAAC,cAAc,EAAE,MAAM,CAAA;IAC/B,QAAQ,CAAC,oBAAoB,EAAE,MAAM,CAAA;CACtC;AAED,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,YAAY,EAAE,YAAY,EAAE,cAAc,CA0DrE,CAAA"}