@opensip-cli/yagni 0.1.11 → 0.1.12
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/README.md +2 -2
- package/dist/__tests__/architecture-invariants.test.d.ts +6 -0
- package/dist/__tests__/architecture-invariants.test.d.ts.map +1 -0
- package/dist/__tests__/architecture-invariants.test.js +37 -0
- package/dist/__tests__/architecture-invariants.test.js.map +1 -0
- package/dist/__tests__/detector-progress.test.d.ts +2 -0
- package/dist/__tests__/detector-progress.test.d.ts.map +1 -0
- package/dist/__tests__/detector-progress.test.js +73 -0
- package/dist/__tests__/detector-progress.test.js.map +1 -0
- package/dist/__tests__/duplicate-parity.test.d.ts +15 -0
- package/dist/__tests__/duplicate-parity.test.d.ts.map +1 -0
- package/dist/__tests__/duplicate-parity.test.js +304 -0
- package/dist/__tests__/duplicate-parity.test.js.map +1 -0
- package/dist/__tests__/hardening.test.d.ts +2 -0
- package/dist/__tests__/hardening.test.d.ts.map +1 -0
- package/dist/__tests__/hardening.test.js +101 -0
- package/dist/__tests__/hardening.test.js.map +1 -0
- package/dist/__tests__/session-payload.test.d.ts +2 -0
- package/dist/__tests__/session-payload.test.d.ts.map +1 -0
- package/dist/__tests__/session-payload.test.js +57 -0
- package/dist/__tests__/session-payload.test.js.map +1 -0
- package/dist/__tests__/walk-typescript-files.test.js +15 -1
- package/dist/__tests__/walk-typescript-files.test.js.map +1 -1
- package/dist/__tests__/yagni-coverage.test.js +24 -199
- package/dist/__tests__/yagni-coverage.test.js.map +1 -1
- package/dist/__tests__/yagni-golden.test.js +7 -24
- package/dist/__tests__/yagni-golden.test.js.map +1 -1
- package/dist/__tests__/yagni-presentation.test.js +4 -5
- package/dist/__tests__/yagni-presentation.test.js.map +1 -1
- package/dist/cli/__tests__/yagni-runner.test.js +4 -6
- package/dist/cli/__tests__/yagni-runner.test.js.map +1 -1
- package/dist/cli/execute-yagni.d.ts +15 -4
- package/dist/cli/execute-yagni.d.ts.map +1 -1
- package/dist/cli/execute-yagni.js +68 -30
- package/dist/cli/execute-yagni.js.map +1 -1
- package/dist/cli/report-data.d.ts +0 -2
- package/dist/cli/report-data.d.ts.map +1 -1
- package/dist/cli/report-data.js +0 -2
- package/dist/cli/report-data.js.map +1 -1
- package/dist/cli/yagni-command-spec.d.ts.map +1 -1
- package/dist/cli/yagni-command-spec.js +4 -19
- package/dist/cli/yagni-command-spec.js.map +1 -1
- package/dist/cli/yagni-config-schema.d.ts +1 -7
- package/dist/cli/yagni-config-schema.d.ts.map +1 -1
- package/dist/cli/yagni-config-schema.js +4 -6
- package/dist/cli/yagni-config-schema.js.map +1 -1
- package/dist/cli/yagni-config.d.ts.map +1 -1
- package/dist/cli/yagni-config.js +3 -7
- package/dist/cli/yagni-config.js.map +1 -1
- package/dist/cli/yagni-presentation.d.ts +1 -2
- package/dist/cli/yagni-presentation.d.ts.map +1 -1
- package/dist/cli/yagni-presentation.js +4 -4
- package/dist/cli/yagni-presentation.js.map +1 -1
- package/dist/cli/yagni-runner.d.ts +0 -2
- package/dist/cli/yagni-runner.d.ts.map +1 -1
- package/dist/cli/yagni-runner.js +40 -8
- package/dist/cli/yagni-runner.js.map +1 -1
- package/dist/detectors/duplicate-body-candidate.d.ts +9 -2
- package/dist/detectors/duplicate-body-candidate.d.ts.map +1 -1
- package/dist/detectors/duplicate-body-candidate.js +123 -120
- package/dist/detectors/duplicate-body-candidate.js.map +1 -1
- package/dist/detectors/registry.d.ts +9 -1
- package/dist/detectors/registry.d.ts.map +1 -1
- package/dist/detectors/registry.js +9 -1
- package/dist/detectors/registry.js.map +1 -1
- package/dist/detectors/types.d.ts +1 -2
- package/dist/detectors/types.d.ts.map +1 -1
- package/dist/detectors/unused-config-surface.d.ts.map +1 -1
- package/dist/detectors/unused-config-surface.js +0 -2
- package/dist/detectors/unused-config-surface.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/lib/build-ts-inventory.d.ts +33 -0
- package/dist/lib/build-ts-inventory.d.ts.map +1 -0
- package/dist/lib/build-ts-inventory.js +252 -0
- package/dist/lib/build-ts-inventory.js.map +1 -0
- package/dist/persistence/session-payload.d.ts +7 -10
- package/dist/persistence/session-payload.d.ts.map +1 -1
- package/dist/persistence/session-payload.js +64 -6
- package/dist/persistence/session-payload.js.map +1 -1
- package/dist/scoring/__tests__/confidence.test.js +3 -4
- package/dist/scoring/__tests__/confidence.test.js.map +1 -1
- package/dist/scoring/confidence.d.ts +1 -1
- package/dist/scoring/confidence.d.ts.map +1 -1
- package/dist/scoring/confidence.js +1 -2
- package/dist/scoring/confidence.js.map +1 -1
- package/dist/types/yagni-config.d.ts +1 -4
- package/dist/types/yagni-config.d.ts.map +1 -1
- package/dist/types/yagni-config.js +0 -1
- package/dist/types/yagni-config.js.map +1 -1
- package/dist/types/yagni-metadata.d.ts +0 -1
- package/dist/types/yagni-metadata.d.ts.map +1 -1
- package/package.json +10 -10
- package/dist/__tests__/graph-evidence.test.d.ts +0 -2
- package/dist/__tests__/graph-evidence.test.d.ts.map +0 -1
- package/dist/__tests__/graph-evidence.test.js +0 -159
- package/dist/__tests__/graph-evidence.test.js.map +0 -1
- package/dist/evidence/graph-evidence.d.ts +0 -15
- package/dist/evidence/graph-evidence.d.ts.map +0 -1
- package/dist/evidence/graph-evidence.js +0 -89
- package/dist/evidence/graph-evidence.js.map +0 -1
- package/dist/evidence/load-graph-adapters.d.ts +0 -13
- package/dist/evidence/load-graph-adapters.d.ts.map +0 -1
- package/dist/evidence/load-graph-adapters.js +0 -67
- package/dist/evidence/load-graph-adapters.js.map +0 -1
- package/dist/lib/isolate-exit-code.d.ts +0 -8
- package/dist/lib/isolate-exit-code.d.ts.map +0 -1
- package/dist/lib/isolate-exit-code.js +0 -27
- package/dist/lib/isolate-exit-code.js.map +0 -1
package/dist/cli/yagni-config.js
CHANGED
|
@@ -19,18 +19,14 @@
|
|
|
19
19
|
* `dogfood-one-config-document-ratchet` check's sanctioned config readers for
|
|
20
20
|
* exactly this reason.
|
|
21
21
|
*/
|
|
22
|
-
import { currentScope, readYamlFile, resolveProjectConfigPath } from '@opensip-cli/core';
|
|
22
|
+
import { currentScope, isPlainRecord, readYamlFile, resolveProjectConfigPath, } from '@opensip-cli/core';
|
|
23
23
|
import { DEFAULT_YAGNI_CONFIG } from '../types/yagni-config.js';
|
|
24
24
|
import { YagniConfigSchema } from './yagni-config-schema.js';
|
|
25
|
-
function isPlainObject(v) {
|
|
26
|
-
return typeof v === 'object' && v !== null && !Array.isArray(v);
|
|
27
|
-
}
|
|
28
25
|
function mergeDefaults(parsed) {
|
|
29
26
|
return {
|
|
30
27
|
failOnErrors: parsed.failOnErrors ?? DEFAULT_YAGNI_CONFIG.failOnErrors,
|
|
31
28
|
failOnWarnings: parsed.failOnWarnings ?? DEFAULT_YAGNI_CONFIG.failOnWarnings,
|
|
32
29
|
defaultMinConfidence: parsed.defaultMinConfidence ?? DEFAULT_YAGNI_CONFIG.defaultMinConfidence,
|
|
33
|
-
graphMode: parsed.graphMode ?? DEFAULT_YAGNI_CONFIG.graphMode,
|
|
34
30
|
includeTests: parsed.includeTests ?? DEFAULT_YAGNI_CONFIG.includeTests,
|
|
35
31
|
...(parsed.disabledDetectors === undefined
|
|
36
32
|
? {}
|
|
@@ -48,7 +44,7 @@ export function loadYagniConfig(cwd, explicitPath) {
|
|
|
48
44
|
// YAML read below.
|
|
49
45
|
const scope = currentScope();
|
|
50
46
|
const scoped = scope?.toolConfig?.yagni;
|
|
51
|
-
if (
|
|
47
|
+
if (isPlainRecord(scoped)) {
|
|
52
48
|
const parsed = YagniConfigSchema.safeParse(scoped);
|
|
53
49
|
if (parsed.success)
|
|
54
50
|
return mergeDefaults(parsed.data);
|
|
@@ -61,7 +57,7 @@ export function loadYagniConfig(cwd, explicitPath) {
|
|
|
61
57
|
}
|
|
62
58
|
const configPath = resolveProjectConfigPath(cwd, explicitPath);
|
|
63
59
|
const doc = readYamlFile(configPath);
|
|
64
|
-
if (!
|
|
60
|
+
if (!isPlainRecord(doc) || !isPlainRecord(doc.yagni)) {
|
|
65
61
|
return mergeDefaults({});
|
|
66
62
|
}
|
|
67
63
|
const parsed = YagniConfigSchema.safeParse(doc.yagni);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yagni-config.js","sourceRoot":"","sources":["../../src/cli/yagni-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,
|
|
1
|
+
{"version":3,"file":"yagni-config.js","sourceRoot":"","sources":["../../src/cli/yagni-config.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;GAoBG;AAEH,OAAO,EACL,YAAY,EACZ,aAAa,EACb,YAAY,EACZ,wBAAwB,GACzB,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,oBAAoB,EAAE,MAAM,0BAA0B,CAAC;AAEhE,OAAO,EAAE,iBAAiB,EAAE,MAAM,0BAA0B,CAAC;AAI7D,SAAS,aAAa,CAAC,MAAmB;IACxC,OAAO;QACL,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,oBAAoB,CAAC,YAAY;QACtE,cAAc,EAAE,MAAM,CAAC,cAAc,IAAI,oBAAoB,CAAC,cAAc;QAC5E,oBAAoB,EAAE,MAAM,CAAC,oBAAoB,IAAI,oBAAoB,CAAC,oBAAoB;QAC9F,YAAY,EAAE,MAAM,CAAC,YAAY,IAAI,oBAAoB,CAAC,YAAY;QACtE,GAAG,CAAC,MAAM,CAAC,iBAAiB,KAAK,SAAS;YACxC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACpD,GAAG,CAAC,MAAM,CAAC,gBAAgB,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gBAAgB,EAAE,MAAM,CAAC,gBAAgB,EAAE,CAAC;KAChG,CAAC;AACJ,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,GAAW,EAAE,YAAqB;IAChE,uEAAuE;IACvE,+EAA+E;IAC/E,gFAAgF;IAChF,mBAAmB;IACnB,MAAM,KAAK,GAAG,YAAY,EAAE,CAAC;IAC7B,MAAM,MAAM,GAAG,KAAK,EAAE,UAAU,EAAE,KAAK,CAAC;IACxC,IAAI,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QACnD,IAAI,MAAM,CAAC,OAAO;YAAE,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IACxD,CAAC;IACD,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,6EAA6E;QAC7E,6EAA6E;QAC7E,0EAA0E;QAC1E,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IAED,MAAM,UAAU,GAAG,wBAAwB,CAAC,GAAG,EAAE,YAAY,CAAC,CAAC;IAC/D,MAAM,GAAG,GAAG,YAAY,CAAC,UAAU,CAAC,CAAC;IACrC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;QACrD,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;IAC3B,CAAC;IACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;IACtD,IAAI,CAAC,MAAM,CAAC,OAAO;QAAE,OAAO,aAAa,CAAC,EAAE,CAAC,CAAC;IAC9C,OAAO,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC"}
|
|
@@ -3,11 +3,10 @@
|
|
|
3
3
|
*/
|
|
4
4
|
import type { SkippedDetector } from '../detectors/types.js';
|
|
5
5
|
import type { RunPresentation, SignalEnvelope } from '@opensip-cli/contracts';
|
|
6
|
-
export declare function buildYagniPresentationLines(envelope: SignalEnvelope, cwd: string,
|
|
6
|
+
export declare function buildYagniPresentationLines(envelope: SignalEnvelope, cwd: string, skippedDetectors: readonly SkippedDetector[], verbose: boolean): string[];
|
|
7
7
|
export declare function buildYagniRunPresentation(input: {
|
|
8
8
|
readonly envelope: SignalEnvelope;
|
|
9
9
|
readonly cwd: string;
|
|
10
|
-
readonly graphMode: string;
|
|
11
10
|
readonly skippedDetectors: readonly SkippedDetector[];
|
|
12
11
|
readonly verbose: boolean;
|
|
13
12
|
readonly durationMs?: number;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yagni-presentation.d.ts","sourceRoot":"","sources":["../../src/cli/yagni-presentation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAiB,MAAM,wBAAwB,CAAC;AAqD7F,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,MAAM,EACX,
|
|
1
|
+
{"version":3,"file":"yagni-presentation.d.ts","sourceRoot":"","sources":["../../src/cli/yagni-presentation.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AAE7D,OAAO,KAAK,EAAE,eAAe,EAAE,cAAc,EAAiB,MAAM,wBAAwB,CAAC;AAqD7F,wBAAgB,2BAA2B,CACzC,QAAQ,EAAE,cAAc,EACxB,GAAG,EAAE,MAAM,EACX,gBAAgB,EAAE,SAAS,eAAe,EAAE,EAC5C,OAAO,EAAE,OAAO,GACf,MAAM,EAAE,CA8BV;AAED,wBAAgB,yBAAyB,CAAC,KAAK,EAAE;IAC/C,QAAQ,CAAC,QAAQ,EAAE,cAAc,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,gBAAgB,EAAE,SAAS,eAAe,EAAE,CAAC;IACtD,QAAQ,CAAC,OAAO,EAAE,OAAO,CAAC;IAC1B,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B,GAAG,eAAe,CAclB"}
|
|
@@ -53,8 +53,8 @@ function candidateLines(signals, cwd, verbose) {
|
|
|
53
53
|
}
|
|
54
54
|
return lines;
|
|
55
55
|
}
|
|
56
|
-
export function buildYagniPresentationLines(envelope, cwd,
|
|
57
|
-
const summary = buildYagniRunSummary(envelope.signals,
|
|
56
|
+
export function buildYagniPresentationLines(envelope, cwd, skippedDetectors, verbose) {
|
|
57
|
+
const summary = buildYagniRunSummary(envelope.signals, skippedDetectors);
|
|
58
58
|
const visibleSignals = verbose
|
|
59
59
|
? envelope.signals
|
|
60
60
|
: envelope.signals.filter((s) => {
|
|
@@ -65,7 +65,7 @@ export function buildYagniPresentationLines(envelope, cwd, graphMode, skippedDet
|
|
|
65
65
|
const headline = `YAGNI audit: ${String(summary.totalCandidates)} reduction candidates (${String(high)} high, ${String(medium)} medium)`;
|
|
66
66
|
const ran = envelope.units.length;
|
|
67
67
|
const skipped = skippedDetectors.length;
|
|
68
|
-
const metaLine =
|
|
68
|
+
const metaLine = `${String(ran)} detectors ran · ${String(skipped)} skipped`;
|
|
69
69
|
const lines = [headline, metaLine, ...candidateLines(visibleSignals, cwd, verbose)];
|
|
70
70
|
if (summary.estimatedTotalLocReduction > 0) {
|
|
71
71
|
lines.push('', `net: ~${String(summary.estimatedTotalLocReduction)} LOC possible`);
|
|
@@ -80,7 +80,7 @@ export function buildYagniPresentationLines(envelope, cwd, graphMode, skippedDet
|
|
|
80
80
|
return lines;
|
|
81
81
|
}
|
|
82
82
|
export function buildYagniRunPresentation(input) {
|
|
83
|
-
const lines = buildYagniPresentationLines(input.envelope, input.cwd, input.
|
|
83
|
+
const lines = buildYagniPresentationLines(input.envelope, input.cwd, input.skippedDetectors, input.verbose);
|
|
84
84
|
return {
|
|
85
85
|
type: 'run-presentation',
|
|
86
86
|
tool: 'yagni',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yagni-presentation.js","sourceRoot":"","sources":["../../src/cli/yagni-presentation.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"yagni-presentation.js","sourceRoot":"","sources":["../../src/cli/yagni-presentation.ts"],"names":[],"mappings":"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"}
|
|
@@ -2,14 +2,12 @@
|
|
|
2
2
|
* yagni-runner — live-view entry for `opensip yagni` via @opensip-cli/cli-live.
|
|
3
3
|
*/
|
|
4
4
|
import { type LiveViewContext, type ToolCliContext } from '@opensip-cli/core';
|
|
5
|
-
import type { YagniGraphMode } from '../types/yagni-config.js';
|
|
6
5
|
import type { YagniConfidence } from '../types/yagni-metadata.js';
|
|
7
6
|
export { YAGNI_LIVE_VIEW_KEY } from '../identity.js';
|
|
8
7
|
export interface YagniLiveArgs {
|
|
9
8
|
readonly cwd: string;
|
|
10
9
|
readonly verbose?: boolean;
|
|
11
10
|
readonly quiet?: boolean;
|
|
12
|
-
readonly graphMode: YagniGraphMode;
|
|
13
11
|
readonly minConfidence?: YagniConfidence;
|
|
14
12
|
readonly detectors?: readonly string[];
|
|
15
13
|
readonly categories?: readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yagni-runner.d.ts","sourceRoot":"","sources":["../../src/cli/yagni-runner.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;
|
|
1
|
+
{"version":3,"file":"yagni-runner.d.ts","sourceRoot":"","sources":["../../src/cli/yagni-runner.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAGL,KAAK,eAAe,EACpB,KAAK,cAAc,EACpB,MAAM,mBAAmB,CAAC;AAQ3B,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAC;AAmClE,OAAO,EAAE,mBAAmB,EAAE,MAAM,gBAAgB,CAAC;AAErD,MAAM,WAAW,aAAa;IAC5B,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,OAAO,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC;IACzB,QAAQ,CAAC,aAAa,CAAC,EAAE,eAAe,CAAC;IACzC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACvC,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,YAAY,CAAC,EAAE,OAAO,CAAC;IAChC,QAAQ,CAAC,SAAS,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;CACxC;AA2BD,wBAAsB,eAAe,CACnC,IAAI,EAAE,aAAa,EACnB,GAAG,EAAE,cAAc,EACnB,WAAW,CAAC,EAAE,eAAe,0DAyE9B"}
|
package/dist/cli/yagni-runner.js
CHANGED
|
@@ -4,12 +4,37 @@
|
|
|
4
4
|
import { runToolLiveView } from '@opensip-cli/cli-live';
|
|
5
5
|
import { groupSignalsBySource } from '@opensip-cli/contracts';
|
|
6
6
|
import { isErrorSignal, currentScope, } from '@opensip-cli/core';
|
|
7
|
+
import { YAGNI_DETECTORS } from '../detectors/registry.js';
|
|
7
8
|
import { executeYagni } from './execute-yagni.js';
|
|
8
9
|
import { loadYagniConfig } from './yagni-config.js';
|
|
9
10
|
import { buildYagniPresentationLines } from './yagni-presentation.js';
|
|
10
11
|
const YAGNI_TOOL_TITLE = 'YAGNI Audit';
|
|
11
12
|
const YAGNI_TOOL_DESCRIPTION = 'Scanning for speculative surface to remove.';
|
|
12
|
-
|
|
13
|
+
/**
|
|
14
|
+
* Friendly checklist row label from a detector slug — drops the `yagni:`
|
|
15
|
+
* namespace and title-cases the kebab tail (`yagni:unused-config-surface` →
|
|
16
|
+
* `Unused Config Surface`).
|
|
17
|
+
*/
|
|
18
|
+
function detectorLabel(slug) {
|
|
19
|
+
const name = slug.slice(slug.indexOf(':') + 1);
|
|
20
|
+
return name
|
|
21
|
+
.split('-')
|
|
22
|
+
.map((w) => (w.length === 0 ? w : w[0].toUpperCase() + w.slice(1)))
|
|
23
|
+
.join(' ');
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Per-detector checklist (one phase per detector), mirroring graph's staged view.
|
|
27
|
+
* Detectors run serially, so each row spins, completes with its duration, then the
|
|
28
|
+
* next starts; a detector `planDetectors` excludes renders as a skipped row.
|
|
29
|
+
*/
|
|
30
|
+
const YAGNI_RUNNING_SURFACE = {
|
|
31
|
+
shape: 'phases',
|
|
32
|
+
stages: YAGNI_DETECTORS.map((d) => ({
|
|
33
|
+
id: d.slug,
|
|
34
|
+
label: detectorLabel(d.slug),
|
|
35
|
+
runningDetail: 'Analyzing project...',
|
|
36
|
+
})),
|
|
37
|
+
};
|
|
13
38
|
const YAGNI_LOADING_SURFACE = { shape: 'pool', label: 'Loading detectors...' };
|
|
14
39
|
export { YAGNI_LIVE_VIEW_KEY } from '../identity.js';
|
|
15
40
|
function rowStatus(unit) {
|
|
@@ -50,27 +75,34 @@ export async function renderYagniLive(args, cli, liveContext) {
|
|
|
50
75
|
projectPath: args.cwd,
|
|
51
76
|
walkedUp: currentScope()?.projectContext?.walkedUp,
|
|
52
77
|
produce: async (emit, helpers) => {
|
|
53
|
-
emit({ type: 'stage-start', stage: 'detectors', label: 'Running detectors...' });
|
|
54
78
|
helpers.setRunning(() => {
|
|
55
|
-
// In-process run —
|
|
79
|
+
// In-process run — per-detector phase events flow through emit() directly.
|
|
56
80
|
});
|
|
57
81
|
const executeOpts = {
|
|
58
82
|
cwd: args.cwd,
|
|
59
83
|
config,
|
|
60
|
-
graphMode: args.graphMode,
|
|
61
84
|
minConfidence: args.minConfidence,
|
|
62
85
|
detectors: args.detectors,
|
|
63
86
|
categories: args.categories,
|
|
64
87
|
includeTests: args.includeTests,
|
|
65
88
|
pathRoots: args.pathRoots,
|
|
66
|
-
|
|
67
|
-
|
|
89
|
+
// Phases live view: one checklist row per detector (declared in
|
|
90
|
+
// YAGNI_RUNNING_SURFACE), driven by the detector lifecycle.
|
|
91
|
+
onDetectorStart: (slug) => {
|
|
92
|
+
emit({ type: 'stage-start', stage: slug, label: detectorLabel(slug) });
|
|
93
|
+
},
|
|
94
|
+
onDetectorDone: (slug, durationMs) => {
|
|
95
|
+
emit({ type: 'stage-done', stage: slug, durationMs });
|
|
96
|
+
},
|
|
97
|
+
onDetectorsSkipped: (slugs) => {
|
|
98
|
+
for (const slug of slugs) {
|
|
99
|
+
emit({ type: 'stage-done', stage: slug, durationMs: 0, detail: 'skipped' });
|
|
100
|
+
}
|
|
68
101
|
},
|
|
69
102
|
};
|
|
70
103
|
const outcome = await executeYagni(executeOpts, cli);
|
|
71
|
-
const graphMode = outcome.session.payload.summary.graphMode ?? args.graphMode;
|
|
72
104
|
const skippedDetectors = outcome.session.payload.summary.skippedDetectors;
|
|
73
|
-
const verboseLines = buildYagniPresentationLines(outcome.envelope, args.cwd,
|
|
105
|
+
const verboseLines = buildYagniPresentationLines(outcome.envelope, args.cwd, skippedDetectors, args.verbose === true);
|
|
74
106
|
return {
|
|
75
107
|
kind: 'done',
|
|
76
108
|
done: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"yagni-runner.js","sourceRoot":"","sources":["../../src/cli/yagni-runner.tsx"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAC9D,OAAO,EACL,aAAa,EACb,YAAY,GAGb,MAAM,mBAAmB,CAAC;AAE3B,OAAO,EAAE,YAAY,EAA4B,MAAM,oBAAoB,CAAC;AAC5E,OAAO,EAAE,eAAe,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAE,2BAA2B,EAAE,MAAM,yBAAyB,CAAC;
|
|
1
|
+
{"version":3,"file":"yagni-runner.js","sourceRoot":"","sources":["../../src/cli/yagni-runner.tsx"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,13 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* duplicate-body-candidate —
|
|
3
|
-
*
|
|
2
|
+
* duplicate-body-candidate — flags function bodies that are byte-identical (after comment
|
|
3
|
+
* strip + whitespace normalization) across two or more sites, so they can be consolidated.
|
|
4
|
+
*
|
|
5
|
+
* yagni owns NO detection math (ADR-0064): it builds its own TypeScript inventory
|
|
6
|
+
* (`buildTsInventory`, no `@opensip-cli/graph` dependency) and calls the shared
|
|
7
|
+
* `findDuplicateBodies` from `@opensip-cli/clone-detection` — the SAME implementation +
|
|
8
|
+
* curation policy graph's `graph:duplicated-function-body` rule uses, so the two tools
|
|
9
|
+
* cannot diverge (the cross-tool parity test is the standing guard). yagni adds only the
|
|
10
|
+
* reduction framing + confidence/metadata.
|
|
4
11
|
*/
|
|
5
12
|
import type { YagniDetector } from './types.js';
|
|
6
13
|
export declare const duplicateBodyCandidateDetector: YagniDetector;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-body-candidate.d.ts","sourceRoot":"","sources":["../../src/detectors/duplicate-body-candidate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"duplicate-body-candidate.d.ts","sourceRoot":"","sources":["../../src/detectors/duplicate-body-candidate.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAUH,OAAO,KAAK,EAAE,aAAa,EAA6C,MAAM,YAAY,CAAC;AAsI3F,eAAO,MAAM,8BAA8B,EAAE,aAK5C,CAAC"}
|
|
@@ -1,137 +1,140 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* duplicate-body-candidate —
|
|
3
|
-
*
|
|
2
|
+
* duplicate-body-candidate — flags function bodies that are byte-identical (after comment
|
|
3
|
+
* strip + whitespace normalization) across two or more sites, so they can be consolidated.
|
|
4
|
+
*
|
|
5
|
+
* yagni owns NO detection math (ADR-0064): it builds its own TypeScript inventory
|
|
6
|
+
* (`buildTsInventory`, no `@opensip-cli/graph` dependency) and calls the shared
|
|
7
|
+
* `findDuplicateBodies` from `@opensip-cli/clone-detection` — the SAME implementation +
|
|
8
|
+
* curation policy graph's `graph:duplicated-function-body` rule uses, so the two tools
|
|
9
|
+
* cannot diverge (the cross-tool parity test is the standing guard). yagni adds only the
|
|
10
|
+
* reduction framing + confidence/metadata.
|
|
4
11
|
*/
|
|
5
|
-
import {
|
|
12
|
+
import { findDuplicateBodies } from '@opensip-cli/clone-detection';
|
|
13
|
+
import { currentScope, withSpan } from '@opensip-cli/core';
|
|
14
|
+
import { buildTsInventory } from '../lib/build-ts-inventory.js';
|
|
6
15
|
import { severityForConfidence } from '../scoring/confidence.js';
|
|
7
16
|
import { createYagniSignal } from './create-yagni-signal.js';
|
|
8
17
|
const DETECTOR_ID = 'duplicate-body-candidate';
|
|
9
18
|
const SLUG = 'yagni:duplicate-body-candidate';
|
|
10
|
-
const
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
const buckets = new Map();
|
|
14
|
-
for (const occurrences of Object.values(catalog.functions)) {
|
|
15
|
-
for (const occ of occurrences) {
|
|
16
|
-
const bucket = buckets.get(occ.bodyHash);
|
|
17
|
-
if (bucket)
|
|
18
|
-
bucket.push(occ);
|
|
19
|
-
else
|
|
20
|
-
buckets.set(occ.bodyHash, [occ]);
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
return buckets;
|
|
19
|
+
const CONFIDENCE = 'medium';
|
|
20
|
+
function span(occ) {
|
|
21
|
+
return occ.bodyLines ?? occ.endLine - occ.line + 1;
|
|
24
22
|
}
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
function
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
23
|
+
/**
|
|
24
|
+
* Build a reduction signal for a duplicate group.
|
|
25
|
+
*
|
|
26
|
+
* @throws {Error} If the clone-detection substrate returns a structurally invalid
|
|
27
|
+
* empty group.
|
|
28
|
+
*/
|
|
29
|
+
function groupSignal(group) {
|
|
30
|
+
const primary = group.members[0];
|
|
31
|
+
/* v8 ignore next */
|
|
32
|
+
if (!primary)
|
|
33
|
+
throw new Error('duplicate group with no members');
|
|
34
|
+
const count = group.members.length;
|
|
35
|
+
const netEstimate = span(primary) * (count - 1);
|
|
36
|
+
const peers = group.members
|
|
37
|
+
.slice(1)
|
|
38
|
+
.map((m) => `${m.filePath}:${String(m.line)}`)
|
|
39
|
+
.join(', ');
|
|
40
|
+
return createYagniSignal({
|
|
41
|
+
source: SLUG,
|
|
42
|
+
ruleId: SLUG,
|
|
43
|
+
severity: severityForConfidence(CONFIDENCE),
|
|
44
|
+
category: 'quality',
|
|
45
|
+
message: `${primary.simpleName} has a body duplicated across ${String(count)} sites — consolidate.`,
|
|
46
|
+
suggestion: `Extract the shared body into one function and have all ${String(count)} sites call it.`,
|
|
47
|
+
code: { file: primary.filePath, line: primary.line, column: primary.column },
|
|
48
|
+
yagni: {
|
|
49
|
+
detector: DETECTOR_ID,
|
|
50
|
+
reductionCategory: 'dedupe',
|
|
51
|
+
confidence: CONFIDENCE,
|
|
52
|
+
locDelta: { remove: netEstimate, add: 0, netEstimate, estimateKind: 'lower-bound' },
|
|
53
|
+
preservationArgument: `The body is byte-identical (normalized) across ${String(count)} sites, so consolidating to one function preserves behavior.`,
|
|
54
|
+
suggestedAction: `Consolidate ${String(count)} identical copies of ${primary.simpleName} (peers: ${peers}).`,
|
|
55
|
+
validationRequired: [
|
|
56
|
+
'Confirm the copies are behaviorally identical, not just textually (closures, captured scope).',
|
|
57
|
+
'Run the affected packages’ test suites after consolidation.',
|
|
58
|
+
],
|
|
59
|
+
riskTags: [],
|
|
60
|
+
evidence: [
|
|
61
|
+
{
|
|
62
|
+
id: `dup-body:${primary.bodyHash}`,
|
|
63
|
+
kind: 'duplicate-body',
|
|
64
|
+
summary: `${String(count)} sites share body hash ${primary.bodyHash.slice(0, 12)}.`,
|
|
65
|
+
data: {
|
|
66
|
+
bodyHash: primary.bodyHash,
|
|
67
|
+
occurrenceCount: count,
|
|
68
|
+
sites: group.members.map((m) => `${m.filePath}:${String(m.line)}`),
|
|
69
|
+
},
|
|
70
|
+
},
|
|
71
|
+
],
|
|
72
|
+
},
|
|
73
|
+
});
|
|
46
74
|
}
|
|
47
|
-
function
|
|
48
|
-
|
|
75
|
+
function aggregateSignal(agg) {
|
|
76
|
+
const netEstimate = span(agg.anchor) * (agg.occurrenceCount - 1);
|
|
77
|
+
return createYagniSignal({
|
|
78
|
+
source: SLUG,
|
|
79
|
+
ruleId: SLUG,
|
|
80
|
+
severity: severityForConfidence(CONFIDENCE),
|
|
81
|
+
category: 'quality',
|
|
82
|
+
message: `A body is duplicated across ${String(agg.packages.length)} packages (${agg.packages.join(', ')}) in ${String(agg.occurrenceCount)} sites — hoist it into a shared package.`,
|
|
83
|
+
suggestion: 'Hoist the shared body into one shared package and have every copy import it.',
|
|
84
|
+
code: { file: agg.anchor.filePath, line: agg.anchor.line, column: agg.anchor.column },
|
|
85
|
+
yagni: {
|
|
86
|
+
detector: DETECTOR_ID,
|
|
87
|
+
reductionCategory: 'dedupe',
|
|
88
|
+
confidence: CONFIDENCE,
|
|
89
|
+
locDelta: { remove: netEstimate, add: 0, netEstimate, estimateKind: 'lower-bound' },
|
|
90
|
+
preservationArgument: `The same normalized body appears in ${String(agg.occurrenceCount)} sites across ${String(agg.packages.length)} packages; hoisting to a shared package preserves behavior.`,
|
|
91
|
+
suggestedAction: `Hoist the body shared across ${agg.packages.join(', ')} into one shared package.`,
|
|
92
|
+
validationRequired: [
|
|
93
|
+
'Confirm the cross-package copies are behaviorally identical.',
|
|
94
|
+
'Add the new shared package as a dependency of each consumer and run their tests.',
|
|
95
|
+
],
|
|
96
|
+
riskTags: ['cross-package'],
|
|
97
|
+
evidence: [
|
|
98
|
+
{
|
|
99
|
+
id: `dup-body-xpkg:${agg.bodyHash}`,
|
|
100
|
+
kind: 'cross-package-duplicate-body',
|
|
101
|
+
summary: `${String(agg.occurrenceCount)} sites across ${agg.packages.join(', ')} share body hash ${agg.bodyHash.slice(0, 12)}.`,
|
|
102
|
+
data: {
|
|
103
|
+
bodyHash: agg.bodyHash,
|
|
104
|
+
occurrenceCount: agg.occurrenceCount,
|
|
105
|
+
packages: agg.packages,
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
],
|
|
109
|
+
},
|
|
110
|
+
});
|
|
49
111
|
}
|
|
50
112
|
function runDuplicateBodyCandidate(ctx) {
|
|
51
|
-
const
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
const anchorRel = relPath(ctx.cwd, anchor.filePath);
|
|
72
|
-
const peer = occs.find((o) => o.qualifiedName !== anchor.qualifiedName) ?? anchor;
|
|
73
|
-
const peerDisplay = displayOccurrence(ctx.cwd, peer);
|
|
74
|
-
signals.push(createYagniSignal({
|
|
75
|
-
source: SLUG,
|
|
76
|
-
ruleId: SLUG,
|
|
77
|
-
severity: severityForConfidence(confidence),
|
|
78
|
-
category: 'architecture',
|
|
79
|
-
message: `Duplicate body candidate (${String(occs.length)} occurrences) — consolidate shared logic (${confidence} confidence)`,
|
|
80
|
-
suggestion: 'Extract the shared body into one module and import it from each copy site.',
|
|
81
|
-
code: {
|
|
82
|
-
file: anchor.filePath,
|
|
83
|
-
line: anchor.line,
|
|
84
|
-
column: anchor.column,
|
|
85
|
-
},
|
|
86
|
-
yagni: {
|
|
87
|
-
detector: DETECTOR_ID,
|
|
88
|
-
reductionCategory: 'dedupe',
|
|
89
|
-
confidence,
|
|
90
|
-
locDelta: {
|
|
91
|
-
remove: netEstimate,
|
|
92
|
-
add: Math.max(1, Math.floor(bodyLines / 2)),
|
|
93
|
-
netEstimate,
|
|
94
|
-
estimateKind: 'heuristic',
|
|
95
|
-
},
|
|
96
|
-
preservationArgument: 'Occurrences share an identical bodyHash from the graph catalog; behavior should match after hoisting.',
|
|
97
|
-
suggestedAction: `Consolidate with ${peerDisplay}.`,
|
|
98
|
-
validationRequired: [
|
|
99
|
-
'Confirm neither occurrence is published public API.',
|
|
100
|
-
'Run tests covering each duplicate site after extraction.',
|
|
101
|
-
],
|
|
102
|
-
riskTags: ['cross-package', 'behavior-preservation'],
|
|
103
|
-
evidence: [
|
|
104
|
-
{
|
|
105
|
-
id: `body-hash:${bodyHash}`,
|
|
106
|
-
kind: 'body-hash-group',
|
|
107
|
-
summary: `${String(occs.length)} functions share bodyHash ${bodyHash.slice(0, 8)}.`,
|
|
108
|
-
data: {
|
|
109
|
-
bodyHash,
|
|
110
|
-
occurrenceCount: occs.length,
|
|
111
|
-
packages,
|
|
112
|
-
anchor: {
|
|
113
|
-
qualifiedName: anchor.qualifiedName,
|
|
114
|
-
filePath: anchorRel,
|
|
115
|
-
line: anchor.line,
|
|
116
|
-
},
|
|
117
|
-
peer: {
|
|
118
|
-
qualifiedName: peer.qualifiedName,
|
|
119
|
-
filePath: relPath(ctx.cwd, peer.filePath),
|
|
120
|
-
line: peer.line,
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
},
|
|
124
|
-
],
|
|
125
|
-
},
|
|
126
|
-
}));
|
|
127
|
-
}
|
|
128
|
-
return Promise.resolve({ signals, durationMs: Date.now() - started });
|
|
113
|
+
const result = withSpan('opensip-cli-yagni', 'yagni.duplicate_body_candidate', () => {
|
|
114
|
+
const started = Date.now();
|
|
115
|
+
const candidates = buildTsInventory(ctx.cwd, ctx.pathRoots);
|
|
116
|
+
const { aggregates, groups } = findDuplicateBodies(candidates);
|
|
117
|
+
const signals = [
|
|
118
|
+
...aggregates.map((a) => aggregateSignal(a)),
|
|
119
|
+
...groups.map((g) => groupSignal(g)),
|
|
120
|
+
];
|
|
121
|
+
const durationMs = Date.now() - started;
|
|
122
|
+
// O2 — one structured scan-complete event (counts + duration only; never body text).
|
|
123
|
+
currentScope()?.logger?.info({
|
|
124
|
+
evt: 'yagni.duplicate-detector.scan.complete',
|
|
125
|
+
module: 'yagni:duplicate-body-candidate',
|
|
126
|
+
durationMs,
|
|
127
|
+
candidateCount: candidates.length,
|
|
128
|
+
groupCount: aggregates.length + groups.length,
|
|
129
|
+
});
|
|
130
|
+
return { signals, durationMs };
|
|
131
|
+
}, { 'yagni.detector': DETECTOR_ID });
|
|
132
|
+
return Promise.resolve(result);
|
|
129
133
|
}
|
|
130
134
|
export const duplicateBodyCandidateDetector = {
|
|
131
135
|
id: DETECTOR_ID,
|
|
132
136
|
slug: SLUG,
|
|
133
|
-
description: '
|
|
134
|
-
requiresGraph: true,
|
|
137
|
+
description: 'Function bodies duplicated across two or more sites (consolidation candidates)',
|
|
135
138
|
run: runDuplicateBodyCandidate,
|
|
136
139
|
};
|
|
137
140
|
//# sourceMappingURL=duplicate-body-candidate.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"duplicate-body-candidate.js","sourceRoot":"","sources":["../../src/detectors/duplicate-body-candidate.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"duplicate-body-candidate.js","sourceRoot":"","sources":["../../src/detectors/duplicate-body-candidate.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,4 +1,12 @@
|
|
|
1
1
|
import type { YagniDetector } from './types.js';
|
|
2
|
-
/**
|
|
2
|
+
/**
|
|
3
|
+
* Built-in detector registry in stable registration order.
|
|
4
|
+
*
|
|
5
|
+
* Duplicate-body detection is back (ADR-0064) but now owns NO detection math: it builds
|
|
6
|
+
* yagni's own TypeScript inventory and calls `findDuplicateBodies` from the shared
|
|
7
|
+
* `@opensip-cli/clone-detection` substrate — the same implementation + policy graph uses,
|
|
8
|
+
* so the 430-vs-0 divergence cannot recur (cross-tool parity test guards it). yagni keeps
|
|
9
|
+
* NO dependency on `@opensip-cli/graph`.
|
|
10
|
+
*/
|
|
3
11
|
export declare const YAGNI_DETECTORS: readonly YagniDetector[];
|
|
4
12
|
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/detectors/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/detectors/registry.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAEhD;;;;;;;;GAQG;AACH,eAAO,MAAM,eAAe,EAAE,SAAS,aAAa,EAGnD,CAAC"}
|
|
@@ -1,6 +1,14 @@
|
|
|
1
1
|
import { duplicateBodyCandidateDetector } from './duplicate-body-candidate.js';
|
|
2
2
|
import { unusedConfigSurfaceDetector } from './unused-config-surface.js';
|
|
3
|
-
/**
|
|
3
|
+
/**
|
|
4
|
+
* Built-in detector registry in stable registration order.
|
|
5
|
+
*
|
|
6
|
+
* Duplicate-body detection is back (ADR-0064) but now owns NO detection math: it builds
|
|
7
|
+
* yagni's own TypeScript inventory and calls `findDuplicateBodies` from the shared
|
|
8
|
+
* `@opensip-cli/clone-detection` substrate — the same implementation + policy graph uses,
|
|
9
|
+
* so the 430-vs-0 divergence cannot recur (cross-tool parity test guards it). yagni keeps
|
|
10
|
+
* NO dependency on `@opensip-cli/graph`.
|
|
11
|
+
*/
|
|
4
12
|
export const YAGNI_DETECTORS = [
|
|
5
13
|
unusedConfigSurfaceDetector,
|
|
6
14
|
duplicateBodyCandidateDetector,
|