@mf-toolkit/shared-inspector 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/README.md +254 -0
- package/dist/analyzer/analyze-project.d.ts +9 -0
- package/dist/analyzer/analyze-project.d.ts.map +1 -0
- package/dist/analyzer/analyze-project.js +38 -0
- package/dist/analyzer/analyze-project.js.map +1 -0
- package/dist/analyzer/detect-issues.d.ts +33 -0
- package/dist/analyzer/detect-issues.d.ts.map +1 -0
- package/dist/analyzer/detect-issues.js +69 -0
- package/dist/analyzer/detect-issues.js.map +1 -0
- package/dist/analyzer/policy.d.ts +27 -0
- package/dist/analyzer/policy.d.ts.map +1 -0
- package/dist/analyzer/policy.js +84 -0
- package/dist/analyzer/policy.js.map +1 -0
- package/dist/collector/build-project-manifest.d.ts +10 -0
- package/dist/collector/build-project-manifest.d.ts.map +1 -0
- package/dist/collector/build-project-manifest.js +82 -0
- package/dist/collector/build-project-manifest.js.map +1 -0
- package/dist/collector/collect-imports.d.ts +17 -0
- package/dist/collector/collect-imports.d.ts.map +1 -0
- package/dist/collector/collect-imports.js +87 -0
- package/dist/collector/collect-imports.js.map +1 -0
- package/dist/collector/parse-declarations.d.ts +26 -0
- package/dist/collector/parse-declarations.d.ts.map +1 -0
- package/dist/collector/parse-declarations.js +134 -0
- package/dist/collector/parse-declarations.js.map +1 -0
- package/dist/collector/parse-shared-config.d.ts +12 -0
- package/dist/collector/parse-shared-config.d.ts.map +1 -0
- package/dist/collector/parse-shared-config.js +56 -0
- package/dist/collector/parse-shared-config.js.map +1 -0
- package/dist/collector/resolve-tsconfig-paths.d.ts +39 -0
- package/dist/collector/resolve-tsconfig-paths.d.ts.map +1 -0
- package/dist/collector/resolve-tsconfig-paths.js +89 -0
- package/dist/collector/resolve-tsconfig-paths.js.map +1 -0
- package/dist/collector/resolve-versions.d.ts +15 -0
- package/dist/collector/resolve-versions.d.ts.map +1 -0
- package/dist/collector/resolve-versions.js +49 -0
- package/dist/collector/resolve-versions.js.map +1 -0
- package/dist/collector/traverse-local-modules.d.ts +27 -0
- package/dist/collector/traverse-local-modules.d.ts.map +1 -0
- package/dist/collector/traverse-local-modules.js +119 -0
- package/dist/collector/traverse-local-modules.js.map +1 -0
- package/dist/index.d.ts +7 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +9 -0
- package/dist/index.js.map +1 -0
- package/dist/inspect.d.ts +12 -0
- package/dist/inspect.d.ts.map +1 -0
- package/dist/inspect.js +15 -0
- package/dist/inspect.js.map +1 -0
- package/dist/plugins/webpack.d.ts +40 -0
- package/dist/plugins/webpack.d.ts.map +1 -0
- package/dist/plugins/webpack.js +95 -0
- package/dist/plugins/webpack.js.map +1 -0
- package/dist/reporter/format-report.d.ts +18 -0
- package/dist/reporter/format-report.d.ts.map +1 -0
- package/dist/reporter/format-report.js +87 -0
- package/dist/reporter/format-report.js.map +1 -0
- package/dist/reporter/write-report.d.ts +12 -0
- package/dist/reporter/write-report.d.ts.map +1 -0
- package/dist/reporter/write-report.js +19 -0
- package/dist/reporter/write-report.js.map +1 -0
- package/dist/types.d.ts +179 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/dist/webpack.d.ts +3 -0
- package/dist/webpack.d.ts.map +1 -0
- package/dist/webpack.js +2 -0
- package/dist/webpack.js.map +1 -0
- package/package.json +55 -0
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { resolve, dirname, join } from 'node:path';
|
|
3
|
+
import { scanFiles } from './collect-imports.js';
|
|
4
|
+
import { parseDeclarations, isRelativeSpecifier, isNodeBuiltin, normalizePackageName, } from './parse-declarations.js';
|
|
5
|
+
import { loadTsConfigPaths, resolveAliasedSpecifier, } from './resolve-tsconfig-paths.js';
|
|
6
|
+
const DEFAULT_EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx'];
|
|
7
|
+
/**
|
|
8
|
+
* Local-graph mode collector.
|
|
9
|
+
*
|
|
10
|
+
* Scans all files in sourceDirs and follows relative import/export chains
|
|
11
|
+
* recursively within those directories. Finds external packages reachable
|
|
12
|
+
* through barrel re-exports and local module wrappers.
|
|
13
|
+
*
|
|
14
|
+
* When tsconfigPath is provided, TypeScript path aliases (e.g. '@app/*') are
|
|
15
|
+
* resolved to local files and followed in the same DFS — packages behind
|
|
16
|
+
* aliases become visible.
|
|
17
|
+
*
|
|
18
|
+
* Uses two-phase approach:
|
|
19
|
+
* Phase 1 — parallel async reads of all source files into contentMap
|
|
20
|
+
* Phase 2 — synchronous DFS over in-memory content (zero disk I/O)
|
|
21
|
+
*/
|
|
22
|
+
export async function traverseLocalModules(options) {
|
|
23
|
+
const extensions = options.extensions ?? DEFAULT_EXTENSIONS;
|
|
24
|
+
const files = await scanFiles(options.sourceDirs, extensions);
|
|
25
|
+
// Phase 1: pre-read all files in parallel — turns F sequential disk reads
|
|
26
|
+
// into a single concurrent batch, giving 3-8× speedup on large projects.
|
|
27
|
+
const contentMap = new Map();
|
|
28
|
+
await Promise.all(files.map(async (filePath) => {
|
|
29
|
+
try {
|
|
30
|
+
contentMap.set(filePath, await readFile(filePath, 'utf-8'));
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
// Unreadable files are skipped silently during DFS
|
|
34
|
+
}
|
|
35
|
+
}));
|
|
36
|
+
// Load tsconfig path aliases once, before DFS
|
|
37
|
+
const tsConfigPaths = options.tsconfigPath
|
|
38
|
+
? loadTsConfigPaths(options.tsconfigPath)
|
|
39
|
+
: null;
|
|
40
|
+
const visited = new Set();
|
|
41
|
+
/** package → { files observed in, via: direct | reexport } */
|
|
42
|
+
const pkgMap = new Map();
|
|
43
|
+
// Phase 2: DFS over in-memory content — no disk I/O during traversal.
|
|
44
|
+
function visit(filePath) {
|
|
45
|
+
if (visited.has(filePath))
|
|
46
|
+
return;
|
|
47
|
+
visited.add(filePath);
|
|
48
|
+
const content = contentMap.get(filePath);
|
|
49
|
+
if (content === undefined)
|
|
50
|
+
return;
|
|
51
|
+
for (const decl of parseDeclarations(content)) {
|
|
52
|
+
// ── Relative import → follow locally ──────────────────────────────────
|
|
53
|
+
if (isRelativeSpecifier(decl.specifier)) {
|
|
54
|
+
const resolved = resolveLocalFile(decl.specifier, filePath, contentMap);
|
|
55
|
+
if (resolved)
|
|
56
|
+
visit(resolved);
|
|
57
|
+
continue;
|
|
58
|
+
}
|
|
59
|
+
if (isNodeBuiltin(decl.specifier))
|
|
60
|
+
continue;
|
|
61
|
+
// ── TypeScript path alias → resolve and follow locally ────────────────
|
|
62
|
+
if (tsConfigPaths) {
|
|
63
|
+
const aliased = resolveAliasedSpecifier(decl.specifier, tsConfigPaths, contentMap);
|
|
64
|
+
if (aliased) {
|
|
65
|
+
visit(aliased);
|
|
66
|
+
continue;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
// ── External package ──────────────────────────────────────────────────
|
|
70
|
+
const pkg = normalizePackageName(decl.specifier);
|
|
71
|
+
if (options.ignore?.some((p) => matchesIgnorePattern(pkg, p)))
|
|
72
|
+
continue;
|
|
73
|
+
if (options.workspacePackages?.some((p) => matchesIgnorePattern(pkg, p)))
|
|
74
|
+
continue;
|
|
75
|
+
const via = decl.kind === 'reexport' ? 'reexport' : 'direct';
|
|
76
|
+
const existing = pkgMap.get(pkg);
|
|
77
|
+
if (!existing) {
|
|
78
|
+
pkgMap.set(pkg, { files: new Set([filePath]), via });
|
|
79
|
+
}
|
|
80
|
+
else {
|
|
81
|
+
existing.files.add(filePath);
|
|
82
|
+
// Direct import takes precedence: once seen as direct, stays direct
|
|
83
|
+
if (via === 'direct')
|
|
84
|
+
existing.via = 'direct';
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
for (const file of files) {
|
|
89
|
+
visit(file);
|
|
90
|
+
}
|
|
91
|
+
// One PackageOccurrence per (package, file) pair — consistent with collectImports
|
|
92
|
+
return Array.from(pkgMap.entries()).flatMap(([pkg, { files: fileSet, via }]) => [...fileSet].map((file) => ({ package: pkg, file, via })));
|
|
93
|
+
}
|
|
94
|
+
// ─── Local file resolver ──────────────────────────────────────────────────────
|
|
95
|
+
/**
|
|
96
|
+
* Resolves a relative specifier to an absolute file path.
|
|
97
|
+
* Uses the pre-built contentMap (Map lookup) instead of existsSync —
|
|
98
|
+
* zero disk I/O during DFS traversal.
|
|
99
|
+
*/
|
|
100
|
+
function resolveLocalFile(specifier, fromFile, contentMap) {
|
|
101
|
+
const base = resolve(dirname(fromFile), specifier);
|
|
102
|
+
for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
|
|
103
|
+
const candidate = base + ext;
|
|
104
|
+
if (contentMap.has(candidate))
|
|
105
|
+
return candidate;
|
|
106
|
+
}
|
|
107
|
+
for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
|
|
108
|
+
const candidate = join(base, 'index' + ext);
|
|
109
|
+
if (contentMap.has(candidate))
|
|
110
|
+
return candidate;
|
|
111
|
+
}
|
|
112
|
+
return null;
|
|
113
|
+
}
|
|
114
|
+
function matchesIgnorePattern(pkg, pattern) {
|
|
115
|
+
if (pattern.endsWith('/*'))
|
|
116
|
+
return pkg.startsWith(pattern.slice(0, -2) + '/');
|
|
117
|
+
return pkg === pattern;
|
|
118
|
+
}
|
|
119
|
+
//# sourceMappingURL=traverse-local-modules.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"traverse-local-modules.js","sourceRoot":"","sources":["../../src/collector/traverse-local-modules.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { buildProjectManifest } from './collector/build-project-manifest.js';
|
|
2
|
+
export { analyzeProject } from './analyzer/analyze-project.js';
|
|
3
|
+
export { inspect } from './inspect.js';
|
|
4
|
+
export { formatReport } from './reporter/format-report.js';
|
|
5
|
+
export { writeReport, writeManifest } from './reporter/write-report.js';
|
|
6
|
+
export type { ProjectManifest, ProjectReport, CollectorOptions, AnalysisOptions, SharedDepConfig, PackageOccurrence, UnusedEntry, CandidateEntry, MismatchedEntry, SingletonRiskEntry, } from './types.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAG/D,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAGvC,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAGxE,YAAY,EACV,eAAe,EACf,aAAa,EACb,gBAAgB,EAChB,eAAe,EACf,eAAe,EACf,iBAAiB,EACjB,WAAW,EACX,cAAc,EACd,eAAe,EACf,kBAAkB,GACnB,MAAM,YAAY,CAAC"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// ─── Two-phase API ────────────────────────────────────────────────────────────
|
|
2
|
+
export { buildProjectManifest } from './collector/build-project-manifest.js';
|
|
3
|
+
export { analyzeProject } from './analyzer/analyze-project.js';
|
|
4
|
+
// ─── Shortcut API ─────────────────────────────────────────────────────────────
|
|
5
|
+
export { inspect } from './inspect.js';
|
|
6
|
+
// ─── Reporter ─────────────────────────────────────────────────────────────────
|
|
7
|
+
export { formatReport } from './reporter/format-report.js';
|
|
8
|
+
export { writeReport, writeManifest } from './reporter/write-report.js';
|
|
9
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,iFAAiF;AACjF,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D,iFAAiF;AACjF,OAAO,EAAE,OAAO,EAAE,MAAM,cAAc,CAAC;AAEvC,iFAAiF;AACjF,OAAO,EAAE,YAAY,EAAE,MAAM,6BAA6B,CAAC;AAC3D,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,4BAA4B,CAAC"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { CollectorOptions, AnalysisOptions, ProjectReport } from './types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Shortcut API — combines buildProjectManifest() + analyzeProject() in one call.
|
|
4
|
+
*
|
|
5
|
+
* Use this when you only need the report and don't need the intermediate manifest.
|
|
6
|
+
* For CI pipelines or multi-project federation analysis, use the two-phase API
|
|
7
|
+
* directly so you can persist and share the manifest.
|
|
8
|
+
*/
|
|
9
|
+
export declare function inspect(options: CollectorOptions & {
|
|
10
|
+
analysis?: AnalysisOptions;
|
|
11
|
+
}): Promise<ProjectReport>;
|
|
12
|
+
//# sourceMappingURL=inspect.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.d.ts","sourceRoot":"","sources":["../src/inspect.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAInF;;;;;;GAMG;AACH,wBAAsB,OAAO,CAC3B,OAAO,EAAE,gBAAgB,GAAG;IAAE,QAAQ,CAAC,EAAE,eAAe,CAAA;CAAE,GACzD,OAAO,CAAC,aAAa,CAAC,CAIxB"}
|
package/dist/inspect.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { buildProjectManifest } from './collector/build-project-manifest.js';
|
|
2
|
+
import { analyzeProject } from './analyzer/analyze-project.js';
|
|
3
|
+
/**
|
|
4
|
+
* Shortcut API — combines buildProjectManifest() + analyzeProject() in one call.
|
|
5
|
+
*
|
|
6
|
+
* Use this when you only need the report and don't need the intermediate manifest.
|
|
7
|
+
* For CI pipelines or multi-project federation analysis, use the two-phase API
|
|
8
|
+
* directly so you can persist and share the manifest.
|
|
9
|
+
*/
|
|
10
|
+
export async function inspect(options) {
|
|
11
|
+
const { analysis, ...collectorOptions } = options;
|
|
12
|
+
const manifest = await buildProjectManifest(collectorOptions);
|
|
13
|
+
return analyzeProject(manifest, analysis);
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=inspect.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inspect.js","sourceRoot":"","sources":["../src/inspect.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,oBAAoB,EAAE,MAAM,uCAAuC,CAAC;AAC7E,OAAO,EAAE,cAAc,EAAE,MAAM,+BAA+B,CAAC;AAE/D;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,OAA0D;IAE1D,MAAM,EAAE,QAAQ,EAAE,GAAG,gBAAgB,EAAE,GAAG,OAAO,CAAC;IAClD,MAAM,QAAQ,GAAG,MAAM,oBAAoB,CAAC,gBAAgB,CAAC,CAAC;IAC9D,OAAO,cAAc,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;AAC5C,CAAC"}
|
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
import type { WebpackPluginOptions } from '../types.js';
|
|
2
|
+
interface WebpackCompilation {
|
|
3
|
+
errors: Error[];
|
|
4
|
+
warnings: Error[];
|
|
5
|
+
}
|
|
6
|
+
interface WebpackCompiler {
|
|
7
|
+
context: string;
|
|
8
|
+
options: {
|
|
9
|
+
name?: string;
|
|
10
|
+
};
|
|
11
|
+
hooks: {
|
|
12
|
+
afterCompile: {
|
|
13
|
+
tapPromise(name: string, fn: (compilation: WebpackCompilation) => Promise<void>): void;
|
|
14
|
+
};
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Webpack plugin that analyses Module Federation shared dependencies after
|
|
19
|
+
* each compilation and reports issues to the console and/or build output.
|
|
20
|
+
*
|
|
21
|
+
* In v0.1, `sharedConfig` must be provided explicitly. Auto-extraction from
|
|
22
|
+
* ModuleFederationPlugin is planned for v0.1.1.
|
|
23
|
+
*
|
|
24
|
+
* @example
|
|
25
|
+
* ```js
|
|
26
|
+
* new MfSharedInspectorPlugin({
|
|
27
|
+
* sourceDirs: ['./src'],
|
|
28
|
+
* sharedConfig: { react: { singleton: true }, mobx: { singleton: true } },
|
|
29
|
+
* warn: true,
|
|
30
|
+
* writeManifest: true,
|
|
31
|
+
* })
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class MfSharedInspectorPlugin {
|
|
35
|
+
private options;
|
|
36
|
+
constructor(options: WebpackPluginOptions);
|
|
37
|
+
apply(compiler: WebpackCompiler): void;
|
|
38
|
+
}
|
|
39
|
+
export {};
|
|
40
|
+
//# sourceMappingURL=webpack.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webpack.d.ts","sourceRoot":"","sources":["../../src/plugins/webpack.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AASxD,UAAU,kBAAkB;IAC1B,MAAM,EAAE,KAAK,EAAE,CAAC;IAChB,QAAQ,EAAE,KAAK,EAAE,CAAC;CACnB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE;QACP,IAAI,CAAC,EAAE,MAAM,CAAC;KACf,CAAC;IACF,KAAK,EAAE;QACL,YAAY,EAAE;YACZ,UAAU,CACR,IAAI,EAAE,MAAM,EACZ,EAAE,EAAE,CAAC,WAAW,EAAE,kBAAkB,KAAK,OAAO,CAAC,IAAI,CAAC,GACrD,IAAI,CAAC;SACT,CAAC;KACH,CAAC;CACH;AAMD;;;;;;;;;;;;;;;;GAgBG;AACH,qBAAa,uBAAuB;IAClC,OAAO,CAAC,OAAO,CAAuB;gBAE1B,OAAO,EAAE,oBAAoB;IAIzC,KAAK,CAAC,QAAQ,EAAE,eAAe,GAAG,IAAI;CAyFvC"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { isAbsolute, join, basename } from 'node:path';
|
|
2
|
+
import { buildProjectManifest } from '../collector/build-project-manifest.js';
|
|
3
|
+
import { analyzeProject } from '../analyzer/analyze-project.js';
|
|
4
|
+
import { formatReport } from '../reporter/format-report.js';
|
|
5
|
+
import { writeManifest } from '../reporter/write-report.js';
|
|
6
|
+
// ─────────────────────────────────────────────────────────────────────────────
|
|
7
|
+
const PLUGIN_NAME = 'MfSharedInspectorPlugin';
|
|
8
|
+
/**
|
|
9
|
+
* Webpack plugin that analyses Module Federation shared dependencies after
|
|
10
|
+
* each compilation and reports issues to the console and/or build output.
|
|
11
|
+
*
|
|
12
|
+
* In v0.1, `sharedConfig` must be provided explicitly. Auto-extraction from
|
|
13
|
+
* ModuleFederationPlugin is planned for v0.1.1.
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* ```js
|
|
17
|
+
* new MfSharedInspectorPlugin({
|
|
18
|
+
* sourceDirs: ['./src'],
|
|
19
|
+
* sharedConfig: { react: { singleton: true }, mobx: { singleton: true } },
|
|
20
|
+
* warn: true,
|
|
21
|
+
* writeManifest: true,
|
|
22
|
+
* })
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export class MfSharedInspectorPlugin {
|
|
26
|
+
options;
|
|
27
|
+
constructor(options) {
|
|
28
|
+
this.options = options;
|
|
29
|
+
}
|
|
30
|
+
apply(compiler) {
|
|
31
|
+
compiler.hooks.afterCompile.tapPromise(PLUGIN_NAME, async (compilation) => {
|
|
32
|
+
const { sourceDirs, depth = 'local-graph', sharedConfig, kind, packageJsonPath, extensions, ignore, parser, analysis, warn = true, failOn, writeManifest: shouldWriteManifest = false, outputDir = '.', } = this.options;
|
|
33
|
+
// Resolve name from webpack compiler, fallback to context dir name
|
|
34
|
+
const name = compiler.options.name ?? basename(compiler.context);
|
|
35
|
+
// Resolve paths relative to compiler.context when not absolute
|
|
36
|
+
const resolvedPkgJson = packageJsonPath
|
|
37
|
+
? (isAbsolute(packageJsonPath) ? packageJsonPath : join(compiler.context, packageJsonPath))
|
|
38
|
+
: join(compiler.context, 'package.json');
|
|
39
|
+
const resolvedSourceDirs = sourceDirs.map((dir) => isAbsolute(dir) ? dir : join(compiler.context, dir));
|
|
40
|
+
const resolvedOutputDir = isAbsolute(outputDir)
|
|
41
|
+
? outputDir
|
|
42
|
+
: join(compiler.context, outputDir);
|
|
43
|
+
try {
|
|
44
|
+
const manifest = await buildProjectManifest({
|
|
45
|
+
name,
|
|
46
|
+
sourceDirs: resolvedSourceDirs,
|
|
47
|
+
depth,
|
|
48
|
+
sharedConfig,
|
|
49
|
+
kind,
|
|
50
|
+
packageJsonPath: resolvedPkgJson,
|
|
51
|
+
extensions,
|
|
52
|
+
ignore,
|
|
53
|
+
parser,
|
|
54
|
+
});
|
|
55
|
+
const report = analyzeProject(manifest, analysis);
|
|
56
|
+
const hasFindings = report.mismatched.length > 0 ||
|
|
57
|
+
report.unused.length > 0 ||
|
|
58
|
+
report.candidates.length > 0 ||
|
|
59
|
+
report.singletonRisks.length > 0;
|
|
60
|
+
if (warn && hasFindings) {
|
|
61
|
+
console.warn(formatReport(report, {
|
|
62
|
+
name: manifest.project.name,
|
|
63
|
+
depth: manifest.source.depth,
|
|
64
|
+
filesScanned: manifest.source.filesScanned,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
if (shouldWriteManifest) {
|
|
68
|
+
await writeManifest(manifest, join(resolvedOutputDir, 'project-manifest.json'));
|
|
69
|
+
}
|
|
70
|
+
if (failOn && shouldFailBuild(failOn, report)) {
|
|
71
|
+
const msg = `[${PLUGIN_NAME}] Build failed (failOn: "${failOn}"): ` +
|
|
72
|
+
`${report.mismatched.length} mismatch, ${report.unused.length} unused, ` +
|
|
73
|
+
`${report.candidates.length} candidates, ${report.singletonRisks.length} singleton risks.`;
|
|
74
|
+
compilation.errors.push(new Error(msg));
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
catch (err) {
|
|
78
|
+
// Analysis errors are non-fatal — warn but don't break the build
|
|
79
|
+
compilation.warnings.push(new Error(`[${PLUGIN_NAME}] Analysis failed: ${err instanceof Error ? err.message : String(err)}`));
|
|
80
|
+
}
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
85
|
+
function shouldFailBuild(failOn, report) {
|
|
86
|
+
switch (failOn) {
|
|
87
|
+
case 'mismatch': return report.mismatched.length > 0;
|
|
88
|
+
case 'unused': return report.unused.length > 0;
|
|
89
|
+
case 'any': return (report.mismatched.length > 0 ||
|
|
90
|
+
report.unused.length > 0 ||
|
|
91
|
+
report.candidates.length > 0 ||
|
|
92
|
+
report.singletonRisks.length > 0);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=webpack.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"webpack.js","sourceRoot":"","sources":["../../src/plugins/webpack.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProjectReport } from '../types.js';
|
|
2
|
+
export interface FormatReportContext {
|
|
3
|
+
name?: string;
|
|
4
|
+
depth?: 'direct' | 'local-graph';
|
|
5
|
+
filesScanned?: number;
|
|
6
|
+
}
|
|
7
|
+
/**
|
|
8
|
+
* Formats a ProjectReport as a human-readable terminal string.
|
|
9
|
+
*
|
|
10
|
+
* Section order (by severity / determinism):
|
|
11
|
+
* 1. Version mismatch — deterministic, most dangerous
|
|
12
|
+
* 2. Unused shared — deterministic, easy wins
|
|
13
|
+
* 3. Candidates — heuristic, actionable suggestions
|
|
14
|
+
* 4. Singleton risks — heuristic, potential runtime issues
|
|
15
|
+
* 5. Summary line
|
|
16
|
+
*/
|
|
17
|
+
export declare function formatReport(report: ProjectReport, ctx?: FormatReportContext): string;
|
|
18
|
+
//# sourceMappingURL=format-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-report.d.ts","sourceRoot":"","sources":["../../src/reporter/format-report.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,aAAa,CAAC;AAEjD,MAAM,WAAW,mBAAmB;IAClC,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,QAAQ,GAAG,aAAa,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,MAAM,EAAE,aAAa,EAAE,GAAG,CAAC,EAAE,mBAAmB,GAAG,MAAM,CA6ErF"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Formats a ProjectReport as a human-readable terminal string.
|
|
3
|
+
*
|
|
4
|
+
* Section order (by severity / determinism):
|
|
5
|
+
* 1. Version mismatch — deterministic, most dangerous
|
|
6
|
+
* 2. Unused shared — deterministic, easy wins
|
|
7
|
+
* 3. Candidates — heuristic, actionable suggestions
|
|
8
|
+
* 4. Singleton risks — heuristic, potential runtime issues
|
|
9
|
+
* 5. Summary line
|
|
10
|
+
*/
|
|
11
|
+
export function formatReport(report, ctx) {
|
|
12
|
+
const lines = [];
|
|
13
|
+
const { unused, candidates, mismatched, singletonRisks, eagerRisks, summary } = report;
|
|
14
|
+
// Header
|
|
15
|
+
const header = buildHeader(ctx);
|
|
16
|
+
lines.push('', header, '');
|
|
17
|
+
const hasFindings = mismatched.length > 0 ||
|
|
18
|
+
unused.length > 0 ||
|
|
19
|
+
candidates.length > 0 ||
|
|
20
|
+
singletonRisks.length > 0 ||
|
|
21
|
+
eagerRisks.length > 0;
|
|
22
|
+
if (!hasFindings) {
|
|
23
|
+
lines.push(' No issues found. Shared config looks good.');
|
|
24
|
+
}
|
|
25
|
+
// ── 1. Version mismatch ────────────────────────────────────────────────────
|
|
26
|
+
if (mismatched.length > 0) {
|
|
27
|
+
lines.push(' Version mismatch (sharing silently broken):');
|
|
28
|
+
for (const m of mismatched) {
|
|
29
|
+
lines.push(` ⚠ ${m.package} — requires ${m.configured}, installed ${m.installed}`);
|
|
30
|
+
}
|
|
31
|
+
lines.push('');
|
|
32
|
+
}
|
|
33
|
+
// ── 2. Unused shared ──────────────────────────────────────────────────────
|
|
34
|
+
if (unused.length > 0) {
|
|
35
|
+
lines.push(' Unused shared (safe to remove):');
|
|
36
|
+
for (const u of unused) {
|
|
37
|
+
const note = u.singleton ? 'shared as singleton' : 'shared without singleton';
|
|
38
|
+
lines.push(` ✗ ${u.package} — 0 imports, ${note}`);
|
|
39
|
+
}
|
|
40
|
+
lines.push('');
|
|
41
|
+
}
|
|
42
|
+
// ── 3. Candidates ─────────────────────────────────────────────────────────
|
|
43
|
+
if (candidates.length > 0) {
|
|
44
|
+
lines.push(' Candidates (consider adding to shared):');
|
|
45
|
+
for (const c of candidates) {
|
|
46
|
+
const fileCount = c.files.length;
|
|
47
|
+
const filesLabel = fileCount === 1 ? '1 file' : `${fileCount} files`;
|
|
48
|
+
const viaLabel = c.via === 'reexport' ? `, via re-export in ${c.files[0]}` : '';
|
|
49
|
+
lines.push(` → ${c.package} (${c.importCount} imports in ${filesLabel}${viaLabel})`);
|
|
50
|
+
}
|
|
51
|
+
lines.push('');
|
|
52
|
+
}
|
|
53
|
+
// ── 4. Singleton risks ────────────────────────────────────────────────────
|
|
54
|
+
if (singletonRisks.length > 0) {
|
|
55
|
+
lines.push(' Singleton risks (add singleton: true):');
|
|
56
|
+
for (const r of singletonRisks) {
|
|
57
|
+
lines.push(` ⚠ ${r.package} — manages global state, singleton: true recommended`);
|
|
58
|
+
}
|
|
59
|
+
lines.push('');
|
|
60
|
+
}
|
|
61
|
+
// ── 5. Eager risks ────────────────────────────────────────────────────────
|
|
62
|
+
if (eagerRisks.length > 0) {
|
|
63
|
+
lines.push(' Eager risks (add singleton: true or remove eager: true):');
|
|
64
|
+
for (const r of eagerRisks) {
|
|
65
|
+
lines.push(` ⚠ ${r.package} — eager: true without singleton: true, risk of duplicate instances`);
|
|
66
|
+
}
|
|
67
|
+
lines.push('');
|
|
68
|
+
}
|
|
69
|
+
// ── 6. Summary ────────────────────────────────────────────────────────────
|
|
70
|
+
lines.push(` Total: ${summary.totalShared} shared, ${summary.usedShared} used, ` +
|
|
71
|
+
`${summary.unusedCount} unused, ${summary.candidatesCount} candidates, ` +
|
|
72
|
+
`${summary.mismatchedCount} mismatch, ${summary.eagerRisksCount} eager risks`);
|
|
73
|
+
lines.push('');
|
|
74
|
+
return lines.join('\n');
|
|
75
|
+
}
|
|
76
|
+
// ─── Helpers ──────────────────────────────────────────────────────────────────
|
|
77
|
+
function buildHeader(ctx) {
|
|
78
|
+
const parts = [];
|
|
79
|
+
if (ctx?.depth)
|
|
80
|
+
parts.push(`depth: ${ctx.depth}`);
|
|
81
|
+
if (ctx?.filesScanned !== undefined)
|
|
82
|
+
parts.push(`${ctx.filesScanned} files scanned`);
|
|
83
|
+
const meta = parts.length > 0 ? ` (${parts.join(', ')})` : '';
|
|
84
|
+
const name = ctx?.name ? ` ${ctx.name}` : '';
|
|
85
|
+
return `[MfSharedInspector]${name}${meta}`;
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=format-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"format-report.js","sourceRoot":"","sources":["../../src/reporter/format-report.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { ProjectReport, ProjectManifest } from '../types.js';
|
|
2
|
+
/**
|
|
3
|
+
* Serialises a ProjectReport to a JSON file.
|
|
4
|
+
* Creates parent directories if they don't exist.
|
|
5
|
+
*/
|
|
6
|
+
export declare function writeReport(report: ProjectReport, outputPath: string): Promise<void>;
|
|
7
|
+
/**
|
|
8
|
+
* Serialises a ProjectManifest to a JSON file.
|
|
9
|
+
* Creates parent directories if they don't exist.
|
|
10
|
+
*/
|
|
11
|
+
export declare function writeManifest(manifest: ProjectManifest, outputPath: string): Promise<void>;
|
|
12
|
+
//# sourceMappingURL=write-report.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-report.d.ts","sourceRoot":"","sources":["../../src/reporter/write-report.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,aAAa,CAAC;AAElE;;;GAGG;AACH,wBAAsB,WAAW,CAAC,MAAM,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1F;AAED;;;GAGG;AACH,wBAAsB,aAAa,CAAC,QAAQ,EAAE,eAAe,EAAE,UAAU,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAGhG"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { dirname } from 'node:path';
|
|
3
|
+
/**
|
|
4
|
+
* Serialises a ProjectReport to a JSON file.
|
|
5
|
+
* Creates parent directories if they don't exist.
|
|
6
|
+
*/
|
|
7
|
+
export async function writeReport(report, outputPath) {
|
|
8
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
9
|
+
await writeFile(outputPath, JSON.stringify(report, null, 2), 'utf-8');
|
|
10
|
+
}
|
|
11
|
+
/**
|
|
12
|
+
* Serialises a ProjectManifest to a JSON file.
|
|
13
|
+
* Creates parent directories if they don't exist.
|
|
14
|
+
*/
|
|
15
|
+
export async function writeManifest(manifest, outputPath) {
|
|
16
|
+
await mkdir(dirname(outputPath), { recursive: true });
|
|
17
|
+
await writeFile(outputPath, JSON.stringify(manifest, null, 2), 'utf-8');
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=write-report.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"write-report.js","sourceRoot":"","sources":["../../src/reporter/write-report.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACpD,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAGpC;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,MAAqB,EAAE,UAAkB;IACzE,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AACxE,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,QAAyB,EAAE,UAAkB;IAC/E,MAAM,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACtD,MAAM,SAAS,CAAC,UAAU,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,OAAO,CAAC,CAAC;AAC1E,CAAC"}
|