impact-analysis 2.0.0 → 2.0.2

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/src/cli.ts DELETED
@@ -1,110 +0,0 @@
1
- #!/usr/bin/env node
2
- import 'dotenv/config';
3
- import path from 'path';
4
- import { exec } from 'child_process';
5
- import { promisify } from 'util';
6
- import { getChangedFiles } from './git/getChangedFiles';
7
- import { scanRepo } from './scanner/scanRepo';
8
- import { buildGraph } from './graph/buildGraph';
9
- import { analyzeImpact } from './core/analyzer';
10
- import { generateHtmlReport } from './report/html-generator';
11
- import { explainImpact } from './ai/explain';
12
-
13
- const execAsync = promisify(exec);
14
-
15
- async function main() {
16
- const args = process.argv.slice(2);
17
- const showHtml = args.includes('--html');
18
- const useAI = args.includes('--ai');
19
- const clearCache = args.includes('--clear-cache');
20
- const baseBranch = args.find(arg => !arg.startsWith('--')) || 'main';
21
-
22
- try {
23
- if (clearCache) {
24
- const fs = await import('fs');
25
- if (fs.existsSync('.impact-analysis-cache.json')) {
26
- fs.unlinkSync('.impact-analysis-cache.json');
27
- console.log('Cache cleared.');
28
- }
29
- }
30
-
31
- console.log('Scanning repository...');
32
- const allFiles = await scanRepo();
33
-
34
- console.log(`Building dependency graph from ${allFiles.length} files...`);
35
- const graph = await buildGraph(allFiles);
36
-
37
- console.log(`Getting changed files against ${baseBranch}...`);
38
- const changedFiles = await getChangedFiles(baseBranch);
39
-
40
- if (changedFiles.length === 0) {
41
- console.log('No changed files found.');
42
- return;
43
- }
44
-
45
- console.log(`Found ${changedFiles.length} changed files. Analyzing impact...`);
46
-
47
- const dependencyMap: Record<string, string[]> = {};
48
- graph.importedBy.forEach((importers, file) => {
49
- dependencyMap[file] = Array.from(importers);
50
- });
51
-
52
- const results = analyzeImpact(changedFiles, dependencyMap);
53
-
54
- if (useAI) {
55
- try {
56
- console.log('Getting AI explanation...');
57
- const explanation = await explainImpact(results);
58
- if (explanation) {
59
- (results as any).aiExplanation = explanation;
60
- }
61
- } catch (error) {
62
- console.warn('AI explanation failed:', error instanceof Error ? error.message : String(error));
63
- }
64
- }
65
-
66
- console.log('\n--- Impact Analysis Results ---\n');
67
- results.forEach((result, index) => {
68
- console.log(`${index + 1}. ${path.basename(result.changedFile)}`);
69
- console.log(` Risk: ${result.risk}`);
70
- console.log(` Impacted files: ${result.impactedFiles.length}`);
71
- if (result.impactedFiles.length > 0) {
72
- result.impactedFiles.slice(0, 5).forEach(file => {
73
- console.log(` - ${path.basename(file)}`);
74
- });
75
- if (result.impactedFiles.length > 5) {
76
- console.log(` ... and ${result.impactedFiles.length - 5} more`);
77
- }
78
- }
79
- console.log('');
80
- });
81
-
82
- // Generate HTML by default
83
- console.log('Generating HTML report...');
84
- const htmlPath = generateHtmlReport(results);
85
- console.log(`Report saved: ${htmlPath}`);
86
-
87
- if (showHtml) {
88
- try {
89
- // Use platform-specific command to open the file
90
- const command = process.platform === 'win32'
91
- ? `start "" "${htmlPath}"`
92
- : process.platform === 'darwin'
93
- ? `open "${htmlPath}"`
94
- : `xdg-open "${htmlPath}"`;
95
-
96
- await execAsync(command);
97
- console.log(`Report opened in browser`);
98
- } catch (err) {
99
- console.log(`Could not auto-open browser. Please open: ${htmlPath}`);
100
- }
101
- } else {
102
- console.log(`\nTo view the graphical report, run: impact-analysis --html`);
103
- }
104
- } catch (error) {
105
- console.error('Error:', error instanceof Error ? error.message : String(error));
106
- process.exit(1);
107
- }
108
- }
109
-
110
- main();
@@ -1,5 +0,0 @@
1
- export interface DependencyGraph {
2
- imports: Map<string, Set<string>>;
3
- importedBy: Map<string, Set<string>>;
4
- componentUsage: Map<string, Set<string>>;
5
- }
@@ -1,69 +0,0 @@
1
- import { parse } from "@babel/parser";
2
- import traverse from "@babel/traverse";
3
-
4
- export function extractImports(code: string): string[] {
5
- const imports: string[] = [];
6
-
7
- try {
8
- const ast = parse(code, {
9
- sourceType: "unambiguous",
10
- plugins: [
11
- "typescript",
12
- "jsx",
13
- "decorators-legacy",
14
- "classProperties",
15
- "dynamicImport",
16
- "importMeta",
17
- "topLevelAwait",
18
- "classStaticBlock",
19
- "optionalChaining",
20
- "nullishCoalescingOperator"
21
- ],
22
- errorRecovery: true
23
- });
24
-
25
- traverse(ast as any, {
26
- // Static imports: import x from 'module'
27
- ImportDeclaration(path) {
28
- imports.push(path.node.source.value);
29
- },
30
- // Dynamic imports: import('module')
31
- Import(path) {
32
- const parent = path.parent;
33
- if (parent.type === 'CallExpression' && parent.arguments[0]) {
34
- const arg = parent.arguments[0];
35
- if (arg.type === 'StringLiteral') {
36
- imports.push(arg.value);
37
- }
38
- }
39
- },
40
- // Export from: export { x } from 'module'
41
- ExportNamedDeclaration(path) {
42
- if (path.node.source) {
43
- imports.push(path.node.source.value);
44
- }
45
- },
46
- // Export all: export * from 'module'
47
- ExportAllDeclaration(path) {
48
- imports.push(path.node.source.value);
49
- },
50
- // CommonJS require: const x = require('module')
51
- CallExpression(path) {
52
- if (
53
- path.node.callee.type === 'Identifier' &&
54
- path.node.callee.name === 'require' &&
55
- path.node.arguments[0] &&
56
- path.node.arguments[0].type === 'StringLiteral'
57
- ) {
58
- imports.push(path.node.arguments[0].value);
59
- }
60
- }
61
- });
62
- } catch (error) {
63
- // Silently skip files with parse errors
64
- // Most errors are from node_modules or generated files
65
- }
66
-
67
- // Remove duplicates
68
- return [...new Set(imports)];
69
- }
@@ -1,23 +0,0 @@
1
- import { parse as parseSFC } from "@vue/compiler-sfc";
2
- import { extractImports } from "./parseJS";
3
- import { extractTemplateComponents } from "./parseVueTemplate";
4
-
5
- export function parseVue(code: string) {
6
- try {
7
- const { descriptor } = parseSFC(code);
8
-
9
- const scriptContent = descriptor.script?.content || '';
10
- const scriptSetupContent = descriptor.scriptSetup?.content || '';
11
- const allScript = scriptContent + '\n' + scriptSetupContent;
12
-
13
- return {
14
- imports: allScript.trim() ? extractImports(allScript) : [],
15
- components: extractTemplateComponents(code)
16
- };
17
- } catch (error) {
18
- return {
19
- imports: [],
20
- components: []
21
- };
22
- }
23
- }
@@ -1,16 +0,0 @@
1
- import { parse as parseSFC } from "@vue/compiler-sfc";
2
-
3
- export function extractTemplateComponents(code: string): string[] {
4
- const { descriptor } = parseSFC(code);
5
- const template = descriptor.template?.content || "";
6
-
7
- const componentRegex = /<([A-Z][\w-]*)/g;
8
- const components = new Set<string>();
9
-
10
- let match;
11
- while ((match = componentRegex.exec(template))) {
12
- components.add(match[1]);
13
- }
14
-
15
- return Array.from(components);
16
- }
@@ -1,25 +0,0 @@
1
- import fg from "fast-glob";
2
- import path from "path";
3
-
4
- export async function scanRepo(): Promise<string[]> {
5
- try {
6
- const files = await fg("**/*.{js,jsx,ts,tsx,vue}", {
7
- ignore: [
8
- "node_modules/**",
9
- "dist/**",
10
- "build/**",
11
- "*.min.js",
12
- "**/*.min.js",
13
- ".next/**",
14
- "coverage/**",
15
- ".cache/**",
16
- "out/**",
17
- ".nuxt/**"
18
- ]
19
- });
20
-
21
- return files.map(file => path.resolve(process.cwd(), file));
22
- } catch (error) {
23
- throw new Error(`Failed to scan repository: ${error instanceof Error ? error.message : String(error)}`);
24
- }
25
- }
package/tsconfig.json DELETED
@@ -1,10 +0,0 @@
1
- {
2
- "compilerOptions": {
3
- "target": "ES2020",
4
- "module": "CommonJS",
5
- "outDir": "dist",
6
- "rootDir": "src",
7
- "strict": true,
8
- "esModuleInterop": true
9
- }
10
- }