@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.
- package/dist/cargo-metadata.d.ts +59 -0
- package/dist/cargo-metadata.d.ts.map +1 -0
- package/dist/cargo-metadata.js +162 -0
- package/dist/cargo-metadata.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +7 -0
- package/dist/index.js.map +1 -0
- package/dist/lock-file.d.ts +20 -0
- package/dist/lock-file.d.ts.map +1 -0
- package/dist/lock-file.js +144 -0
- package/dist/lock-file.js.map +1 -0
- package/dist/pack.d.ts +6 -0
- package/dist/pack.d.ts.map +1 -0
- package/dist/pack.js +55 -0
- package/dist/pack.js.map +1 -0
- package/dist/project.d.ts +26 -0
- package/dist/project.d.ts.map +1 -0
- package/dist/project.js +172 -0
- package/dist/project.js.map +1 -0
- package/dist/rust-analysis-collect.d.ts +4 -0
- package/dist/rust-analysis-collect.d.ts.map +1 -0
- package/dist/rust-analysis-collect.js +84 -0
- package/dist/rust-analysis-collect.js.map +1 -0
- package/dist/rust-analysis-functions.d.ts +4 -0
- package/dist/rust-analysis-functions.d.ts.map +1 -0
- package/dist/rust-analysis-functions.js +140 -0
- package/dist/rust-analysis-functions.js.map +1 -0
- package/dist/rust-analysis-identifiers.d.ts +3 -0
- package/dist/rust-analysis-identifiers.d.ts.map +1 -0
- package/dist/rust-analysis-identifiers.js +5 -0
- package/dist/rust-analysis-identifiers.js.map +1 -0
- package/dist/rust-analysis-items.d.ts +4 -0
- package/dist/rust-analysis-items.d.ts.map +1 -0
- package/dist/rust-analysis-items.js +58 -0
- package/dist/rust-analysis-items.js.map +1 -0
- package/dist/rust-analysis-modules.d.ts +7 -0
- package/dist/rust-analysis-modules.d.ts.map +1 -0
- package/dist/rust-analysis-modules.js +52 -0
- package/dist/rust-analysis-modules.js.map +1 -0
- package/dist/rust-analysis-syntax.d.ts +12 -0
- package/dist/rust-analysis-syntax.d.ts.map +1 -0
- package/dist/rust-analysis-syntax.js +102 -0
- package/dist/rust-analysis-syntax.js.map +1 -0
- package/dist/rust-analysis-types.d.ts +109 -0
- package/dist/rust-analysis-types.d.ts.map +1 -0
- package/dist/rust-analysis-types.js +2 -0
- package/dist/rust-analysis-types.js.map +1 -0
- package/dist/rust-analysis-uses.d.ts +4 -0
- package/dist/rust-analysis-uses.d.ts.map +1 -0
- package/dist/rust-analysis-uses.js +63 -0
- package/dist/rust-analysis-uses.js.map +1 -0
- package/dist/rust-analysis.d.ts +5 -0
- package/dist/rust-analysis.d.ts.map +1 -0
- package/dist/rust-analysis.js +4 -0
- package/dist/rust-analysis.js.map +1 -0
- package/dist/signals/rs-ab-01-unused-pub.d.ts +29 -0
- package/dist/signals/rs-ab-01-unused-pub.d.ts.map +1 -0
- package/dist/signals/rs-ab-01-unused-pub.js +184 -0
- package/dist/signals/rs-ab-01-unused-pub.js.map +1 -0
- package/dist/signals/rs-ab-02-trait-object-depth.d.ts +26 -0
- package/dist/signals/rs-ab-02-trait-object-depth.d.ts.map +1 -0
- package/dist/signals/rs-ab-02-trait-object-depth.js +157 -0
- package/dist/signals/rs-ab-02-trait-object-depth.js.map +1 -0
- package/dist/signals/rs-ab-03-generic-proliferation.d.ts +28 -0
- package/dist/signals/rs-ab-03-generic-proliferation.d.ts.map +1 -0
- package/dist/signals/rs-ab-03-generic-proliferation.js +108 -0
- package/dist/signals/rs-ab-03-generic-proliferation.js.map +1 -0
- package/dist/signals/rs-ab-04-derive-density.d.ts +25 -0
- package/dist/signals/rs-ab-04-derive-density.d.ts.map +1 -0
- package/dist/signals/rs-ab-04-derive-density.js +101 -0
- package/dist/signals/rs-ab-04-derive-density.js.map +1 -0
- package/dist/signals/rs-ad-01-visibility-surface.d.ts +29 -0
- package/dist/signals/rs-ad-01-visibility-surface.d.ts.map +1 -0
- package/dist/signals/rs-ad-01-visibility-surface.js +129 -0
- package/dist/signals/rs-ad-01-visibility-surface.js.map +1 -0
- package/dist/signals/rs-ad-02-boundary-rules.d.ts +3 -0
- package/dist/signals/rs-ad-02-boundary-rules.d.ts.map +1 -0
- package/dist/signals/rs-ad-02-boundary-rules.js +26 -0
- package/dist/signals/rs-ad-02-boundary-rules.js.map +1 -0
- package/dist/signals/rs-ad-02-crate-analysis.d.ts +9 -0
- package/dist/signals/rs-ad-02-crate-analysis.d.ts.map +1 -0
- package/dist/signals/rs-ad-02-crate-analysis.js +117 -0
- package/dist/signals/rs-ad-02-crate-analysis.js.map +1 -0
- package/dist/signals/rs-ad-02-crate-boundaries.d.ts +6 -0
- package/dist/signals/rs-ad-02-crate-boundaries.d.ts.map +1 -0
- package/dist/signals/rs-ad-02-crate-boundaries.js +84 -0
- package/dist/signals/rs-ad-02-crate-boundaries.js.map +1 -0
- package/dist/signals/rs-ad-02-types.d.ts +26 -0
- package/dist/signals/rs-ad-02-types.d.ts.map +1 -0
- package/dist/signals/rs-ad-02-types.js +6 -0
- package/dist/signals/rs-ad-02-types.js.map +1 -0
- package/dist/signals/rs-ad-03-circular-crate-deps.d.ts +30 -0
- package/dist/signals/rs-ad-03-circular-crate-deps.d.ts.map +1 -0
- package/dist/signals/rs-ad-03-circular-crate-deps.js +185 -0
- package/dist/signals/rs-ad-03-circular-crate-deps.js.map +1 -0
- package/dist/signals/rs-de-01-trait-coupling.d.ts +43 -0
- package/dist/signals/rs-de-01-trait-coupling.d.ts.map +1 -0
- package/dist/signals/rs-de-01-trait-coupling.js +222 -0
- package/dist/signals/rs-de-01-trait-coupling.js.map +1 -0
- package/dist/signals/rs-de-02-dep-tree.d.ts +28 -0
- package/dist/signals/rs-de-02-dep-tree.d.ts.map +1 -0
- package/dist/signals/rs-de-02-dep-tree.js +173 -0
- package/dist/signals/rs-de-02-dep-tree.js.map +1 -0
- package/dist/signals/rs-de-03-feature-flags.d.ts +32 -0
- package/dist/signals/rs-de-03-feature-flags.d.ts.map +1 -0
- package/dist/signals/rs-de-03-feature-flags.js +139 -0
- package/dist/signals/rs-de-03-feature-flags.js.map +1 -0
- package/dist/signals/rs-de-04-fan-in-fan-out.d.ts +28 -0
- package/dist/signals/rs-de-04-fan-in-fan-out.d.ts.map +1 -0
- package/dist/signals/rs-de-04-fan-in-fan-out.js +109 -0
- package/dist/signals/rs-de-04-fan-in-fan-out.js.map +1 -0
- package/dist/signals/rs-ld-01-unsafe.d.ts +28 -0
- package/dist/signals/rs-ld-01-unsafe.d.ts.map +1 -0
- package/dist/signals/rs-ld-01-unsafe.js +116 -0
- package/dist/signals/rs-ld-01-unsafe.js.map +1 -0
- package/dist/signals/rs-ld-02-lifetimes.d.ts +30 -0
- package/dist/signals/rs-ld-02-lifetimes.d.ts.map +1 -0
- package/dist/signals/rs-ld-02-lifetimes.js +79 -0
- package/dist/signals/rs-ld-02-lifetimes.js.map +1 -0
- package/dist/signals/rs-ld-03-match-catch-all.d.ts +26 -0
- package/dist/signals/rs-ld-03-match-catch-all.d.ts.map +1 -0
- package/dist/signals/rs-ld-03-match-catch-all.js +68 -0
- package/dist/signals/rs-ld-03-match-catch-all.js.map +1 -0
- package/dist/signals/rs-ld-04-error-granularity.d.ts +25 -0
- package/dist/signals/rs-ld-04-error-granularity.d.ts.map +1 -0
- package/dist/signals/rs-ld-04-error-granularity.js +77 -0
- package/dist/signals/rs-ld-04-error-granularity.js.map +1 -0
- package/dist/signals/rs-ld-05-complexity.d.ts +26 -0
- package/dist/signals/rs-ld-05-complexity.d.ts.map +1 -0
- package/dist/signals/rs-ld-05-complexity.js +70 -0
- package/dist/signals/rs-ld-05-complexity.js.map +1 -0
- package/dist/signals/rs-ld-06-domain-terms.d.ts +29 -0
- package/dist/signals/rs-ld-06-domain-terms.d.ts.map +1 -0
- package/dist/signals/rs-ld-06-domain-terms.js +158 -0
- package/dist/signals/rs-ld-06-domain-terms.js.map +1 -0
- package/dist/signals/rs-rp-01-hotspots.d.ts +27 -0
- package/dist/signals/rs-rp-01-hotspots.d.ts.map +1 -0
- package/dist/signals/rs-rp-01-hotspots.js +110 -0
- package/dist/signals/rs-rp-01-hotspots.js.map +1 -0
- package/dist/signals/rs-rp-02-compile-time.d.ts +25 -0
- package/dist/signals/rs-rp-02-compile-time.d.ts.map +1 -0
- package/dist/signals/rs-rp-02-compile-time.js +177 -0
- package/dist/signals/rs-rp-02-compile-time.js.map +1 -0
- package/dist/signals/rs-rp-03-pr-size.d.ts +23 -0
- package/dist/signals/rs-rp-03-pr-size.d.ts.map +1 -0
- package/dist/signals/rs-rp-03-pr-size.js +160 -0
- package/dist/signals/rs-rp-03-pr-size.js.map +1 -0
- package/dist/signals/rs-sl-01-duplication.d.ts +28 -0
- package/dist/signals/rs-sl-01-duplication.d.ts.map +1 -0
- package/dist/signals/rs-sl-01-duplication.js +172 -0
- package/dist/signals/rs-sl-01-duplication.js.map +1 -0
- package/dist/signals/rs-sl-02-suppressions.d.ts +30 -0
- package/dist/signals/rs-sl-02-suppressions.d.ts.map +1 -0
- package/dist/signals/rs-sl-02-suppressions.js +176 -0
- package/dist/signals/rs-sl-02-suppressions.js.map +1 -0
- package/dist/signals/rs-sl-03-unwrap-expect.d.ts +22 -0
- package/dist/signals/rs-sl-03-unwrap-expect.d.ts.map +1 -0
- package/dist/signals/rs-sl-03-unwrap-expect.js +94 -0
- package/dist/signals/rs-sl-03-unwrap-expect.js.map +1 -0
- package/dist/signals/rs-sl-04-clone-abuse.d.ts +22 -0
- package/dist/signals/rs-sl-04-clone-abuse.d.ts.map +1 -0
- package/dist/signals/rs-sl-04-clone-abuse.js +115 -0
- package/dist/signals/rs-sl-04-clone-abuse.js.map +1 -0
- package/dist/signals/shared-globs.d.ts +4 -0
- package/dist/signals/shared-globs.d.ts.map +1 -0
- package/dist/signals/shared-globs.js +12 -0
- package/dist/signals/shared-globs.js.map +1 -0
- package/dist/signals/shared-record-guards.d.ts +4 -0
- package/dist/signals/shared-record-guards.d.ts.map +1 -0
- package/dist/signals/shared-record-guards.js +4 -0
- package/dist/signals/shared-record-guards.js.map +1 -0
- package/dist/signals/shared-rust-ast.d.ts +30 -0
- package/dist/signals/shared-rust-ast.d.ts.map +1 -0
- package/dist/signals/shared-rust-ast.js +78 -0
- package/dist/signals/shared-rust-ast.js.map +1 -0
- package/dist/signals/shared-rust-resolution.d.ts +10 -0
- package/dist/signals/shared-rust-resolution.d.ts.map +1 -0
- package/dist/signals/shared-rust-resolution.js +53 -0
- package/dist/signals/shared-rust-resolution.js.map +1 -0
- package/dist/signals/shared-threshold-score.d.ts +2 -0
- package/dist/signals/shared-threshold-score.d.ts.map +1 -0
- package/dist/signals/shared-threshold-score.js +6 -0
- package/dist/signals/shared-threshold-score.js.map +1 -0
- package/dist/syn-walker.d.ts +7 -0
- package/dist/syn-walker.d.ts.map +1 -0
- package/dist/syn-walker.js +61 -0
- package/dist/syn-walker.js.map +1 -0
- 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":"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"}
|
|
@@ -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"}
|