nestjs-doctor 0.4.12 → 0.4.14

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 CHANGED
@@ -1,3 +1,7 @@
1
+ <p align="center">
2
+ <img src="https://nestjs.doctor/logo.png" width="120" alt="nestjs-doctor logo" />
3
+ </p>
4
+
1
5
  <p align="center">
2
6
  <h1 align="center">nestjs-doctor</h1>
3
7
  </p>
@@ -114,6 +114,55 @@ function extractArrayPropertyNames(obj, propertyName) {
114
114
  return text;
115
115
  });
116
116
  }
117
+ function updateModuleGraphForFile(graph, project, filePath) {
118
+ for (const [name, node] of graph.modules) if (node.filePath === filePath) {
119
+ graph.modules.delete(name);
120
+ graph.edges.delete(name);
121
+ for (const provider of node.providers) if (graph.providerToModule.get(provider) === node) graph.providerToModule.delete(provider);
122
+ for (const edgeSet of graph.edges.values()) edgeSet.delete(name);
123
+ }
124
+ const sourceFile = project.getSourceFile(filePath);
125
+ if (!sourceFile) return;
126
+ const newModules = [];
127
+ for (const cls of sourceFile.getClasses()) {
128
+ const moduleDecorator = cls.getDecorator("Module");
129
+ if (!moduleDecorator) continue;
130
+ const name = cls.getName() ?? "AnonymousModule";
131
+ const args = moduleDecorator.getArguments()[0];
132
+ const node = {
133
+ name,
134
+ filePath,
135
+ classDeclaration: cls,
136
+ imports: [],
137
+ exports: [],
138
+ providers: [],
139
+ controllers: []
140
+ };
141
+ if (args && args.getKind() === ts_morph.SyntaxKind.ObjectLiteralExpression) {
142
+ const obj = args.asKind(ts_morph.SyntaxKind.ObjectLiteralExpression);
143
+ if (obj) {
144
+ node.imports = extractArrayPropertyNames(obj, "imports");
145
+ node.exports = extractArrayPropertyNames(obj, "exports");
146
+ node.providers = extractArrayPropertyNames(obj, "providers");
147
+ node.controllers = extractArrayPropertyNames(obj, "controllers");
148
+ }
149
+ }
150
+ graph.modules.set(name, node);
151
+ newModules.push(node);
152
+ }
153
+ for (const node of newModules) {
154
+ const importSet = /* @__PURE__ */ new Set();
155
+ for (const imp of node.imports) if (graph.modules.has(imp)) importSet.add(imp);
156
+ graph.edges.set(node.name, importSet);
157
+ for (const provider of node.providers) graph.providerToModule.set(provider, node);
158
+ }
159
+ for (const [name, node] of graph.modules) {
160
+ if (node.filePath === filePath) continue;
161
+ const importSet = /* @__PURE__ */ new Set();
162
+ for (const imp of node.imports) if (graph.modules.has(imp)) importSet.add(imp);
163
+ graph.edges.set(name, importSet);
164
+ }
165
+ }
117
166
  function findCircularDeps(graph) {
118
167
  const cycles = [];
119
168
  const visited = /* @__PURE__ */ new Set();
@@ -321,6 +370,32 @@ function resolveProviders(project, files) {
321
370
  }
322
371
  return providers;
323
372
  }
373
+ function updateProvidersForFile(providers, project, filePath) {
374
+ for (const [name, info] of providers) if (info.filePath === filePath) providers.delete(name);
375
+ const sourceFile = project.getSourceFile(filePath);
376
+ if (!sourceFile) return;
377
+ for (const cls of sourceFile.getClasses()) {
378
+ if (!cls.getDecorator("Injectable")) continue;
379
+ const name = cls.getName();
380
+ if (!name) continue;
381
+ const ctor = cls.getConstructors()[0];
382
+ const dependencies = ctor ? ctor.getParameters().map((p) => {
383
+ const typeNode = p.getTypeNode();
384
+ return extractSimpleTypeName(typeNode ? typeNode.getText() : p.getType().getText());
385
+ }) : [];
386
+ const publicMethodCount = cls.getMethods().filter((m) => {
387
+ const scope = m.getScope();
388
+ return !scope || scope === "public";
389
+ }).length;
390
+ providers.set(name, {
391
+ name,
392
+ filePath,
393
+ classDeclaration: cls,
394
+ dependencies,
395
+ publicMethodCount
396
+ });
397
+ }
398
+ }
324
399
  function extractSimpleTypeName(typeText) {
325
400
  const importMatch = typeText.match(IMPORT_TYPE_REGEX);
326
401
  if (importMatch) return importMatch[1];
@@ -2265,11 +2340,11 @@ async function collectFiles(targetPath, config = {}) {
2265
2340
  })).sort();
2266
2341
  }
2267
2342
  async function collectMonorepoFiles(targetPath, monorepo, config = {}) {
2343
+ const entries = await Promise.all([...monorepo.projects.entries()].map(async ([name, root]) => {
2344
+ return [name, await collectFiles((0, node_path.join)(targetPath, root), config)];
2345
+ }));
2268
2346
  const result = /* @__PURE__ */ new Map();
2269
- for (const [name, root] of monorepo.projects) {
2270
- const files = await collectFiles((0, node_path.join)(targetPath, root), config);
2271
- result.set(name, files);
2272
- }
2347
+ for (const [name, files] of entries) result.set(name, files);
2273
2348
  return result;
2274
2349
  }
2275
2350
 
@@ -2490,9 +2565,8 @@ function formatRuleError(error) {
2490
2565
  }
2491
2566
  async function prepareScan(targetPath, options = {}) {
2492
2567
  const config = await loadConfig(targetPath, options.config);
2493
- const { rules: customRules, warnings: customRuleWarnings } = await resolveCustomRules(config, targetPath);
2568
+ const [{ rules: customRules, warnings: customRuleWarnings }, files] = await Promise.all([resolveCustomRules(config, targetPath), collectFiles(targetPath, config)]);
2494
2569
  const combinedRules = mergeRules(allRules, customRules, customRuleWarnings);
2495
- const files = await collectFiles(targetPath, config);
2496
2570
  const astProject = createAstParser(files);
2497
2571
  const moduleGraph = buildModuleGraph(astProject, files);
2498
2572
  const providers = resolveProviders(astProject, files);
@@ -2516,8 +2590,8 @@ function updateFile(context, filePath) {
2516
2590
  if (existing) context.astProject.removeSourceFile(existing);
2517
2591
  context.astProject.addSourceFileAtPath(filePath);
2518
2592
  if (!context.files.includes(filePath)) context.files.push(filePath);
2519
- context.moduleGraph = buildModuleGraph(context.astProject, context.files);
2520
- context.providers = resolveProviders(context.astProject, context.files);
2593
+ updateModuleGraphForFile(context.moduleGraph, context.astProject, filePath);
2594
+ updateProvidersForFile(context.providers, context.astProject, filePath);
2521
2595
  }
2522
2596
  function scanFile(context, filePath) {
2523
2597
  const { diagnostics: rawDiagnostics, errors } = runFileRules(context.astProject, [filePath], context.fileRules);
@@ -2557,11 +2631,12 @@ function scanProject(context) {
2557
2631
  async function scan(targetPath, options = {}) {
2558
2632
  const startTime = node_perf_hooks.performance.now();
2559
2633
  const { context, customRuleWarnings } = await prepareScan(targetPath, options);
2634
+ const projectPromise = detectProject(targetPath);
2560
2635
  const fileResult = scanAllFiles(context);
2561
2636
  const projectResult = scanProject(context);
2562
2637
  const diagnostics = [...fileResult.diagnostics, ...projectResult.diagnostics];
2563
2638
  const ruleErrors = [...fileResult.errors, ...projectResult.errors];
2564
- const project = await detectProject(targetPath);
2639
+ const project = await projectPromise;
2565
2640
  const score = calculateScore(diagnostics, context.files.length);
2566
2641
  const summary = buildSummary(diagnostics);
2567
2642
  const elapsedMs = node_perf_hooks.performance.now() - startTime;
@@ -2618,16 +2693,9 @@ async function scanMonorepo(targetPath, options = {}) {
2618
2693
  const { rules: customRules, warnings: customRuleWarnings } = await resolveCustomRules(rootConfig, targetPath);
2619
2694
  const combinedRules = mergeRules(allRules, customRules, customRuleWarnings);
2620
2695
  const filesByProject = await collectMonorepoFiles(targetPath, monorepo, rootConfig);
2621
- const subProjects = [];
2622
- const allDiagnostics = [];
2623
- const allRuleErrors = [];
2624
- const moduleGraphs = /* @__PURE__ */ new Map();
2625
- let totalFiles = 0;
2626
- for (const [name, files] of filesByProject) {
2627
- if (files.length === 0) continue;
2696
+ const subProjectEntries = await Promise.all([...filesByProject.entries()].filter(([, files]) => files.length > 0).map(async ([name, files]) => {
2628
2697
  const projectPath = (0, node_path.join)(targetPath, monorepo.projects.get(name));
2629
- const project = await detectProject(projectPath);
2630
- const projectConfig = await loadConfigWithFallback(projectPath, rootConfig);
2698
+ const [project, projectConfig] = await Promise.all([detectProject(projectPath), loadConfigWithFallback(projectPath, rootConfig)]);
2631
2699
  const astProject = createAstParser(files);
2632
2700
  const moduleGraph = buildModuleGraph(astProject, files);
2633
2701
  const providers = resolveProviders(astProject, files);
@@ -2643,26 +2711,39 @@ async function scanMonorepo(targetPath, options = {}) {
2643
2711
  ruleId: e.ruleId,
2644
2712
  error: formatRuleError(e.error)
2645
2713
  }));
2646
- const result = {
2647
- score,
2648
- diagnostics,
2649
- project: {
2650
- ...project,
2651
- fileCount: files.length,
2652
- moduleCount: moduleGraph.modules.size
2714
+ return {
2715
+ name,
2716
+ result: {
2717
+ score,
2718
+ diagnostics,
2719
+ project: {
2720
+ ...project,
2721
+ fileCount: files.length,
2722
+ moduleCount: moduleGraph.modules.size
2723
+ },
2724
+ summary,
2725
+ ruleErrors,
2726
+ elapsedMs: 0
2653
2727
  },
2654
- summary,
2655
- ruleErrors,
2656
- elapsedMs: 0
2728
+ moduleGraph,
2729
+ diagnostics,
2730
+ ruleErrors
2657
2731
  };
2732
+ }));
2733
+ const subProjects = [];
2734
+ const allDiagnostics = [];
2735
+ const allRuleErrors = [];
2736
+ const moduleGraphs = /* @__PURE__ */ new Map();
2737
+ let totalFiles = 0;
2738
+ for (const entry of subProjectEntries) {
2658
2739
  subProjects.push({
2659
- name,
2660
- result
2740
+ name: entry.name,
2741
+ result: entry.result
2661
2742
  });
2662
- moduleGraphs.set(name, moduleGraph);
2663
- allDiagnostics.push(...diagnostics);
2664
- allRuleErrors.push(...ruleErrors);
2665
- totalFiles += files.length;
2743
+ moduleGraphs.set(entry.name, entry.moduleGraph);
2744
+ allDiagnostics.push(...entry.diagnostics);
2745
+ allRuleErrors.push(...entry.ruleErrors);
2746
+ totalFiles += entry.result.project.fileCount;
2666
2747
  }
2667
2748
  const combinedScore = calculateScore(allDiagnostics, totalFiles);
2668
2749
  const combinedSummary = buildSummary(allDiagnostics);
@@ -2798,4 +2879,6 @@ exports.prepareScan = prepareScan;
2798
2879
  exports.scanAllFiles = scanAllFiles;
2799
2880
  exports.scanFile = scanFile;
2800
2881
  exports.scanProject = scanProject;
2801
- exports.updateFile = updateFile;
2882
+ exports.updateFile = updateFile;
2883
+ exports.updateModuleGraphForFile = updateModuleGraphForFile;
2884
+ exports.updateProvidersForFile = updateProvidersForFile;
@@ -8,6 +8,7 @@ interface ProviderInfo {
8
8
  name: string;
9
9
  publicMethodCount: number;
10
10
  }
11
+ declare function updateProvidersForFile(providers: Map<string, ProviderInfo>, project: Project, filePath: string): void;
11
12
  //#endregion
12
13
  //#region src/engine/module-graph.d.ts
13
14
  interface ModuleNode {
@@ -24,6 +25,7 @@ interface ModuleGraph {
24
25
  modules: Map<string, ModuleNode>;
25
26
  providerToModule: Map<string, ModuleNode>;
26
27
  }
28
+ declare function updateModuleGraphForFile(graph: ModuleGraph, project: Project, filePath: string): void;
27
29
  //#endregion
28
30
  //#region src/types/diagnostic.d.ts
29
31
  type Severity = "error" | "warning" | "info";
@@ -216,5 +218,5 @@ declare function diagnoseMonorepo(path: string, options?: {
216
218
  config?: string;
217
219
  }): Promise<MonorepoResult>;
218
220
  //#endregion
219
- export { type AnyRule, type Category, ConfigurationError, type DiagnoseResult, type DiagnoseSummary, type Diagnostic, type MonorepoResult, type NestjsDoctorConfig, NestjsDoctorError, type ProjectInfo, type ProjectRule, type ProjectRuleContext, type Rule, type RuleContext, type RuleErrorInfo, type RuleMeta, type ScanContext, ScanError, type Score, type Severity, type SubProjectResult, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile };
221
+ export { type AnyRule, type Category, ConfigurationError, type DiagnoseResult, type DiagnoseSummary, type Diagnostic, type MonorepoResult, type NestjsDoctorConfig, NestjsDoctorError, type ProjectInfo, type ProjectRule, type ProjectRuleContext, type Rule, type RuleContext, type RuleErrorInfo, type RuleMeta, type ScanContext, ScanError, type Score, type Severity, type SubProjectResult, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile, updateModuleGraphForFile, updateProvidersForFile };
220
222
  //# sourceMappingURL=index.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/engine/type-resolver.ts","../../src/engine/module-graph.ts","../../src/types/diagnostic.ts","../../src/types/config.ts","../../src/rules/types.ts","../../src/types/result.ts","../../src/core/scanner.ts","../../src/rules/index.ts","../../src/types/errors.ts","../../src/api/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.cts","names":[],"sources":["../../src/engine/type-resolver.ts","../../src/engine/module-graph.ts","../../src/types/diagnostic.ts","../../src/types/config.ts","../../src/rules/types.ts","../../src/types/result.ts","../../src/core/scanner.ts","../../src/rules/index.ts","../../src/types/errors.ts","../../src/api/index.ts"],"mappings":"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"}
@@ -8,6 +8,7 @@ interface ProviderInfo {
8
8
  name: string;
9
9
  publicMethodCount: number;
10
10
  }
11
+ declare function updateProvidersForFile(providers: Map<string, ProviderInfo>, project: Project, filePath: string): void;
11
12
  //#endregion
12
13
  //#region src/engine/module-graph.d.ts
13
14
  interface ModuleNode {
@@ -24,6 +25,7 @@ interface ModuleGraph {
24
25
  modules: Map<string, ModuleNode>;
25
26
  providerToModule: Map<string, ModuleNode>;
26
27
  }
28
+ declare function updateModuleGraphForFile(graph: ModuleGraph, project: Project, filePath: string): void;
27
29
  //#endregion
28
30
  //#region src/types/diagnostic.d.ts
29
31
  type Severity = "error" | "warning" | "info";
@@ -216,5 +218,5 @@ declare function diagnoseMonorepo(path: string, options?: {
216
218
  config?: string;
217
219
  }): Promise<MonorepoResult>;
218
220
  //#endregion
219
- export { type AnyRule, type Category, ConfigurationError, type DiagnoseResult, type DiagnoseSummary, type Diagnostic, type MonorepoResult, type NestjsDoctorConfig, NestjsDoctorError, type ProjectInfo, type ProjectRule, type ProjectRuleContext, type Rule, type RuleContext, type RuleErrorInfo, type RuleMeta, type ScanContext, ScanError, type Score, type Severity, type SubProjectResult, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile };
221
+ export { type AnyRule, type Category, ConfigurationError, type DiagnoseResult, type DiagnoseSummary, type Diagnostic, type MonorepoResult, type NestjsDoctorConfig, NestjsDoctorError, type ProjectInfo, type ProjectRule, type ProjectRuleContext, type Rule, type RuleContext, type RuleErrorInfo, type RuleMeta, type ScanContext, ScanError, type Score, type Severity, type SubProjectResult, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile, updateModuleGraphForFile, updateProvidersForFile };
220
222
  //# sourceMappingURL=index.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/engine/type-resolver.ts","../../src/engine/module-graph.ts","../../src/types/diagnostic.ts","../../src/types/config.ts","../../src/rules/types.ts","../../src/types/result.ts","../../src/core/scanner.ts","../../src/rules/index.ts","../../src/types/errors.ts","../../src/api/index.ts"],"mappings":"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"}
1
+ {"version":3,"file":"index.d.mts","names":[],"sources":["../../src/engine/type-resolver.ts","../../src/engine/module-graph.ts","../../src/types/diagnostic.ts","../../src/types/config.ts","../../src/rules/types.ts","../../src/types/result.ts","../../src/core/scanner.ts","../../src/rules/index.ts","../../src/types/errors.ts","../../src/api/index.ts"],"mappings":"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"}
@@ -85,6 +85,55 @@ function extractArrayPropertyNames(obj, propertyName) {
85
85
  return text;
86
86
  });
87
87
  }
88
+ function updateModuleGraphForFile(graph, project, filePath) {
89
+ for (const [name, node] of graph.modules) if (node.filePath === filePath) {
90
+ graph.modules.delete(name);
91
+ graph.edges.delete(name);
92
+ for (const provider of node.providers) if (graph.providerToModule.get(provider) === node) graph.providerToModule.delete(provider);
93
+ for (const edgeSet of graph.edges.values()) edgeSet.delete(name);
94
+ }
95
+ const sourceFile = project.getSourceFile(filePath);
96
+ if (!sourceFile) return;
97
+ const newModules = [];
98
+ for (const cls of sourceFile.getClasses()) {
99
+ const moduleDecorator = cls.getDecorator("Module");
100
+ if (!moduleDecorator) continue;
101
+ const name = cls.getName() ?? "AnonymousModule";
102
+ const args = moduleDecorator.getArguments()[0];
103
+ const node = {
104
+ name,
105
+ filePath,
106
+ classDeclaration: cls,
107
+ imports: [],
108
+ exports: [],
109
+ providers: [],
110
+ controllers: []
111
+ };
112
+ if (args && args.getKind() === SyntaxKind.ObjectLiteralExpression) {
113
+ const obj = args.asKind(SyntaxKind.ObjectLiteralExpression);
114
+ if (obj) {
115
+ node.imports = extractArrayPropertyNames(obj, "imports");
116
+ node.exports = extractArrayPropertyNames(obj, "exports");
117
+ node.providers = extractArrayPropertyNames(obj, "providers");
118
+ node.controllers = extractArrayPropertyNames(obj, "controllers");
119
+ }
120
+ }
121
+ graph.modules.set(name, node);
122
+ newModules.push(node);
123
+ }
124
+ for (const node of newModules) {
125
+ const importSet = /* @__PURE__ */ new Set();
126
+ for (const imp of node.imports) if (graph.modules.has(imp)) importSet.add(imp);
127
+ graph.edges.set(node.name, importSet);
128
+ for (const provider of node.providers) graph.providerToModule.set(provider, node);
129
+ }
130
+ for (const [name, node] of graph.modules) {
131
+ if (node.filePath === filePath) continue;
132
+ const importSet = /* @__PURE__ */ new Set();
133
+ for (const imp of node.imports) if (graph.modules.has(imp)) importSet.add(imp);
134
+ graph.edges.set(name, importSet);
135
+ }
136
+ }
88
137
  function findCircularDeps(graph) {
89
138
  const cycles = [];
90
139
  const visited = /* @__PURE__ */ new Set();
@@ -292,6 +341,32 @@ function resolveProviders(project, files) {
292
341
  }
293
342
  return providers;
294
343
  }
344
+ function updateProvidersForFile(providers, project, filePath) {
345
+ for (const [name, info] of providers) if (info.filePath === filePath) providers.delete(name);
346
+ const sourceFile = project.getSourceFile(filePath);
347
+ if (!sourceFile) return;
348
+ for (const cls of sourceFile.getClasses()) {
349
+ if (!cls.getDecorator("Injectable")) continue;
350
+ const name = cls.getName();
351
+ if (!name) continue;
352
+ const ctor = cls.getConstructors()[0];
353
+ const dependencies = ctor ? ctor.getParameters().map((p) => {
354
+ const typeNode = p.getTypeNode();
355
+ return extractSimpleTypeName(typeNode ? typeNode.getText() : p.getType().getText());
356
+ }) : [];
357
+ const publicMethodCount = cls.getMethods().filter((m) => {
358
+ const scope = m.getScope();
359
+ return !scope || scope === "public";
360
+ }).length;
361
+ providers.set(name, {
362
+ name,
363
+ filePath,
364
+ classDeclaration: cls,
365
+ dependencies,
366
+ publicMethodCount
367
+ });
368
+ }
369
+ }
295
370
  function extractSimpleTypeName(typeText) {
296
371
  const importMatch = typeText.match(IMPORT_TYPE_REGEX);
297
372
  if (importMatch) return importMatch[1];
@@ -2236,11 +2311,11 @@ async function collectFiles(targetPath, config = {}) {
2236
2311
  })).sort();
2237
2312
  }
2238
2313
  async function collectMonorepoFiles(targetPath, monorepo, config = {}) {
2314
+ const entries = await Promise.all([...monorepo.projects.entries()].map(async ([name, root]) => {
2315
+ return [name, await collectFiles(join(targetPath, root), config)];
2316
+ }));
2239
2317
  const result = /* @__PURE__ */ new Map();
2240
- for (const [name, root] of monorepo.projects) {
2241
- const files = await collectFiles(join(targetPath, root), config);
2242
- result.set(name, files);
2243
- }
2318
+ for (const [name, files] of entries) result.set(name, files);
2244
2319
  return result;
2245
2320
  }
2246
2321
 
@@ -2461,9 +2536,8 @@ function formatRuleError(error) {
2461
2536
  }
2462
2537
  async function prepareScan(targetPath, options = {}) {
2463
2538
  const config = await loadConfig(targetPath, options.config);
2464
- const { rules: customRules, warnings: customRuleWarnings } = await resolveCustomRules(config, targetPath);
2539
+ const [{ rules: customRules, warnings: customRuleWarnings }, files] = await Promise.all([resolveCustomRules(config, targetPath), collectFiles(targetPath, config)]);
2465
2540
  const combinedRules = mergeRules(allRules, customRules, customRuleWarnings);
2466
- const files = await collectFiles(targetPath, config);
2467
2541
  const astProject = createAstParser(files);
2468
2542
  const moduleGraph = buildModuleGraph(astProject, files);
2469
2543
  const providers = resolveProviders(astProject, files);
@@ -2487,8 +2561,8 @@ function updateFile(context, filePath) {
2487
2561
  if (existing) context.astProject.removeSourceFile(existing);
2488
2562
  context.astProject.addSourceFileAtPath(filePath);
2489
2563
  if (!context.files.includes(filePath)) context.files.push(filePath);
2490
- context.moduleGraph = buildModuleGraph(context.astProject, context.files);
2491
- context.providers = resolveProviders(context.astProject, context.files);
2564
+ updateModuleGraphForFile(context.moduleGraph, context.astProject, filePath);
2565
+ updateProvidersForFile(context.providers, context.astProject, filePath);
2492
2566
  }
2493
2567
  function scanFile(context, filePath) {
2494
2568
  const { diagnostics: rawDiagnostics, errors } = runFileRules(context.astProject, [filePath], context.fileRules);
@@ -2528,11 +2602,12 @@ function scanProject(context) {
2528
2602
  async function scan(targetPath, options = {}) {
2529
2603
  const startTime = performance.now();
2530
2604
  const { context, customRuleWarnings } = await prepareScan(targetPath, options);
2605
+ const projectPromise = detectProject(targetPath);
2531
2606
  const fileResult = scanAllFiles(context);
2532
2607
  const projectResult = scanProject(context);
2533
2608
  const diagnostics = [...fileResult.diagnostics, ...projectResult.diagnostics];
2534
2609
  const ruleErrors = [...fileResult.errors, ...projectResult.errors];
2535
- const project = await detectProject(targetPath);
2610
+ const project = await projectPromise;
2536
2611
  const score = calculateScore(diagnostics, context.files.length);
2537
2612
  const summary = buildSummary(diagnostics);
2538
2613
  const elapsedMs = performance.now() - startTime;
@@ -2589,16 +2664,9 @@ async function scanMonorepo(targetPath, options = {}) {
2589
2664
  const { rules: customRules, warnings: customRuleWarnings } = await resolveCustomRules(rootConfig, targetPath);
2590
2665
  const combinedRules = mergeRules(allRules, customRules, customRuleWarnings);
2591
2666
  const filesByProject = await collectMonorepoFiles(targetPath, monorepo, rootConfig);
2592
- const subProjects = [];
2593
- const allDiagnostics = [];
2594
- const allRuleErrors = [];
2595
- const moduleGraphs = /* @__PURE__ */ new Map();
2596
- let totalFiles = 0;
2597
- for (const [name, files] of filesByProject) {
2598
- if (files.length === 0) continue;
2667
+ const subProjectEntries = await Promise.all([...filesByProject.entries()].filter(([, files]) => files.length > 0).map(async ([name, files]) => {
2599
2668
  const projectPath = join(targetPath, monorepo.projects.get(name));
2600
- const project = await detectProject(projectPath);
2601
- const projectConfig = await loadConfigWithFallback(projectPath, rootConfig);
2669
+ const [project, projectConfig] = await Promise.all([detectProject(projectPath), loadConfigWithFallback(projectPath, rootConfig)]);
2602
2670
  const astProject = createAstParser(files);
2603
2671
  const moduleGraph = buildModuleGraph(astProject, files);
2604
2672
  const providers = resolveProviders(astProject, files);
@@ -2614,26 +2682,39 @@ async function scanMonorepo(targetPath, options = {}) {
2614
2682
  ruleId: e.ruleId,
2615
2683
  error: formatRuleError(e.error)
2616
2684
  }));
2617
- const result = {
2618
- score,
2619
- diagnostics,
2620
- project: {
2621
- ...project,
2622
- fileCount: files.length,
2623
- moduleCount: moduleGraph.modules.size
2685
+ return {
2686
+ name,
2687
+ result: {
2688
+ score,
2689
+ diagnostics,
2690
+ project: {
2691
+ ...project,
2692
+ fileCount: files.length,
2693
+ moduleCount: moduleGraph.modules.size
2694
+ },
2695
+ summary,
2696
+ ruleErrors,
2697
+ elapsedMs: 0
2624
2698
  },
2625
- summary,
2626
- ruleErrors,
2627
- elapsedMs: 0
2699
+ moduleGraph,
2700
+ diagnostics,
2701
+ ruleErrors
2628
2702
  };
2703
+ }));
2704
+ const subProjects = [];
2705
+ const allDiagnostics = [];
2706
+ const allRuleErrors = [];
2707
+ const moduleGraphs = /* @__PURE__ */ new Map();
2708
+ let totalFiles = 0;
2709
+ for (const entry of subProjectEntries) {
2629
2710
  subProjects.push({
2630
- name,
2631
- result
2711
+ name: entry.name,
2712
+ result: entry.result
2632
2713
  });
2633
- moduleGraphs.set(name, moduleGraph);
2634
- allDiagnostics.push(...diagnostics);
2635
- allRuleErrors.push(...ruleErrors);
2636
- totalFiles += files.length;
2714
+ moduleGraphs.set(entry.name, entry.moduleGraph);
2715
+ allDiagnostics.push(...entry.diagnostics);
2716
+ allRuleErrors.push(...entry.ruleErrors);
2717
+ totalFiles += entry.result.project.fileCount;
2637
2718
  }
2638
2719
  const combinedScore = calculateScore(allDiagnostics, totalFiles);
2639
2720
  const combinedSummary = buildSummary(allDiagnostics);
@@ -2758,5 +2839,5 @@ async function diagnoseMonorepo(path, options = {}) {
2758
2839
  }
2759
2840
 
2760
2841
  //#endregion
2761
- export { ConfigurationError, NestjsDoctorError, ScanError, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile };
2842
+ export { ConfigurationError, NestjsDoctorError, ScanError, ValidationError, diagnose, diagnoseMonorepo, getRules, prepareScan, scanAllFiles, scanFile, scanProject, updateFile, updateModuleGraphForFile, updateProvidersForFile };
2762
2843
  //# sourceMappingURL=index.mjs.map