@nexus-ioc/graph-analyzer 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/CHANGELOG.md +112 -0
- package/LICENSE +21 -0
- package/README.md +742 -0
- package/dist/analyzer/circular-dependency-detector.d.ts +94 -0
- package/dist/analyzer/circular-dependency-detector.js +203 -0
- package/dist/analyzer/circular-dependency-detector.js.map +1 -0
- package/dist/analyzer/module-depth-analyzer.d.ts +117 -0
- package/dist/analyzer/module-depth-analyzer.js +221 -0
- package/dist/analyzer/module-depth-analyzer.js.map +1 -0
- package/dist/analyzer/provider-scope-analyzer.d.ts +91 -0
- package/dist/analyzer/provider-scope-analyzer.js +137 -0
- package/dist/analyzer/provider-scope-analyzer.js.map +1 -0
- package/dist/analyzer/unused-provider-detector.d.ts +73 -0
- package/dist/analyzer/unused-provider-detector.js +147 -0
- package/dist/analyzer/unused-provider-detector.js.map +1 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +537 -0
- package/dist/cli.js.map +1 -0
- package/dist/config/config-loader.d.ts +27 -0
- package/dist/config/config-loader.js +205 -0
- package/dist/config/config-loader.js.map +1 -0
- package/dist/config/config-schema.d.ts +83 -0
- package/dist/config/config-schema.js +97 -0
- package/dist/config/config-schema.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.js +50 -0
- package/dist/index.js.map +1 -0
- package/dist/interfaces/graph-output.interface.d.ts +126 -0
- package/dist/interfaces/graph-output.interface.js +3 -0
- package/dist/interfaces/graph-output.interface.js.map +1 -0
- package/dist/interfaces/providers.interface.d.ts +10 -0
- package/dist/interfaces/providers.interface.js +3 -0
- package/dist/interfaces/providers.interface.js.map +1 -0
- package/dist/parser/dependency-extractor.d.ts +88 -0
- package/dist/parser/dependency-extractor.js +334 -0
- package/dist/parser/dependency-extractor.js.map +1 -0
- package/dist/parser/parse-entry-file.d.ts +15 -0
- package/dist/parser/parse-entry-file.js +46 -0
- package/dist/parser/parse-entry-file.js.map +1 -0
- package/dist/parser/parse-imports.d.ts +15 -0
- package/dist/parser/parse-imports.js +65 -0
- package/dist/parser/parse-imports.js.map +1 -0
- package/dist/parser/parse-ns-module.d.ts +39 -0
- package/dist/parser/parse-ns-module.js +122 -0
- package/dist/parser/parse-ns-module.js.map +1 -0
- package/dist/parser/parse-provider.d.ts +2 -0
- package/dist/parser/parse-provider.js +7 -0
- package/dist/parser/parse-provider.js.map +1 -0
- package/dist/parser/parse-ts-config.d.ts +10 -0
- package/dist/parser/parse-ts-config.js +40 -0
- package/dist/parser/parse-ts-config.js.map +1 -0
- package/dist/parser/parser-rec.d.ts +1 -0
- package/dist/parser/parser-rec.js +52 -0
- package/dist/parser/parser-rec.js.map +1 -0
- package/dist/parser/parser.d.ts +1 -0
- package/dist/parser/parser.js +61 -0
- package/dist/parser/parser.js.map +1 -0
- package/dist/parser/provider/class-parser.d.ts +20 -0
- package/dist/parser/provider/class-parser.js +137 -0
- package/dist/parser/provider/class-parser.js.map +1 -0
- package/dist/parser/provider/providers-parser.d.ts +9 -0
- package/dist/parser/provider/providers-parser.js +32 -0
- package/dist/parser/provider/providers-parser.js.map +1 -0
- package/dist/parser/provider/use-class-parser.d.ts +25 -0
- package/dist/parser/provider/use-class-parser.js +161 -0
- package/dist/parser/provider/use-class-parser.js.map +1 -0
- package/dist/parser/provider/use-factory-parser.d.ts +15 -0
- package/dist/parser/provider/use-factory-parser.js +53 -0
- package/dist/parser/provider/use-factory-parser.js.map +1 -0
- package/dist/parser/provider/use-value-parser.d.ts +13 -0
- package/dist/parser/provider/use-value-parser.js +41 -0
- package/dist/parser/provider/use-value-parser.js.map +1 -0
- package/dist/parser/rules.d.ts +10 -0
- package/dist/parser/rules.js +37 -0
- package/dist/parser/rules.js.map +1 -0
- package/dist/utils/error-formatter.d.ts +27 -0
- package/dist/utils/error-formatter.js +177 -0
- package/dist/utils/error-formatter.js.map +1 -0
- package/dist/utils/validator.d.ts +45 -0
- package/dist/utils/validator.js +252 -0
- package/dist/utils/validator.js.map +1 -0
- package/dist/visualize/generator.d.ts +26 -0
- package/dist/visualize/generator.js +75 -0
- package/dist/visualize/generator.js.map +1 -0
- package/dist/visualize/graph-analyzer.d.ts +126 -0
- package/dist/visualize/graph-analyzer.js +199 -0
- package/dist/visualize/graph-analyzer.js.map +1 -0
- package/dist/visualize/html-generator.d.ts +71 -0
- package/dist/visualize/html-generator.js +1312 -0
- package/dist/visualize/html-generator.js.map +1 -0
- package/dist/visualize/json-formatter.d.ts +106 -0
- package/dist/visualize/json-formatter.js +252 -0
- package/dist/visualize/json-formatter.js.map +1 -0
- package/docs/API_REFERENCE.md +747 -0
- package/docs/ARCHITECTURE.md +486 -0
- package/docs/CLI_GUIDE.md +576 -0
- package/docs/HTML_VISUALIZATION.md +365 -0
- package/package.json +85 -0
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
import type { ParseEntryFile } from "../parser/parse-entry-file";
|
|
2
|
+
import type { ParseNsModule } from "../parser/parse-ns-module";
|
|
3
|
+
/**
|
|
4
|
+
* Provider scope types
|
|
5
|
+
*/
|
|
6
|
+
export type ProviderScope = "Singleton" | "Request";
|
|
7
|
+
/**
|
|
8
|
+
* Information about a provider's scope
|
|
9
|
+
*/
|
|
10
|
+
export interface ProviderScopeInfo {
|
|
11
|
+
/** Provider token */
|
|
12
|
+
token: string;
|
|
13
|
+
/** Module that registers this provider */
|
|
14
|
+
module: string;
|
|
15
|
+
/** Provider scope */
|
|
16
|
+
scope: ProviderScope;
|
|
17
|
+
/** Provider type */
|
|
18
|
+
type: "Class" | "UseValue" | "UseFactory" | "UseClass";
|
|
19
|
+
/** Dependencies of this provider */
|
|
20
|
+
dependencies: string[];
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Scope mismatch issue
|
|
24
|
+
*/
|
|
25
|
+
export interface ScopeMismatch {
|
|
26
|
+
/** Provider with scope issue */
|
|
27
|
+
provider: string;
|
|
28
|
+
/** Provider's scope */
|
|
29
|
+
providerScope: ProviderScope;
|
|
30
|
+
/** Module that registers the provider */
|
|
31
|
+
module: string;
|
|
32
|
+
/** Dependency that causes the mismatch */
|
|
33
|
+
dependency: string;
|
|
34
|
+
/** Dependency's scope */
|
|
35
|
+
dependencyScope: ProviderScope;
|
|
36
|
+
/** Severity of the issue */
|
|
37
|
+
severity: "error" | "warning";
|
|
38
|
+
/** Description of the issue */
|
|
39
|
+
message: string;
|
|
40
|
+
/** Suggestions for fixing the issue */
|
|
41
|
+
suggestions: string[];
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* Provider scope analysis results
|
|
45
|
+
*/
|
|
46
|
+
export interface ProviderScopeAnalysis {
|
|
47
|
+
/** Whether scope analysis was performed */
|
|
48
|
+
hasScopeAnalysis: boolean;
|
|
49
|
+
/** Total number of providers analyzed */
|
|
50
|
+
totalProviders: number;
|
|
51
|
+
/** Number of singleton providers */
|
|
52
|
+
singletonProviders: number;
|
|
53
|
+
/** Number of request-scoped providers */
|
|
54
|
+
requestProviders: number;
|
|
55
|
+
/** Scope mismatches detected */
|
|
56
|
+
scopeMismatches: ScopeMismatch[];
|
|
57
|
+
/** All provider scope information */
|
|
58
|
+
providerScopes: ProviderScopeInfo[];
|
|
59
|
+
}
|
|
60
|
+
/**
|
|
61
|
+
* Analyzes provider scopes and detects scope-related issues
|
|
62
|
+
*
|
|
63
|
+
* This analyzer identifies:
|
|
64
|
+
* - Singleton providers depending on request-scoped providers (scope mismatch)
|
|
65
|
+
* - Potential memory leaks from scope misuse
|
|
66
|
+
* - Scope optimization opportunities
|
|
67
|
+
*/
|
|
68
|
+
export declare class ProviderScopeAnalyzer {
|
|
69
|
+
private readonly graph;
|
|
70
|
+
constructor(graph: Map<string, ParseNsModule | ParseEntryFile>);
|
|
71
|
+
/**
|
|
72
|
+
* Analyze provider scopes and detect issues
|
|
73
|
+
*/
|
|
74
|
+
analyze(): ProviderScopeAnalysis;
|
|
75
|
+
/**
|
|
76
|
+
* Build a map of all providers with their scope information
|
|
77
|
+
*/
|
|
78
|
+
private buildProviderScopeMap;
|
|
79
|
+
/**
|
|
80
|
+
* Extract scope from provider
|
|
81
|
+
*/
|
|
82
|
+
private extractProviderScope;
|
|
83
|
+
/**
|
|
84
|
+
* Extract dependency tokens from provider
|
|
85
|
+
*/
|
|
86
|
+
private extractDependencyTokens;
|
|
87
|
+
/**
|
|
88
|
+
* Detect scope mismatches in provider dependencies
|
|
89
|
+
*/
|
|
90
|
+
private detectScopeMismatches;
|
|
91
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProviderScopeAnalyzer = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Analyzes provider scopes and detects scope-related issues
|
|
6
|
+
*
|
|
7
|
+
* This analyzer identifies:
|
|
8
|
+
* - Singleton providers depending on request-scoped providers (scope mismatch)
|
|
9
|
+
* - Potential memory leaks from scope misuse
|
|
10
|
+
* - Scope optimization opportunities
|
|
11
|
+
*/
|
|
12
|
+
class ProviderScopeAnalyzer {
|
|
13
|
+
constructor(graph) {
|
|
14
|
+
this.graph = graph;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Analyze provider scopes and detect issues
|
|
18
|
+
*/
|
|
19
|
+
analyze() {
|
|
20
|
+
// Build provider scope map
|
|
21
|
+
const providerScopes = this.buildProviderScopeMap();
|
|
22
|
+
// Detect scope mismatches
|
|
23
|
+
const scopeMismatches = this.detectScopeMismatches(providerScopes);
|
|
24
|
+
// Calculate statistics
|
|
25
|
+
const singletonCount = providerScopes.filter((p) => p.scope === "Singleton").length;
|
|
26
|
+
const requestCount = providerScopes.filter((p) => p.scope === "Request").length;
|
|
27
|
+
return {
|
|
28
|
+
hasScopeAnalysis: true,
|
|
29
|
+
totalProviders: providerScopes.length,
|
|
30
|
+
singletonProviders: singletonCount,
|
|
31
|
+
requestProviders: requestCount,
|
|
32
|
+
scopeMismatches,
|
|
33
|
+
providerScopes,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Build a map of all providers with their scope information
|
|
38
|
+
*/
|
|
39
|
+
buildProviderScopeMap() {
|
|
40
|
+
const providerScopes = [];
|
|
41
|
+
for (const [key, value] of this.graph.entries()) {
|
|
42
|
+
if (key === "entry")
|
|
43
|
+
continue;
|
|
44
|
+
const parseNsModule = value;
|
|
45
|
+
if (!parseNsModule.providers)
|
|
46
|
+
continue;
|
|
47
|
+
for (const provider of parseNsModule.providers) {
|
|
48
|
+
if (!provider.token)
|
|
49
|
+
continue;
|
|
50
|
+
const scope = this.extractProviderScope(provider);
|
|
51
|
+
const dependencies = this.extractDependencyTokens(provider);
|
|
52
|
+
providerScopes.push({
|
|
53
|
+
token: provider.token,
|
|
54
|
+
module: parseNsModule.name || key,
|
|
55
|
+
scope,
|
|
56
|
+
type: provider.type,
|
|
57
|
+
dependencies,
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
return providerScopes;
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Extract scope from provider
|
|
65
|
+
*/
|
|
66
|
+
extractProviderScope(provider) {
|
|
67
|
+
// Check if scope is explicitly defined (applies to all provider types)
|
|
68
|
+
if (provider.scope) {
|
|
69
|
+
const scopeStr = provider.scope.toLowerCase();
|
|
70
|
+
if (scopeStr.includes("request") || scopeStr === "1") {
|
|
71
|
+
return "Request";
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// Default to Singleton for all provider types
|
|
75
|
+
return "Singleton";
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Extract dependency tokens from provider
|
|
79
|
+
*/
|
|
80
|
+
extractDependencyTokens(provider) {
|
|
81
|
+
const tokens = [];
|
|
82
|
+
// Extract from dependencies array (Class and UseClass providers)
|
|
83
|
+
if (provider.dependencies && Array.isArray(provider.dependencies)) {
|
|
84
|
+
for (const dep of provider.dependencies) {
|
|
85
|
+
if (dep.token && !dep.optional) {
|
|
86
|
+
tokens.push(dep.token);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Extract from inject array (UseFactory providers)
|
|
91
|
+
if (provider.inject && Array.isArray(provider.inject)) {
|
|
92
|
+
tokens.push(...provider.inject);
|
|
93
|
+
}
|
|
94
|
+
return tokens;
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Detect scope mismatches in provider dependencies
|
|
98
|
+
*/
|
|
99
|
+
detectScopeMismatches(providerScopes) {
|
|
100
|
+
const mismatches = [];
|
|
101
|
+
const scopeMap = new Map();
|
|
102
|
+
// Build lookup map
|
|
103
|
+
for (const provider of providerScopes) {
|
|
104
|
+
scopeMap.set(provider.token, provider);
|
|
105
|
+
}
|
|
106
|
+
// Check each provider's dependencies
|
|
107
|
+
for (const provider of providerScopes) {
|
|
108
|
+
// Only check Singleton providers (they shouldn't depend on Request-scoped)
|
|
109
|
+
if (provider.scope !== "Singleton") {
|
|
110
|
+
continue;
|
|
111
|
+
}
|
|
112
|
+
for (const depToken of provider.dependencies) {
|
|
113
|
+
const dependency = scopeMap.get(depToken);
|
|
114
|
+
// If dependency is Request-scoped, this is a scope mismatch
|
|
115
|
+
if (dependency && dependency.scope === "Request") {
|
|
116
|
+
mismatches.push({
|
|
117
|
+
provider: provider.token,
|
|
118
|
+
providerScope: provider.scope,
|
|
119
|
+
module: provider.module,
|
|
120
|
+
dependency: depToken,
|
|
121
|
+
dependencyScope: dependency.scope,
|
|
122
|
+
severity: "error",
|
|
123
|
+
message: `Singleton provider '${provider.token}' depends on Request-scoped provider '${depToken}'. This can cause memory leaks and unexpected behavior.`,
|
|
124
|
+
suggestions: [
|
|
125
|
+
`Change '${provider.token}' to Request scope`,
|
|
126
|
+
`Change '${depToken}' to Singleton scope if it doesn't need request-specific state`,
|
|
127
|
+
"Use a factory or lazy injection to resolve the dependency per request",
|
|
128
|
+
],
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
return mismatches;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
exports.ProviderScopeAnalyzer = ProviderScopeAnalyzer;
|
|
137
|
+
//# sourceMappingURL=provider-scope-analyzer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"provider-scope-analyzer.js","sourceRoot":"","sources":["../../src/analyzer/provider-scope-analyzer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import type { ParseEntryFile } from "../parser/parse-entry-file";
|
|
2
|
+
import type { ParseNsModule } from "../parser/parse-ns-module";
|
|
3
|
+
/**
|
|
4
|
+
* Information about an unused provider
|
|
5
|
+
*/
|
|
6
|
+
export interface UnusedProvider {
|
|
7
|
+
/** Provider token (identifier) */
|
|
8
|
+
token: string;
|
|
9
|
+
/** Module where the provider is registered */
|
|
10
|
+
module: string;
|
|
11
|
+
/** Type of provider */
|
|
12
|
+
type: "Class" | "UseValue" | "UseFactory" | "UseClass";
|
|
13
|
+
/** Severity level */
|
|
14
|
+
severity: "warning" | "info";
|
|
15
|
+
/** Descriptive message */
|
|
16
|
+
message: string;
|
|
17
|
+
/** Suggestions for resolution */
|
|
18
|
+
suggestions: string[];
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Analysis results for unused providers
|
|
22
|
+
*/
|
|
23
|
+
export interface UnusedProviderAnalysis {
|
|
24
|
+
/** Whether any unused providers were detected */
|
|
25
|
+
hasUnusedProviders: boolean;
|
|
26
|
+
/** List of unused providers */
|
|
27
|
+
unusedProviders: UnusedProvider[];
|
|
28
|
+
/** Total count of unused providers */
|
|
29
|
+
totalUnused: number;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* Detects providers that are registered but never injected
|
|
33
|
+
*
|
|
34
|
+
* Analyzes the dependency graph to find providers that are:
|
|
35
|
+
* - Registered in a module's providers array
|
|
36
|
+
* - Not injected as dependencies in any other provider
|
|
37
|
+
* - Not exported from the module (unless they're used internally)
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* const detector = new UnusedProviderDetector(modulesGraph);
|
|
42
|
+
* const analysis = detector.analyze();
|
|
43
|
+
*
|
|
44
|
+
* if (analysis.hasUnusedProviders) {
|
|
45
|
+
* console.log(`Found ${analysis.totalUnused} unused providers`);
|
|
46
|
+
* for (const provider of analysis.unusedProviders) {
|
|
47
|
+
* console.log(`- ${provider.token} in ${provider.module}`);
|
|
48
|
+
* }
|
|
49
|
+
* }
|
|
50
|
+
* ```
|
|
51
|
+
*/
|
|
52
|
+
export declare class UnusedProviderDetector {
|
|
53
|
+
private readonly graph;
|
|
54
|
+
constructor(graph: Map<string, ParseNsModule | ParseEntryFile>);
|
|
55
|
+
/**
|
|
56
|
+
* Analyze the graph for unused providers
|
|
57
|
+
*
|
|
58
|
+
* @returns Analysis results containing all unused providers
|
|
59
|
+
*/
|
|
60
|
+
analyze(): UnusedProviderAnalysis;
|
|
61
|
+
/**
|
|
62
|
+
* Build a set of all provider tokens that are injected as dependencies
|
|
63
|
+
*/
|
|
64
|
+
private buildInjectedTokensSet;
|
|
65
|
+
/**
|
|
66
|
+
* Build a set of all provider tokens that are exported from modules
|
|
67
|
+
*/
|
|
68
|
+
private buildExportedTokensSet;
|
|
69
|
+
/**
|
|
70
|
+
* Generate suggestions for resolving an unused provider
|
|
71
|
+
*/
|
|
72
|
+
private generateSuggestions;
|
|
73
|
+
}
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.UnusedProviderDetector = void 0;
|
|
4
|
+
/**
|
|
5
|
+
* Detects providers that are registered but never injected
|
|
6
|
+
*
|
|
7
|
+
* Analyzes the dependency graph to find providers that are:
|
|
8
|
+
* - Registered in a module's providers array
|
|
9
|
+
* - Not injected as dependencies in any other provider
|
|
10
|
+
* - Not exported from the module (unless they're used internally)
|
|
11
|
+
*
|
|
12
|
+
* @example
|
|
13
|
+
* ```typescript
|
|
14
|
+
* const detector = new UnusedProviderDetector(modulesGraph);
|
|
15
|
+
* const analysis = detector.analyze();
|
|
16
|
+
*
|
|
17
|
+
* if (analysis.hasUnusedProviders) {
|
|
18
|
+
* console.log(`Found ${analysis.totalUnused} unused providers`);
|
|
19
|
+
* for (const provider of analysis.unusedProviders) {
|
|
20
|
+
* console.log(`- ${provider.token} in ${provider.module}`);
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
class UnusedProviderDetector {
|
|
26
|
+
constructor(graph) {
|
|
27
|
+
this.graph = graph;
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Analyze the graph for unused providers
|
|
31
|
+
*
|
|
32
|
+
* @returns Analysis results containing all unused providers
|
|
33
|
+
*/
|
|
34
|
+
analyze() {
|
|
35
|
+
const unusedProviders = [];
|
|
36
|
+
// Build a set of all injected provider tokens
|
|
37
|
+
const injectedTokens = this.buildInjectedTokensSet();
|
|
38
|
+
// Build a set of all exported provider tokens
|
|
39
|
+
const exportedTokens = this.buildExportedTokensSet();
|
|
40
|
+
// Check each module for unused providers
|
|
41
|
+
for (const [moduleName, module] of this.graph) {
|
|
42
|
+
if (moduleName === "entry")
|
|
43
|
+
continue;
|
|
44
|
+
const nsModule = module;
|
|
45
|
+
if (!nsModule.providers || nsModule.providers.length === 0)
|
|
46
|
+
continue;
|
|
47
|
+
// Check each provider in the module
|
|
48
|
+
for (const provider of nsModule.providers) {
|
|
49
|
+
const token = provider.token;
|
|
50
|
+
// Skip providers with null tokens
|
|
51
|
+
if (!token)
|
|
52
|
+
continue;
|
|
53
|
+
// Skip if the provider is injected somewhere
|
|
54
|
+
if (injectedTokens.has(token))
|
|
55
|
+
continue;
|
|
56
|
+
// Skip if the provider is exported (it may be used externally)
|
|
57
|
+
if (exportedTokens.has(token))
|
|
58
|
+
continue;
|
|
59
|
+
// Skip if the module is global (providers may be used across the app)
|
|
60
|
+
if (nsModule.isGlobal)
|
|
61
|
+
continue;
|
|
62
|
+
// This provider is unused
|
|
63
|
+
const suggestions = this.generateSuggestions(token, moduleName, exportedTokens.has(token), nsModule.isGlobal);
|
|
64
|
+
// Normalize provider type to match expected union type
|
|
65
|
+
const providerType = provider.type;
|
|
66
|
+
unusedProviders.push({
|
|
67
|
+
token,
|
|
68
|
+
module: moduleName,
|
|
69
|
+
type: providerType,
|
|
70
|
+
severity: "warning",
|
|
71
|
+
message: `Provider '${token}' is registered in '${moduleName}' but never injected`,
|
|
72
|
+
suggestions,
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return {
|
|
77
|
+
hasUnusedProviders: unusedProviders.length > 0,
|
|
78
|
+
unusedProviders,
|
|
79
|
+
totalUnused: unusedProviders.length,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Build a set of all provider tokens that are injected as dependencies
|
|
84
|
+
*/
|
|
85
|
+
buildInjectedTokensSet() {
|
|
86
|
+
const injectedTokens = new Set();
|
|
87
|
+
for (const [moduleName, module] of this.graph) {
|
|
88
|
+
if (moduleName === "entry")
|
|
89
|
+
continue;
|
|
90
|
+
const nsModule = module;
|
|
91
|
+
if (!nsModule.providers)
|
|
92
|
+
continue;
|
|
93
|
+
// Check dependencies of each provider
|
|
94
|
+
for (const provider of nsModule.providers) {
|
|
95
|
+
if (!provider.dependencies)
|
|
96
|
+
continue;
|
|
97
|
+
for (const dependency of provider.dependencies) {
|
|
98
|
+
// Skip optional dependencies as they may not be required
|
|
99
|
+
if (!dependency.optional) {
|
|
100
|
+
injectedTokens.add(dependency.token);
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
}
|
|
105
|
+
return injectedTokens;
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Build a set of all provider tokens that are exported from modules
|
|
109
|
+
*/
|
|
110
|
+
buildExportedTokensSet() {
|
|
111
|
+
const exportedTokens = new Set();
|
|
112
|
+
for (const [moduleName, module] of this.graph) {
|
|
113
|
+
if (moduleName === "entry")
|
|
114
|
+
continue;
|
|
115
|
+
const nsModule = module;
|
|
116
|
+
if (!nsModule.exports)
|
|
117
|
+
continue;
|
|
118
|
+
// Add all exported tokens
|
|
119
|
+
for (const exportedToken of nsModule.exports) {
|
|
120
|
+
exportedTokens.add(exportedToken);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
return exportedTokens;
|
|
124
|
+
}
|
|
125
|
+
/**
|
|
126
|
+
* Generate suggestions for resolving an unused provider
|
|
127
|
+
*/
|
|
128
|
+
generateSuggestions(token, moduleName, isExported, isGlobal) {
|
|
129
|
+
const suggestions = [];
|
|
130
|
+
if (isExported) {
|
|
131
|
+
suggestions.push(`Provider is exported - it may be used outside the analyzed scope`);
|
|
132
|
+
suggestions.push(`If not needed externally, remove '${token}' from the exports array`);
|
|
133
|
+
}
|
|
134
|
+
else if (isGlobal) {
|
|
135
|
+
suggestions.push(`Module is global - provider may be used across the application`);
|
|
136
|
+
suggestions.push(`Verify if '${token}' is actually needed before removing`);
|
|
137
|
+
}
|
|
138
|
+
else {
|
|
139
|
+
suggestions.push(`Remove '${token}' from the providers array in '${moduleName}'`);
|
|
140
|
+
suggestions.push(`Or export it if it's intended to be used by other modules`);
|
|
141
|
+
suggestions.push(`Or inject it somewhere if it provides side effects (e.g., initialization)`);
|
|
142
|
+
}
|
|
143
|
+
return suggestions;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
exports.UnusedProviderDetector = UnusedProviderDetector;
|
|
147
|
+
//# sourceMappingURL=unused-provider-detector.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"unused-provider-detector.js","sourceRoot":"","sources":["../../src/analyzer/unused-provider-detector.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED