mcp-react-toolkit 1.0.1 → 1.2.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 +146 -42
- package/package.json +12 -4
- package/tools/accessibility-checker/build/index.js +9 -5
- package/tools/accessibility-checker/build/index.js.map +1 -1
- package/tools/accessibility-checker/build/rules.d.ts.map +1 -1
- package/tools/accessibility-checker/build/rules.js +325 -94
- package/tools/accessibility-checker/build/rules.js.map +1 -1
- package/tools/code-modernizer/build/tools/01-convert-to-typescript.d.ts.map +1 -1
- package/tools/code-modernizer/build/tools/01-convert-to-typescript.js +65 -50
- package/tools/code-modernizer/build/tools/01-convert-to-typescript.js.map +1 -1
- package/tools/code-modernizer/build/types.d.ts +1 -0
- package/tools/code-modernizer/build/types.d.ts.map +1 -1
- package/tools/code-modernizer/build/utils/ast-parser.d.ts.map +1 -1
- package/tools/code-modernizer/build/utils/ast-parser.js +30 -14
- package/tools/code-modernizer/build/utils/ast-parser.js.map +1 -1
- package/tools/code-modernizer/build/utils/type-generator.d.ts +1 -1
- package/tools/code-modernizer/build/utils/type-generator.d.ts.map +1 -1
- package/tools/code-modernizer/build/utils/type-generator.js +72 -23
- package/tools/code-modernizer/build/utils/type-generator.js.map +1 -1
- package/tools/component-factory/build/index.js +59 -7
- package/tools/component-factory/build/index.js.map +1 -1
- package/tools/component-fixer/README.md +44 -0
- package/tools/component-fixer/build/index.d.ts +3 -0
- package/tools/component-fixer/build/index.d.ts.map +1 -0
- package/tools/component-fixer/build/index.js +647 -0
- package/tools/component-fixer/build/index.js.map +1 -0
- package/tools/component-fixer/build/index.test.d.ts +2 -0
- package/tools/component-fixer/build/index.test.d.ts.map +1 -0
- package/tools/component-fixer/build/index.test.js.map +1 -0
- package/tools/component-fixer/package.json +20 -0
- package/tools/component-reviewer/README.md +54 -0
- package/tools/component-reviewer/build/index.d.ts +39 -0
- package/tools/component-reviewer/build/index.d.ts.map +1 -0
- package/tools/component-reviewer/build/index.js +946 -0
- package/tools/component-reviewer/build/index.js.map +1 -0
- package/tools/component-reviewer/build/index.test.d.ts +2 -0
- package/tools/component-reviewer/build/index.test.d.ts.map +1 -0
- package/tools/component-reviewer/build/index.test.js.map +1 -0
- package/tools/component-reviewer/package.json +20 -0
- package/tools/dep-auditor/build/index.d.ts +1 -0
- package/tools/dep-auditor/build/index.d.ts.map +1 -1
- package/tools/dep-auditor/build/index.js +71 -16
- package/tools/dep-auditor/build/index.js.map +1 -1
- package/tools/generate-tests/build/analyzer.d.ts +14 -0
- package/tools/generate-tests/build/analyzer.d.ts.map +1 -1
- package/tools/generate-tests/build/analyzer.js +96 -42
- package/tools/generate-tests/build/analyzer.js.map +1 -1
- package/tools/generate-tests/build/generators.d.ts.map +1 -1
- package/tools/generate-tests/build/generators.js +304 -79
- package/tools/generate-tests/build/generators.js.map +1 -1
- package/tools/generate-tests/build/index.js +29 -10
- package/tools/generate-tests/build/index.js.map +1 -1
- package/tools/json-viewer/build/index.js +29 -6
- package/tools/json-viewer/build/index.js.map +1 -1
- package/tools/legacy-analyzer/README.md +66 -0
- package/tools/legacy-analyzer/build/index.d.ts +3 -0
- package/tools/legacy-analyzer/build/index.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/index.js +209 -0
- package/tools/legacy-analyzer/build/index.js.map +1 -0
- package/tools/legacy-analyzer/build/index.test.d.ts +2 -0
- package/tools/legacy-analyzer/build/index.test.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/index.test.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/01-detect-project-tech.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/01-detect-project-tech.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/01-detect-project-tech.js +115 -0
- package/tools/legacy-analyzer/build/tools/01-detect-project-tech.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/02-analyze-folder-structure.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/02-analyze-folder-structure.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/02-analyze-folder-structure.js +85 -0
- package/tools/legacy-analyzer/build/tools/02-analyze-folder-structure.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/03-analyze-components.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/03-analyze-components.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/03-analyze-components.js +87 -0
- package/tools/legacy-analyzer/build/tools/03-analyze-components.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/04-analyze-state-management.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/04-analyze-state-management.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/04-analyze-state-management.js +133 -0
- package/tools/legacy-analyzer/build/tools/04-analyze-state-management.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/05-analyze-api-layer.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/05-analyze-api-layer.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/05-analyze-api-layer.js +160 -0
- package/tools/legacy-analyzer/build/tools/05-analyze-api-layer.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/06-analyze-routing.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/06-analyze-routing.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/06-analyze-routing.js +150 -0
- package/tools/legacy-analyzer/build/tools/06-analyze-routing.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/07-analyze-styling.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/07-analyze-styling.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/07-analyze-styling.js +131 -0
- package/tools/legacy-analyzer/build/tools/07-analyze-styling.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/08-analyze-assets.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/08-analyze-assets.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/08-analyze-assets.js +85 -0
- package/tools/legacy-analyzer/build/tools/08-analyze-assets.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/09-detect-anti-patterns.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/09-detect-anti-patterns.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/09-detect-anti-patterns.js +329 -0
- package/tools/legacy-analyzer/build/tools/09-detect-anti-patterns.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/10-detect-duplication.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/10-detect-duplication.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/10-detect-duplication.js +192 -0
- package/tools/legacy-analyzer/build/tools/10-detect-duplication.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/11-analyze-dependencies-usage.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/11-analyze-dependencies-usage.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/11-analyze-dependencies-usage.js +232 -0
- package/tools/legacy-analyzer/build/tools/11-analyze-dependencies-usage.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/12-analyze-legacy-app.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/12-analyze-legacy-app.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/12-analyze-legacy-app.js +247 -0
- package/tools/legacy-analyzer/build/tools/12-analyze-legacy-app.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/13-detect-features.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/13-detect-features.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/13-detect-features.js +141 -0
- package/tools/legacy-analyzer/build/tools/13-detect-features.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/14-classify-files.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/14-classify-files.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/14-classify-files.js +76 -0
- package/tools/legacy-analyzer/build/tools/14-classify-files.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/15-detect-shared-modules.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/15-detect-shared-modules.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/15-detect-shared-modules.js +70 -0
- package/tools/legacy-analyzer/build/tools/15-detect-shared-modules.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/16-design-target-structure.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/16-design-target-structure.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/16-design-target-structure.js +26 -0
- package/tools/legacy-analyzer/build/tools/16-design-target-structure.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/17-map-files-to-target.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/17-map-files-to-target.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/17-map-files-to-target.js +108 -0
- package/tools/legacy-analyzer/build/tools/17-map-files-to-target.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/18-detect-boundary-violations.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/18-detect-boundary-violations.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/18-detect-boundary-violations.js +137 -0
- package/tools/legacy-analyzer/build/tools/18-detect-boundary-violations.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/19-suggest-module-splitting.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/19-suggest-module-splitting.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/19-suggest-module-splitting.js +160 -0
- package/tools/legacy-analyzer/build/tools/19-suggest-module-splitting.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/20-naming-standardizer.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/20-naming-standardizer.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/20-naming-standardizer.js +162 -0
- package/tools/legacy-analyzer/build/tools/20-naming-standardizer.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/21-generate-refactor-plan.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/21-generate-refactor-plan.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/21-generate-refactor-plan.js +108 -0
- package/tools/legacy-analyzer/build/tools/21-generate-refactor-plan.js.map +1 -0
- package/tools/legacy-analyzer/build/tools/22-refactor-folder-structure.d.ts +3 -0
- package/tools/legacy-analyzer/build/tools/22-refactor-folder-structure.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/tools/22-refactor-folder-structure.js +98 -0
- package/tools/legacy-analyzer/build/tools/22-refactor-folder-structure.js.map +1 -0
- package/tools/legacy-analyzer/build/types.d.ts +413 -0
- package/tools/legacy-analyzer/build/types.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/types.js +12 -0
- package/tools/legacy-analyzer/build/types.js.map +1 -0
- package/tools/legacy-analyzer/build/utils/ast-parser.d.ts +34 -0
- package/tools/legacy-analyzer/build/utils/ast-parser.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/utils/ast-parser.js +394 -0
- package/tools/legacy-analyzer/build/utils/ast-parser.js.map +1 -0
- package/tools/legacy-analyzer/build/utils/file-scanner.d.ts +51 -0
- package/tools/legacy-analyzer/build/utils/file-scanner.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/utils/file-scanner.js +174 -0
- package/tools/legacy-analyzer/build/utils/file-scanner.js.map +1 -0
- package/tools/legacy-analyzer/build/utils/import-tracker.d.ts +38 -0
- package/tools/legacy-analyzer/build/utils/import-tracker.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/utils/import-tracker.js +194 -0
- package/tools/legacy-analyzer/build/utils/import-tracker.js.map +1 -0
- package/tools/legacy-analyzer/build/utils/refactor-helpers.d.ts +88 -0
- package/tools/legacy-analyzer/build/utils/refactor-helpers.d.ts.map +1 -0
- package/tools/legacy-analyzer/build/utils/refactor-helpers.js +538 -0
- package/tools/legacy-analyzer/build/utils/refactor-helpers.js.map +1 -0
- package/tools/legacy-analyzer/package.json +20 -0
- package/tools/lighthouse-runner/README.md +45 -0
- package/tools/lighthouse-runner/build/index.d.ts +6 -0
- package/tools/lighthouse-runner/build/index.d.ts.map +1 -0
- package/tools/lighthouse-runner/build/index.js +295 -0
- package/tools/lighthouse-runner/build/index.js.map +1 -0
- package/tools/lighthouse-runner/build/index.test.d.ts +2 -0
- package/tools/lighthouse-runner/build/index.test.d.ts.map +1 -0
- package/tools/lighthouse-runner/build/index.test.js.map +1 -0
- package/tools/lighthouse-runner/package.json +20 -0
- package/tools/monorepo-manager/build/utils.d.ts.map +1 -1
- package/tools/monorepo-manager/build/utils.js +12 -9
- package/tools/monorepo-manager/build/utils.js.map +1 -1
- package/tools/performance-audit/README.md +37 -0
- package/tools/performance-audit/build/index.d.ts +13 -0
- package/tools/performance-audit/build/index.d.ts.map +1 -0
- package/tools/performance-audit/build/index.js +311 -0
- package/tools/performance-audit/build/index.js.map +1 -0
- package/tools/performance-audit/build/index.test.d.ts +2 -0
- package/tools/performance-audit/build/index.test.d.ts.map +1 -0
- package/tools/performance-audit/build/index.test.js.map +1 -0
- package/tools/performance-audit/package.json +20 -0
- package/tools/quality-pipeline/build/index.js +55 -15
- package/tools/quality-pipeline/build/index.js.map +1 -1
- package/tools/render-analyzer/README.md +43 -0
- package/tools/render-analyzer/build/index.d.ts +25 -0
- package/tools/render-analyzer/build/index.d.ts.map +1 -0
- package/tools/render-analyzer/build/index.js +342 -0
- package/tools/render-analyzer/build/index.js.map +1 -0
- package/tools/render-analyzer/build/index.test.d.ts +2 -0
- package/tools/render-analyzer/build/index.test.d.ts.map +1 -0
- package/tools/render-analyzer/build/index.test.js.map +1 -0
- package/tools/render-analyzer/package.json +20 -0
- package/tools/shared/build/fs.d.ts +8 -0
- package/tools/shared/build/fs.d.ts.map +1 -0
- package/tools/shared/build/fs.js +45 -0
- package/tools/shared/build/fs.js.map +1 -0
- package/tools/shared/build/index.d.ts +1 -0
- package/tools/shared/build/index.d.ts.map +1 -1
- package/tools/shared/build/index.js +1 -0
- package/tools/shared/build/index.js.map +1 -1
- package/tools/storybook-generator/README.md +39 -0
- package/tools/storybook-generator/build/index.d.ts +13 -0
- package/tools/storybook-generator/build/index.d.ts.map +1 -0
- package/tools/storybook-generator/build/index.js +478 -0
- package/tools/storybook-generator/build/index.js.map +1 -0
- package/tools/storybook-generator/build/index.test.d.ts +2 -0
- package/tools/storybook-generator/build/index.test.d.ts.map +1 -0
- package/tools/storybook-generator/build/index.test.js.map +1 -0
- package/tools/storybook-generator/package.json +20 -0
- package/tools/test-gap-analyzer/README.md +41 -0
- package/tools/test-gap-analyzer/build/index.d.ts +20 -0
- package/tools/test-gap-analyzer/build/index.d.ts.map +1 -0
- package/tools/test-gap-analyzer/build/index.js +371 -0
- package/tools/test-gap-analyzer/build/index.js.map +1 -0
- package/tools/test-gap-analyzer/build/index.test.d.ts +2 -0
- package/tools/test-gap-analyzer/build/index.test.d.ts.map +1 -0
- package/tools/test-gap-analyzer/build/index.test.js.map +1 -0
- package/tools/test-gap-analyzer/package.json +20 -0
- package/tools/typescript-enforcer/build/scanner.d.ts.map +1 -1
- package/tools/typescript-enforcer/build/scanner.js +13 -1
- package/tools/typescript-enforcer/build/scanner.js.map +1 -1
- package/tools/typescript-enforcer/build/types.d.ts +1 -0
- package/tools/typescript-enforcer/build/types.d.ts.map +1 -1
- package/mcp-publisher +0 -0
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL #2: analyze-folder-structure
|
|
3
|
+
// Analyzes directory structure: flat vs feature-based, folder presence, depth
|
|
4
|
+
// ============================================================================
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { getDirectoriesAtDepth, calculateMaxDepth, findSourceFiles, resolveSourceDir } from '../utils/file-scanner.js';
|
|
7
|
+
const COMMON_FOLDERS = [
|
|
8
|
+
'components', 'component', 'ui',
|
|
9
|
+
'utils', 'util', 'helpers', 'helper',
|
|
10
|
+
'services', 'service', 'api',
|
|
11
|
+
'hooks', 'hook', 'custom-hooks',
|
|
12
|
+
'pages', 'page', 'views', 'screens',
|
|
13
|
+
'store', 'stores', 'redux', 'state',
|
|
14
|
+
'assets', 'static', 'public',
|
|
15
|
+
'styles', 'css', 'scss',
|
|
16
|
+
'constants', 'config',
|
|
17
|
+
'types', 'interfaces', 'models',
|
|
18
|
+
'features', 'modules',
|
|
19
|
+
'contexts', 'providers',
|
|
20
|
+
];
|
|
21
|
+
export async function analyzeFolderStructure(appPath, config) {
|
|
22
|
+
const srcPath = resolveSourceDir(appPath);
|
|
23
|
+
const allDirs = getDirectoriesAtDepth(srcPath, 5);
|
|
24
|
+
// Get top-level directories in src/
|
|
25
|
+
const topLevelDirs = allDirs.filter((d) => !d.includes(path.sep));
|
|
26
|
+
const secondLevelDirs = allDirs.filter((d) => d.split(path.sep).length === 2);
|
|
27
|
+
// Detect which common folders exist
|
|
28
|
+
const folders = [];
|
|
29
|
+
const foundFolders = new Set();
|
|
30
|
+
for (const dir of allDirs) {
|
|
31
|
+
const parts = dir.split(path.sep);
|
|
32
|
+
for (const part of parts) {
|
|
33
|
+
const lower = part.toLowerCase();
|
|
34
|
+
if (COMMON_FOLDERS.includes(lower) && !foundFolders.has(lower)) {
|
|
35
|
+
foundFolders.add(lower);
|
|
36
|
+
folders.push(dir);
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
// Classify structure type
|
|
41
|
+
let structureType;
|
|
42
|
+
const hasFeatures = topLevelDirs.some((d) => ['features', 'modules', 'pages', 'screens', 'views'].includes(d.toLowerCase()));
|
|
43
|
+
const hasFlatStructure = topLevelDirs.some((d) => ['components', 'utils', 'services', 'hooks'].includes(d.toLowerCase()));
|
|
44
|
+
if (hasFeatures && hasFlatStructure) {
|
|
45
|
+
structureType = 'mixed';
|
|
46
|
+
}
|
|
47
|
+
else if (hasFeatures) {
|
|
48
|
+
structureType = 'feature-based';
|
|
49
|
+
}
|
|
50
|
+
else {
|
|
51
|
+
structureType = 'flat';
|
|
52
|
+
}
|
|
53
|
+
// Calculate depth
|
|
54
|
+
const maxDepth = calculateMaxDepth(srcPath);
|
|
55
|
+
// Detect issues
|
|
56
|
+
const issues = [];
|
|
57
|
+
if (maxDepth > 5) {
|
|
58
|
+
issues.push(`Deep nesting detected (${maxDepth} levels). Consider flattening the structure.`);
|
|
59
|
+
}
|
|
60
|
+
if (!foundFolders.has('components') && !foundFolders.has('component')) {
|
|
61
|
+
issues.push('No dedicated components folder found.');
|
|
62
|
+
}
|
|
63
|
+
if (!foundFolders.has('utils') && !foundFolders.has('util') && !foundFolders.has('helpers')) {
|
|
64
|
+
issues.push('No dedicated utils/helpers folder found. Utility code may be scattered.');
|
|
65
|
+
}
|
|
66
|
+
if (structureType === 'mixed') {
|
|
67
|
+
issues.push('Mixed folder structure detected (both flat and feature-based). Consider standardizing.');
|
|
68
|
+
}
|
|
69
|
+
// Check for src at wrong level
|
|
70
|
+
const sourceFiles = await findSourceFiles(appPath);
|
|
71
|
+
const filesOutsideSrc = sourceFiles.filter((f) => {
|
|
72
|
+
const rel = path.relative(appPath, f);
|
|
73
|
+
return !rel.startsWith('src' + path.sep) && rel !== 'src';
|
|
74
|
+
});
|
|
75
|
+
if (filesOutsideSrc.length > 0) {
|
|
76
|
+
issues.push(`${filesOutsideSrc.length} source files found outside src/ directory.`);
|
|
77
|
+
}
|
|
78
|
+
return {
|
|
79
|
+
structureType,
|
|
80
|
+
folders: folders.sort(),
|
|
81
|
+
maxDepth,
|
|
82
|
+
issues,
|
|
83
|
+
};
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=02-analyze-folder-structure.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"02-analyze-folder-structure.js","sourceRoot":"","sources":["../../src/tools/02-analyze-folder-structure.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"03-analyze-components.d.ts","sourceRoot":"","sources":["../../src/tools/03-analyze-components.ts"],"names":[],"mappings":"AAUA,OAAO,KAAK,EAAE,uBAAuB,EAAiB,cAAc,EAAE,MAAM,aAAa,CAAC;AAE1F,wBAAsB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,uBAAuB,CAAC,CAoF3H"}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL #3: analyze-components
|
|
3
|
+
// Scans all components: count, large components, complex components
|
|
4
|
+
// ============================================================================
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import * as fs from 'fs';
|
|
7
|
+
import { findSourceFiles, resolveSourceDir } from '../utils/file-scanner.js';
|
|
8
|
+
import { analyzeComponent } from '../utils/ast-parser.js';
|
|
9
|
+
import { DEFAULT_CONFIG } from '../types.js';
|
|
10
|
+
export async function analyzeComponents(appPath, config) {
|
|
11
|
+
const mergedConfig = { ...DEFAULT_CONFIG, ...config };
|
|
12
|
+
const srcPath = resolveSourceDir(appPath);
|
|
13
|
+
const files = await findSourceFiles(srcPath);
|
|
14
|
+
// Include all JS/JSX/TS/TSX files — apps like CRA use lowercase App.js or index.js
|
|
15
|
+
const componentFiles = files;
|
|
16
|
+
const largeComponents = [];
|
|
17
|
+
const complexComponents = [];
|
|
18
|
+
for (const file of componentFiles) {
|
|
19
|
+
const relPath = path.relative(appPath, file);
|
|
20
|
+
// Read raw content first (works for both JS and TS)
|
|
21
|
+
let content;
|
|
22
|
+
try {
|
|
23
|
+
content = fs.readFileSync(file, 'utf8');
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
continue;
|
|
27
|
+
}
|
|
28
|
+
// Try AST analysis — may fail for plain JS files
|
|
29
|
+
const analysis = analyzeComponent(file);
|
|
30
|
+
const responsibilities = [];
|
|
31
|
+
const importSources = (analysis?.imports ?? []).map((i) => i.source.toLowerCase());
|
|
32
|
+
// All responsibility checks use regex on raw content (works for both JS and TS)
|
|
33
|
+
const hasState = /\buseState\s*\(|React\.useState\s*\(|\buseReducer\s*\(|React\.useReducer\s*\(/.test(content)
|
|
34
|
+
|| (analysis?.hooks.some((h) => h.name === 'useState' || h.name === 'useReducer') ?? false);
|
|
35
|
+
if (hasState)
|
|
36
|
+
responsibilities.push('state-management');
|
|
37
|
+
const hasEffect = /\buseEffect\s*\(|React\.useEffect\s*\(/.test(content)
|
|
38
|
+
|| (analysis?.hooks.some((h) => h.name === 'useEffect') ?? false);
|
|
39
|
+
if (hasEffect)
|
|
40
|
+
responsibilities.push('side-effects');
|
|
41
|
+
if (content.includes('fetch(') || content.includes('axios.') || importSources.some((s) => s.includes('api'))) {
|
|
42
|
+
responsibilities.push('api-calls');
|
|
43
|
+
}
|
|
44
|
+
if (importSources.some((s) => s.includes('router') || s.includes('navigate'))) {
|
|
45
|
+
responsibilities.push('routing');
|
|
46
|
+
}
|
|
47
|
+
if (content.includes('onSubmit') || content.includes('FormData') || content.includes('handleSubmit')) {
|
|
48
|
+
responsibilities.push('form-handling');
|
|
49
|
+
}
|
|
50
|
+
const jsxTagCount = (content.match(/<[A-Z][a-zA-Z]*|<[a-z]+[\s>]/g) || []).length;
|
|
51
|
+
const astJsxCount = analysis?.jsxElements.length ?? 0;
|
|
52
|
+
if (astJsxCount > 15 || jsxTagCount > 15)
|
|
53
|
+
responsibilities.push('heavy-rendering');
|
|
54
|
+
const lines = content.split('\n').length;
|
|
55
|
+
const stateVarCount = (content.match(/\buseState\s*\(|React\.useState\s*\(/g) || []).length;
|
|
56
|
+
const hookCount = analysis?.hooks.length ?? 0;
|
|
57
|
+
const jsxDepth = analysis?.jsxMaxDepth ?? 0;
|
|
58
|
+
const componentName = analysis?.name ?? path.basename(file, path.extname(file));
|
|
59
|
+
const componentInfo = {
|
|
60
|
+
name: componentName,
|
|
61
|
+
file: relPath,
|
|
62
|
+
lines,
|
|
63
|
+
jsxMaxDepth: jsxDepth,
|
|
64
|
+
responsibilities,
|
|
65
|
+
};
|
|
66
|
+
// Skip non-component files (no JSX, no hooks, not enough evidence)
|
|
67
|
+
const isLikelyComponent = jsxTagCount > 0 || hasState || hasEffect || content.includes('return (') || content.includes('return(');
|
|
68
|
+
if (!isLikelyComponent)
|
|
69
|
+
continue;
|
|
70
|
+
if (lines > mergedConfig.largeComponentLines) {
|
|
71
|
+
largeComponents.push(componentInfo);
|
|
72
|
+
}
|
|
73
|
+
// Complex: multiple responsibilities, or deep nesting, or many hooks, or many state vars
|
|
74
|
+
const isComplex = responsibilities.length >= 3 ||
|
|
75
|
+
jsxDepth > 6 ||
|
|
76
|
+
hookCount >= 5 ||
|
|
77
|
+
stateVarCount >= 3;
|
|
78
|
+
if (isComplex)
|
|
79
|
+
complexComponents.push(componentInfo);
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
totalComponents: componentFiles.length,
|
|
83
|
+
largeComponents: largeComponents.sort((a, b) => b.lines - a.lines),
|
|
84
|
+
complexComponents: complexComponents.sort((a, b) => b.responsibilities.length - a.responsibilities.length),
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=03-analyze-components.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"03-analyze-components.js","sourceRoot":"","sources":["../../src/tools/03-analyze-components.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"04-analyze-state-management.d.ts","sourceRoot":"","sources":["../../src/tools/04-analyze-state-management.ts"],"names":[],"mappings":"AAQA,OAAO,KAAK,EAAE,kBAAkB,EAAiB,cAAc,EAAE,MAAM,aAAa,CAAC;AAErF,wBAAsB,sBAAsB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,kBAAkB,CAAC,CA+I3H"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL #4: analyze-state-management
|
|
3
|
+
// Detects Redux, Context API, local state patterns, and advanced patterns
|
|
4
|
+
// ============================================================================
|
|
5
|
+
import * as path from 'path';
|
|
6
|
+
import { findSourceFiles, readFileContent, resolveSourceDir } from '../utils/file-scanner.js';
|
|
7
|
+
import { parseFile, extractImports, extractHooks } from '../utils/ast-parser.js';
|
|
8
|
+
export async function analyzeStateManagement(appPath, config) {
|
|
9
|
+
const srcPath = resolveSourceDir(appPath);
|
|
10
|
+
const files = await findSourceFiles(srcPath);
|
|
11
|
+
let reduxUsage = 0;
|
|
12
|
+
let contextUsage = 0;
|
|
13
|
+
let localStateUsage = 0;
|
|
14
|
+
const patterns = {
|
|
15
|
+
normalizedState: false,
|
|
16
|
+
derivedState: false,
|
|
17
|
+
reselectUsed: false,
|
|
18
|
+
};
|
|
19
|
+
const issues = [];
|
|
20
|
+
const stateHeavyComponents = [];
|
|
21
|
+
let hasEntitiesPattern = false;
|
|
22
|
+
let hasIdsPattern = false;
|
|
23
|
+
let hasDerivedState = false;
|
|
24
|
+
let hasCreateSelector = false;
|
|
25
|
+
let totalLocalStateCalls = 0;
|
|
26
|
+
for (const file of files) {
|
|
27
|
+
const content = readFileContent(file);
|
|
28
|
+
if (!content)
|
|
29
|
+
continue;
|
|
30
|
+
const relPath = path.relative(appPath, file);
|
|
31
|
+
// AST-based analysis (best effort)
|
|
32
|
+
let astHooks = [];
|
|
33
|
+
let astImportSources = [];
|
|
34
|
+
const parsed = parseFile(file);
|
|
35
|
+
if (parsed) {
|
|
36
|
+
const imports = extractImports(parsed.ast);
|
|
37
|
+
astHooks = extractHooks(parsed.ast);
|
|
38
|
+
astImportSources = imports.map((i) => i.source);
|
|
39
|
+
}
|
|
40
|
+
// Redux detection
|
|
41
|
+
const hasRedux = astImportSources.some((s) => s.includes('redux') || s.includes('@reduxjs/toolkit') || s.includes('react-redux')) || content.includes('useSelector') || content.includes('useDispatch') || content.includes('createStore');
|
|
42
|
+
if (hasRedux)
|
|
43
|
+
reduxUsage++;
|
|
44
|
+
// Context API detection
|
|
45
|
+
const hasContext = content.includes('createContext') || content.includes('useContext') || content.includes('React.createContext');
|
|
46
|
+
if (hasContext)
|
|
47
|
+
contextUsage++;
|
|
48
|
+
// Local state detection — covers both imported useState and React.useState namespace style
|
|
49
|
+
const astStateHooks = astHooks.filter((h) => h.name === 'useState' || h.name === 'useReducer');
|
|
50
|
+
const regexStateCount = (content.match(/\buseState\s*\(/g) || []).length
|
|
51
|
+
+ (content.match(/React\.useState\s*\(/g) || []).length
|
|
52
|
+
+ (content.match(/\buseReducer\s*\(/g) || []).length
|
|
53
|
+
+ (content.match(/React\.useReducer\s*\(/g) || []).length;
|
|
54
|
+
const localStateCount = Math.max(astStateHooks.length, regexStateCount);
|
|
55
|
+
if (localStateCount > 0) {
|
|
56
|
+
localStateUsage++;
|
|
57
|
+
totalLocalStateCalls += localStateCount;
|
|
58
|
+
// Flag components with excessive local state (potential god component)
|
|
59
|
+
if (localStateCount >= 3) {
|
|
60
|
+
stateHeavyComponents.push(`${relPath} (${localStateCount} state variables)`);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
// Reselect detection
|
|
64
|
+
if (content.includes('createSelector') || astImportSources.some((s) => s.includes('reselect'))) {
|
|
65
|
+
hasCreateSelector = true;
|
|
66
|
+
}
|
|
67
|
+
// Normalized state detection
|
|
68
|
+
if (content.includes('entities') && (content.includes('ids') || content.includes('allIds'))) {
|
|
69
|
+
hasEntitiesPattern = true;
|
|
70
|
+
hasIdsPattern = true;
|
|
71
|
+
}
|
|
72
|
+
if (content.includes('byId') || content.includes('entitiesById')) {
|
|
73
|
+
hasEntitiesPattern = true;
|
|
74
|
+
}
|
|
75
|
+
// Derived state detection
|
|
76
|
+
const hasMemo = content.includes('useMemo') || content.includes('React.useMemo');
|
|
77
|
+
if (hasMemo && localStateCount > 0)
|
|
78
|
+
hasDerivedState = true;
|
|
79
|
+
if (content.includes('getDerived') || content.includes('selectDerived'))
|
|
80
|
+
hasDerivedState = true;
|
|
81
|
+
// Mixed Redux + excessive local state
|
|
82
|
+
if (hasRedux && localStateCount > 5) {
|
|
83
|
+
issues.push(`${relPath}: Mix of Redux and excessive local state (${localStateCount} useState calls). Consider consolidating.`);
|
|
84
|
+
}
|
|
85
|
+
// Large Redux slices
|
|
86
|
+
if (content.includes('createSlice') && content.split('\n').length > 200) {
|
|
87
|
+
issues.push(`${relPath}: Large Redux slice. Consider splitting into smaller slices.`);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
patterns.normalizedState = hasEntitiesPattern && hasIdsPattern;
|
|
91
|
+
patterns.derivedState = hasDerivedState;
|
|
92
|
+
patterns.reselectUsed = hasCreateSelector;
|
|
93
|
+
let stateType;
|
|
94
|
+
const hasRedux = reduxUsage > 0;
|
|
95
|
+
const hasContext = contextUsage > 0;
|
|
96
|
+
const hasLocal = localStateUsage > 0;
|
|
97
|
+
if (hasRedux && (hasContext || hasLocal)) {
|
|
98
|
+
stateType = 'mixed';
|
|
99
|
+
}
|
|
100
|
+
else if (hasRedux) {
|
|
101
|
+
stateType = 'redux';
|
|
102
|
+
}
|
|
103
|
+
else if (hasContext) {
|
|
104
|
+
stateType = 'context';
|
|
105
|
+
}
|
|
106
|
+
else if (hasLocal) {
|
|
107
|
+
stateType = 'local';
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
110
|
+
stateType = 'none';
|
|
111
|
+
}
|
|
112
|
+
if (stateType === 'mixed') {
|
|
113
|
+
issues.push('Mixed state management detected (Redux + Context/Local). Consider standardizing on one approach.');
|
|
114
|
+
}
|
|
115
|
+
if (hasRedux && !hasCreateSelector) {
|
|
116
|
+
issues.push('Redux used without Reselect. Consider using memoized selectors for performance.');
|
|
117
|
+
}
|
|
118
|
+
if (contextUsage > 5) {
|
|
119
|
+
issues.push(`High Context API usage (${contextUsage} files). Consider if some contexts should be Redux stores or Zustand.`);
|
|
120
|
+
}
|
|
121
|
+
if (stateType === 'local' && totalLocalStateCalls > 5) {
|
|
122
|
+
issues.push(`All state is local useState (${totalLocalStateCalls} calls across ${localStateUsage} files). Consider extracting to Context or Zustand for complex shared state.`);
|
|
123
|
+
}
|
|
124
|
+
if (stateHeavyComponents.length > 0) {
|
|
125
|
+
issues.push(`Components with many state variables (potential god components): ${stateHeavyComponents.join(', ')}`);
|
|
126
|
+
}
|
|
127
|
+
return {
|
|
128
|
+
stateType,
|
|
129
|
+
patterns,
|
|
130
|
+
issues,
|
|
131
|
+
};
|
|
132
|
+
}
|
|
133
|
+
//# sourceMappingURL=04-analyze-state-management.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"04-analyze-state-management.js","sourceRoot":"","sources":["../../src/tools/04-analyze-state-management.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"05-analyze-api-layer.d.ts","sourceRoot":"","sources":["../../src/tools/05-analyze-api-layer.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,gBAAgB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAKpE,wBAAsB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,gBAAgB,CAAC,CA2JlH"}
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
// ============================================================================
|
|
2
|
+
// TOOL #5: analyze-api-layer
|
|
3
|
+
// Detects API patterns: axios/fetch/superagent usage, Next.js API routes,
|
|
4
|
+
// centralized vs scattered pattern, and duplicate endpoints
|
|
5
|
+
// ============================================================================
|
|
6
|
+
import * as path from 'path';
|
|
7
|
+
import { findSourceFiles, readFileContent, resolveSourceDir } from '../utils/file-scanner.js';
|
|
8
|
+
import { parseFile, extractImports } from '../utils/ast-parser.js';
|
|
9
|
+
const API_CLIENTS = ['axios', 'node-fetch', 'got', 'superagent', 'ky', 'undici'];
|
|
10
|
+
const API_INDICATORS = ['fetch(', 'axios.', 'api.', '/api/', 'useSWR', 'useQuery', 'useMutation'];
|
|
11
|
+
export async function analyzeApiLayer(appPath, config) {
|
|
12
|
+
const srcPath = resolveSourceDir(appPath);
|
|
13
|
+
const files = await findSourceFiles(srcPath);
|
|
14
|
+
const clients = new Set();
|
|
15
|
+
const issues = [];
|
|
16
|
+
const apiEndpoints = new Map(); // endpoint -> files
|
|
17
|
+
let centralizedFiles = 0;
|
|
18
|
+
let scatteredFiles = 0;
|
|
19
|
+
const duplicateEndpoints = [];
|
|
20
|
+
// Files that look like API service files
|
|
21
|
+
// Next.js API routes are inherently centralized (pages/api/ or app/api/)
|
|
22
|
+
const isNextJsApiRoute = (f) => {
|
|
23
|
+
const rel = f.replace(appPath, '');
|
|
24
|
+
return rel.includes('/pages/api/') || rel.includes('/app/api/');
|
|
25
|
+
};
|
|
26
|
+
const apiServiceFiles = files.filter((f) => {
|
|
27
|
+
if (isNextJsApiRoute(f))
|
|
28
|
+
return true;
|
|
29
|
+
const lower = f.toLowerCase();
|
|
30
|
+
const base = path.basename(lower, path.extname(lower));
|
|
31
|
+
const API_SERVICE_NAMES = ['agent', 'api', 'http', 'client', 'request', 'fetcher', 'axios', 'service'];
|
|
32
|
+
return lower.includes('/api/') || lower.includes('/service') || lower.includes('/services/') ||
|
|
33
|
+
lower.includes('client.') || lower.includes('/api-client') || API_SERVICE_NAMES.includes(base);
|
|
34
|
+
});
|
|
35
|
+
for (const file of files) {
|
|
36
|
+
const content = readFileContent(file);
|
|
37
|
+
if (!content)
|
|
38
|
+
continue;
|
|
39
|
+
const relPath = path.relative(appPath, file);
|
|
40
|
+
const isApiService = apiServiceFiles.includes(file);
|
|
41
|
+
// Content-based detection (works for both JS and TS files)
|
|
42
|
+
const hasFetch = content.includes('fetch(');
|
|
43
|
+
const hasAxios = content.includes('axios.get(') || content.includes('axios.post(') || content.includes('axios(');
|
|
44
|
+
const hasSuperagent = content.includes('superagent.') || content.includes('superagent-promise');
|
|
45
|
+
const hasGot = content.includes('got.get(') || content.includes('got.post(') || content.includes("from 'got'") || content.includes('from "got"');
|
|
46
|
+
const hasKy = content.includes('ky.get(') || content.includes('ky.post(') || content.includes("from 'ky'") || content.includes('from "ky"');
|
|
47
|
+
// Register clients detected by content
|
|
48
|
+
if (hasFetch && !content.includes('axios') && !hasSuperagent)
|
|
49
|
+
clients.add('fetch');
|
|
50
|
+
if (hasAxios)
|
|
51
|
+
clients.add('axios');
|
|
52
|
+
if (hasSuperagent)
|
|
53
|
+
clients.add('superagent');
|
|
54
|
+
if (hasGot)
|
|
55
|
+
clients.add('got');
|
|
56
|
+
if (hasKy)
|
|
57
|
+
clients.add('ky');
|
|
58
|
+
const hasApiIndicator = API_INDICATORS.some((indicator) => content.includes(indicator));
|
|
59
|
+
const hasApiCall = hasApiIndicator || hasFetch || hasAxios || hasSuperagent || hasGot || hasKy;
|
|
60
|
+
if (hasApiCall) {
|
|
61
|
+
if (isApiService)
|
|
62
|
+
centralizedFiles++;
|
|
63
|
+
else
|
|
64
|
+
scatteredFiles++;
|
|
65
|
+
}
|
|
66
|
+
// Extract API endpoints (skip CDN, schema, and asset URLs)
|
|
67
|
+
const EXCLUDED_URL_PATTERNS = ['w3.org', 'schemas.', 'xmlns', 'cdn.', 'fonts.', 'cdnjs.', 'unpkg.', 'jsdelivr.', 'cloudflare.com/ajax', 'localhost', '127.0.0.1', '0.0.0.0'];
|
|
68
|
+
const endpointRegex = /['"`](\/api\/[^'"`\s]+|https?:\/\/[^'"`\s]+)['"`]/g;
|
|
69
|
+
let endpointMatch;
|
|
70
|
+
while ((endpointMatch = endpointRegex.exec(content)) !== null) {
|
|
71
|
+
const endpoint = endpointMatch[1];
|
|
72
|
+
if (EXCLUDED_URL_PATTERNS.some((pat) => endpoint.includes(pat)))
|
|
73
|
+
continue;
|
|
74
|
+
if (!apiEndpoints.has(endpoint))
|
|
75
|
+
apiEndpoints.set(endpoint, []);
|
|
76
|
+
apiEndpoints.get(endpoint).push(relPath);
|
|
77
|
+
}
|
|
78
|
+
// Detect fetch without response handling (fire-and-forget)
|
|
79
|
+
if (hasFetch) {
|
|
80
|
+
const fetchMatches = [...content.matchAll(/fetch\s*\([^)]+\)/g)];
|
|
81
|
+
for (const m of fetchMatches) {
|
|
82
|
+
const idx = m.index ?? 0;
|
|
83
|
+
const after = content.slice(idx, idx + 200);
|
|
84
|
+
if (!after.includes('.then(') && !after.includes('await') && !after.includes('.json(')) {
|
|
85
|
+
issues.push(`${relPath}: fetch() result not handled — response never read or awaited.`);
|
|
86
|
+
break;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
// Detect missing Content-Type on mutating requests
|
|
91
|
+
if (hasFetch && (content.includes("method: 'POST'") || content.includes('method: "POST"') ||
|
|
92
|
+
content.includes("method: 'PUT'") || content.includes("method: 'PATCH'"))) {
|
|
93
|
+
if (!content.includes('Content-Type') && !content.includes('content-type')) {
|
|
94
|
+
issues.push(`${relPath}: POST/PUT fetch call missing Content-Type header.`);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// AST-based: detect library imports (best effort, skip if AST fails for .js)
|
|
98
|
+
const parsed = parseFile(file);
|
|
99
|
+
if (parsed) {
|
|
100
|
+
const imports = extractImports(parsed.ast);
|
|
101
|
+
const importSources = imports.map((i) => i.source);
|
|
102
|
+
for (const client of API_CLIENTS) {
|
|
103
|
+
if (importSources.some((s) => s.includes(client)))
|
|
104
|
+
clients.add(client);
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
// Find duplicate endpoints
|
|
109
|
+
for (const [endpoint, filesUsingIt] of apiEndpoints) {
|
|
110
|
+
if (filesUsingIt.length > 1) {
|
|
111
|
+
duplicateEndpoints.push(`${endpoint} (used in ${filesUsingIt.length} files)`);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
// Determine pattern
|
|
115
|
+
let apiPattern;
|
|
116
|
+
if (centralizedFiles === 0 && scatteredFiles === 0) {
|
|
117
|
+
apiPattern = 'none';
|
|
118
|
+
}
|
|
119
|
+
else if (centralizedFiles > 0 && scatteredFiles === 0) {
|
|
120
|
+
apiPattern = 'centralized';
|
|
121
|
+
}
|
|
122
|
+
else if (scatteredFiles > centralizedFiles) {
|
|
123
|
+
apiPattern = 'scattered';
|
|
124
|
+
}
|
|
125
|
+
else {
|
|
126
|
+
apiPattern = 'mixed';
|
|
127
|
+
}
|
|
128
|
+
// Issues
|
|
129
|
+
if (apiPattern === 'scattered') {
|
|
130
|
+
issues.push('API calls scattered across components. Consider creating a centralized API service layer.');
|
|
131
|
+
}
|
|
132
|
+
if (apiPattern === 'mixed') {
|
|
133
|
+
issues.push('Mixed API patterns. Some calls centralized, some scattered. Standardize for consistency.');
|
|
134
|
+
}
|
|
135
|
+
if (duplicateEndpoints.length > 0) {
|
|
136
|
+
issues.push(`Duplicate API endpoints detected: ${duplicateEndpoints.join(', ')}`);
|
|
137
|
+
}
|
|
138
|
+
if (clients.size > 1) {
|
|
139
|
+
issues.push(`Multiple HTTP clients detected (${Array.from(clients).join(', ')}). Consider using one consistently.`);
|
|
140
|
+
}
|
|
141
|
+
if (clients.size === 0 && apiPattern !== 'none') {
|
|
142
|
+
issues.push('API calls detected but no recognized HTTP client found. May be using a custom wrapper.');
|
|
143
|
+
}
|
|
144
|
+
// Check for missing error handling
|
|
145
|
+
for (const file of files) {
|
|
146
|
+
const content = readFileContent(file);
|
|
147
|
+
if (!content)
|
|
148
|
+
continue;
|
|
149
|
+
if ((content.includes('fetch(') || content.includes('axios.')) && !content.includes('.catch') && !content.includes('try {')) {
|
|
150
|
+
issues.push(`${path.relative(appPath, file)}: API calls without error handling.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
return {
|
|
154
|
+
apiPattern,
|
|
155
|
+
clients: Array.from(clients),
|
|
156
|
+
duplicateEndpoints,
|
|
157
|
+
issues,
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
//# sourceMappingURL=05-analyze-api-layer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"05-analyze-api-layer.js","sourceRoot":"","sources":["../../src/tools/05-analyze-api-layer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"06-analyze-routing.d.ts","sourceRoot":"","sources":["../../src/tools/06-analyze-routing.ts"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,oBAAoB,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAIxE,wBAAsB,cAAc,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAAG,OAAO,CAAC,oBAAoB,CAAC,CA+JrH"}
|