fileflows 1.0.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 +105 -0
- package/cli.js +80 -0
- package/config/localVars.js +48 -0
- package/config/localVars.test.js +37 -0
- package/index.js +8 -0
- package/lib/SUMMARY.md +53 -0
- package/lib/dataFlowGrouper.js +150 -0
- package/lib/dataFlowGrouper.test.js +17 -0
- package/lib/dependencyExtractor.js +70 -0
- package/lib/dependencyExtractor.test.js +9 -0
- package/lib/fileClassifier.js +38 -0
- package/lib/fileClassifier.test.js +9 -0
- package/lib/fileFlowsGenerator.js +141 -0
- package/lib/fileFlowsGenerator.test.js +17 -0
- package/lib/fileIO.js +55 -0
- package/lib/fileIO.test.js +13 -0
- package/lib/graphUtils.js +139 -0
- package/lib/graphUtils.test.js +25 -0
- package/lib/index.js +37 -0
- package/lib/index.test.js +53 -0
- package/lib/jsParser.js +127 -0
- package/lib/jsParser.test.js +13 -0
- package/lib/otherFileParser.js +103 -0
- package/lib/otherFileParser.test.js +9 -0
- package/package.json +74 -0
package/README.md
ADDED
|
@@ -0,0 +1,105 @@
|
|
|
1
|
+
# File Flows CLI
|
|
2
|
+
|
|
3
|
+
A CLI tool for generating `FILE_FLOWS.md` - analyzes project files and creates comprehensive documentation showing data flow relationships.
|
|
4
|
+
|
|
5
|
+
[](https://badge.fury.io/js/file-flows-cli)
|
|
6
|
+
[](https://opensource.org/licenses/Apache-2.0)
|
|
7
|
+
|
|
8
|
+
## Features
|
|
9
|
+
|
|
10
|
+
- **Smart File Grouping**: Groups files by actual data flow relationships (imports/exports) as the primary method
|
|
11
|
+
- **Fallback Naming**: Uses filename similarity for files without clear data flow connections
|
|
12
|
+
- **Comprehensive Analysis**: Supports JavaScript, TypeScript, JSON, Markdown, YAML, HTML, CSS, and more
|
|
13
|
+
- **AST Parsing**: Deep analysis of JavaScript/TypeScript files to extract imports, exports, functions, and components
|
|
14
|
+
- **Clean Output**: Generates well-formatted Markdown documentation
|
|
15
|
+
|
|
16
|
+
## Installation
|
|
17
|
+
|
|
18
|
+
### Global Installation (Recommended)
|
|
19
|
+
```bash
|
|
20
|
+
npm install -g file-flows-cli
|
|
21
|
+
```
|
|
22
|
+
|
|
23
|
+
### Local Installation
|
|
24
|
+
```bash
|
|
25
|
+
npm install file-flows-cli
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
### Development/Direct Use
|
|
29
|
+
```bash
|
|
30
|
+
npm install @babel/parser globby
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
## Usage
|
|
34
|
+
|
|
35
|
+
### Global Installation
|
|
36
|
+
```bash
|
|
37
|
+
# Analyze current directory (generates FILE_FLOWS.md)
|
|
38
|
+
file-flows
|
|
39
|
+
|
|
40
|
+
# Analyze specific directory
|
|
41
|
+
file-flows --dir ./src
|
|
42
|
+
|
|
43
|
+
# Custom output file
|
|
44
|
+
file-flows --output my-flows.md
|
|
45
|
+
|
|
46
|
+
# Show help
|
|
47
|
+
file-flows --help
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
### Local Installation
|
|
51
|
+
```bash
|
|
52
|
+
# Using npx
|
|
53
|
+
npx file-flows
|
|
54
|
+
|
|
55
|
+
# Using npm scripts
|
|
56
|
+
npm run file-flows
|
|
57
|
+
|
|
58
|
+
# Direct node execution
|
|
59
|
+
node node_modules/file-flows-cli/cli-file-flows.js
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
## How It Works
|
|
63
|
+
|
|
64
|
+
1. **File Discovery**: Scans project for all relevant file types, excluding common build/cache directories
|
|
65
|
+
2. **Dependency Analysis**: Parses JavaScript/TypeScript files to extract import/export relationships
|
|
66
|
+
3. **Flow Clustering**: Groups files that share data flow relationships using graph analysis
|
|
67
|
+
4. **Naming Fallback**: Groups remaining files by filename similarity patterns
|
|
68
|
+
5. **Documentation Generation**: Creates comprehensive Markdown with file metadata
|
|
69
|
+
|
|
70
|
+
## File Types Supported
|
|
71
|
+
|
|
72
|
+
- **Code**: `.js`, `.ts`, `.jsx`, `.tsx`
|
|
73
|
+
- **Config**: `.json`, `.yml`, `.yaml`, `.env`
|
|
74
|
+
- **Documentation**: `.md`
|
|
75
|
+
- **Web**: `.html`, `.css`, `.scss`
|
|
76
|
+
- **Other**: `.sh`, `.graphql`
|
|
77
|
+
|
|
78
|
+
## Output Format
|
|
79
|
+
|
|
80
|
+
The generated `FILE_FLOWS.md` includes:
|
|
81
|
+
|
|
82
|
+
- Flow groups based on actual relationships
|
|
83
|
+
- File type classification
|
|
84
|
+
- Extracted metadata (imports, exports, functions, etc.)
|
|
85
|
+
- Clear structure for understanding project architecture
|
|
86
|
+
|
|
87
|
+
## Example Output
|
|
88
|
+
|
|
89
|
+
```markdown
|
|
90
|
+
# FILE_FLOWS
|
|
91
|
+
> Auto-generated. Do not edit directly.
|
|
92
|
+
> Files grouped by PRIMARY: actual data flow relationships, SECONDARY: filename similarity.
|
|
93
|
+
|
|
94
|
+
### 🧩 Flow Group: `auth-flow`
|
|
95
|
+
|
|
96
|
+
## [1] `src/auth/login.js`
|
|
97
|
+
**Type:** Feature Logic/UI
|
|
98
|
+
**Imports:** ./auth-api, ./validators
|
|
99
|
+
**Exports:** LoginComponent, validateLogin
|
|
100
|
+
**Functions:** LoginComponent, validateLogin, handleSubmit
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
This tool preserves all the sophisticated analysis capabilities of the original system while providing a clean, focused CLI interface.
|
package/cli.js
ADDED
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* CLI tool for generating FILE_FLOWS.md
|
|
4
|
+
* Analyzes project files and creates documentation showing data flow relationships
|
|
5
|
+
* Following NPM architecture guidelines with modular structure
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
const generateFileFlows = require(`./lib/fileFlowsGenerator`);
|
|
9
|
+
const localVars = require(`./config/localVars`);
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* CLI usage display functionality
|
|
13
|
+
* Shows help information for the CLI tool
|
|
14
|
+
*/
|
|
15
|
+
function showUsage() {
|
|
16
|
+
console.log(`Usage: node cli.js [options]`);
|
|
17
|
+
console.log(``);
|
|
18
|
+
console.log(`Options:`);
|
|
19
|
+
console.log(` --dir <path> Directory to analyze (default: current directory)`);
|
|
20
|
+
console.log(` --output <file> Output file path (default: FILE_FLOWS.md)`);
|
|
21
|
+
console.log(` --help, -h Show this help message`);
|
|
22
|
+
console.log(``);
|
|
23
|
+
console.log(`Examples:`);
|
|
24
|
+
console.log(` node cli.js # Analyze current directory`);
|
|
25
|
+
console.log(` node cli.js --dir ./src # Analyze src directory`);
|
|
26
|
+
console.log(` node cli.js --output flows.md # Custom output file`);
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* Main CLI logic
|
|
31
|
+
* Parses arguments and executes file flows generation
|
|
32
|
+
*/
|
|
33
|
+
async function main() {
|
|
34
|
+
const args = process.argv.slice(2);
|
|
35
|
+
let rootDir = localVars.DEFAULT_ROOT_DIR;
|
|
36
|
+
let outputFile = null;
|
|
37
|
+
|
|
38
|
+
for (let i = 0; i < args.length; i++) {
|
|
39
|
+
const arg = args[i];
|
|
40
|
+
|
|
41
|
+
if (arg === `--help` || arg === `-h`) {
|
|
42
|
+
showUsage();
|
|
43
|
+
process.exit(0);
|
|
44
|
+
} else if (arg === `--dir`) {
|
|
45
|
+
if (i + 1 < args.length) {
|
|
46
|
+
rootDir = args[++i];
|
|
47
|
+
} else {
|
|
48
|
+
console.error(`Error: --dir requires a directory path`);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
}
|
|
51
|
+
} else if (arg === `--output`) {
|
|
52
|
+
if (i + 1 < args.length) {
|
|
53
|
+
outputFile = args[++i];
|
|
54
|
+
} else {
|
|
55
|
+
console.error(`Error: --output requires a file path`);
|
|
56
|
+
process.exit(1);
|
|
57
|
+
}
|
|
58
|
+
} else {
|
|
59
|
+
console.error(`Error: Unknown argument '${arg}'`);
|
|
60
|
+
showUsage();
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
try {
|
|
66
|
+
console.log(`🚀 Generating FILE_FLOWS.md...`);
|
|
67
|
+
await generateFileFlows(rootDir, outputFile);
|
|
68
|
+
console.log(`🎉 Generation complete!`);
|
|
69
|
+
} catch (error) {
|
|
70
|
+
console.error(`❌ Error:`, error.message);
|
|
71
|
+
process.exit(1);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Run if called directly
|
|
76
|
+
if (require.main === module) {
|
|
77
|
+
main().catch(console.error);
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
module.exports = { showUsage, main };
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Configuration constants and environment variables
|
|
3
|
+
* Single source of truth for all hardcoded values in the application
|
|
4
|
+
* Following NPM architecture guidelines - DO NOT modify existing values
|
|
5
|
+
*/
|
|
6
|
+
// 🚩AI: MUST_UPDATE_IF_FILE_EXTENSIONS_CHANGE
|
|
7
|
+
|
|
8
|
+
// === FILE ANALYSIS CONSTANTS ===
|
|
9
|
+
const CODE_EXTENSIONS = [`js`, `ts`, `jsx`, `tsx`];
|
|
10
|
+
const ALL_EXTENSIONS = [...CODE_EXTENSIONS, `json`, `md`, `yml`, `yaml`, `env`, `html`, `css`, `scss`, `sh`, `graphql`];
|
|
11
|
+
|
|
12
|
+
// === DEFAULT PATHS ===
|
|
13
|
+
const DEFAULT_ROOT_DIR = `.`;
|
|
14
|
+
const DEFAULT_OUTPUT_FILE = `FILE_FLOWS.md`;
|
|
15
|
+
|
|
16
|
+
// === GITIGNORE PATTERNS ===
|
|
17
|
+
const IGNORE_PATTERNS = [
|
|
18
|
+
`**/node_modules/**`,
|
|
19
|
+
`**/.config/**`,
|
|
20
|
+
`**/logs/**`,
|
|
21
|
+
`**/.git/**`,
|
|
22
|
+
`**/tmp/**`,
|
|
23
|
+
`**/temp/**`,
|
|
24
|
+
`**/.npm/**`,
|
|
25
|
+
`**/.cache/**`,
|
|
26
|
+
`**/dist/**`,
|
|
27
|
+
`**/build/**`,
|
|
28
|
+
`**/.next/**`,
|
|
29
|
+
`**/.nuxt/**`
|
|
30
|
+
];
|
|
31
|
+
|
|
32
|
+
// === PARSING LIMITS ===
|
|
33
|
+
const MAX_JSON_KEYS = 10;
|
|
34
|
+
const MAX_YAML_KEYS = 5;
|
|
35
|
+
const MAX_SHELL_COMMANDS = 5;
|
|
36
|
+
const MAX_HTML_TAGS = 5;
|
|
37
|
+
|
|
38
|
+
module.exports = {
|
|
39
|
+
CODE_EXTENSIONS,
|
|
40
|
+
ALL_EXTENSIONS,
|
|
41
|
+
DEFAULT_ROOT_DIR,
|
|
42
|
+
DEFAULT_OUTPUT_FILE,
|
|
43
|
+
IGNORE_PATTERNS,
|
|
44
|
+
MAX_JSON_KEYS,
|
|
45
|
+
MAX_YAML_KEYS,
|
|
46
|
+
MAX_SHELL_COMMANDS,
|
|
47
|
+
MAX_HTML_TAGS
|
|
48
|
+
};
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
// Auto-generated unit test for localVars.js - optimized for speed
|
|
2
|
+
const mod = require('./localVars.js');
|
|
3
|
+
|
|
4
|
+
describe('localVars.js', () => {
|
|
5
|
+
test('CODE_EXTENSIONS works', async () => {
|
|
6
|
+
// Fast assertion - TODO: implement specific test logic
|
|
7
|
+
expect(typeof mod.CODE_EXTENSIONS).toBeDefined();
|
|
8
|
+
});
|
|
9
|
+
test('ALL_EXTENSIONS works', async () => {
|
|
10
|
+
// Fast assertion - TODO: implement specific test logic
|
|
11
|
+
expect(typeof mod.ALL_EXTENSIONS).toBeDefined();
|
|
12
|
+
});
|
|
13
|
+
test('DEFAULT_ROOT_DIR works', async () => {
|
|
14
|
+
// Fast assertion - TODO: implement specific test logic
|
|
15
|
+
expect(typeof mod.DEFAULT_ROOT_DIR).toBeDefined();
|
|
16
|
+
});
|
|
17
|
+
test('DEFAULT_OUTPUT_FILE works', async () => {
|
|
18
|
+
// Fast assertion - TODO: implement specific test logic
|
|
19
|
+
expect(typeof mod.DEFAULT_OUTPUT_FILE).toBeDefined();
|
|
20
|
+
});
|
|
21
|
+
test('IGNORE_PATTERNS works', async () => {
|
|
22
|
+
// Fast assertion - TODO: implement specific test logic
|
|
23
|
+
expect(typeof mod.IGNORE_PATTERNS).toBeDefined();
|
|
24
|
+
});
|
|
25
|
+
test('MAX_JSON_KEYS works', async () => {
|
|
26
|
+
// Fast assertion - TODO: implement specific test logic
|
|
27
|
+
expect(typeof mod.MAX_JSON_KEYS).toBeDefined();
|
|
28
|
+
});
|
|
29
|
+
test('MAX_YAML_KEYS works', async () => {
|
|
30
|
+
// Fast assertion - TODO: implement specific test logic
|
|
31
|
+
expect(typeof mod.MAX_YAML_KEYS).toBeDefined();
|
|
32
|
+
});
|
|
33
|
+
test('MAX_SHELL_COMMANDS works', async () => {
|
|
34
|
+
// Fast assertion - TODO: implement specific test logic
|
|
35
|
+
expect(typeof mod.MAX_SHELL_COMMANDS).toBeDefined();
|
|
36
|
+
});
|
|
37
|
+
});
|
package/index.js
ADDED
package/lib/SUMMARY.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# lib/ Directory Summary
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
Core library modules for FILE_FLOWS.md generation, following Single Responsibility Principle with one function per file.
|
|
5
|
+
|
|
6
|
+
## File Roles & Data Flow
|
|
7
|
+
|
|
8
|
+
### Entry Points
|
|
9
|
+
- **index.js** - Main module aggregator, exports all lib functions for external use
|
|
10
|
+
- **fileFlowsGenerator.js** - Primary orchestrator, coordinates analysis and output generation
|
|
11
|
+
|
|
12
|
+
### Analysis Pipeline
|
|
13
|
+
1. **fileClassifier.js** - Classifies files by type (Code, Configuration, Documentation, etc.)
|
|
14
|
+
2. **jsParser.js** - AST parsing for JavaScript/TypeScript files, extracts functions and imports
|
|
15
|
+
3. **otherFileParser.js** - Simple parsing for non-JS files (JSON, MD, etc.)
|
|
16
|
+
4. **dependencyExtractor.js** - Extracts import/require dependencies from file content
|
|
17
|
+
|
|
18
|
+
### Grouping & Output
|
|
19
|
+
5. **dataFlowGrouper.js** - Groups files by actual data flow relationships and naming patterns
|
|
20
|
+
|
|
21
|
+
## Request/Response Flows
|
|
22
|
+
|
|
23
|
+
### Main Generation Flow
|
|
24
|
+
```
|
|
25
|
+
generateFileFlows(rootDir, outputFile)
|
|
26
|
+
├── globby scan for files
|
|
27
|
+
├── groupByDataFlow(files, rootDir)
|
|
28
|
+
│ ├── classifyFile(filePath, ext) for each file
|
|
29
|
+
│ ├── parseJSFile(filePath, content) OR parseOtherFile(filePath, content)
|
|
30
|
+
│ ├── extractDependencies(content) for dependency mapping
|
|
31
|
+
│ └── clustering algorithms for flow grouping
|
|
32
|
+
└── markdown output generation
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
### Data Dependencies
|
|
36
|
+
- **config/localVars.js** - Centralized constants (file extensions, ignore patterns, etc.)
|
|
37
|
+
- **External**: globby (file discovery), @babel/parser & @babel/traverse (AST parsing)
|
|
38
|
+
|
|
39
|
+
## Known Side Effects
|
|
40
|
+
- **File System**: Reads all project files matching configured extensions
|
|
41
|
+
- **Output**: Overwrites FILE_FLOWS.md without backup
|
|
42
|
+
- **Memory**: Processes entire project file tree in memory
|
|
43
|
+
- **Performance**: AST parsing scales with codebase size
|
|
44
|
+
|
|
45
|
+
## Edge Cases & Caveats
|
|
46
|
+
- **Large Projects**: Memory usage grows with file count and complexity
|
|
47
|
+
- **Binary Files**: Ignored via gitignore patterns but may cause issues if included
|
|
48
|
+
- **Circular Dependencies**: Detected but may create complex flow groups
|
|
49
|
+
- **ES Modules vs CommonJS**: Mixed module systems handled via dynamic imports
|
|
50
|
+
- **Parse Errors**: Individual file failures don't stop overall generation
|
|
51
|
+
|
|
52
|
+
## AI Agent Task Anchors
|
|
53
|
+
See individual files for specific `// 🚩AI:` markers indicating critical update points.
|
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Data flow grouping functionality
|
|
3
|
+
* Groups files by actual data flow relationships (imports/exports)
|
|
4
|
+
* @param {Array} fileList - List of files to analyze
|
|
5
|
+
* @param {string} rootDir - Root directory path
|
|
6
|
+
* @returns {Promise<Map>} Map of grouped files by data flow relationships
|
|
7
|
+
*/
|
|
8
|
+
// 🚩AI: CORE_DATA_FLOW_ANALYSIS_ALGORITHM
|
|
9
|
+
async function groupByDataFlow(fileList, rootDir) {
|
|
10
|
+
const fs = require(`fs`);
|
|
11
|
+
const path = require(`path`);
|
|
12
|
+
const localVars = require(`../config/localVars`);
|
|
13
|
+
const parseJSFile = require(`./jsParser`);
|
|
14
|
+
const parseOtherFile = require(`./otherFileParser`);
|
|
15
|
+
const classifyFile = require(`./fileClassifier`);
|
|
16
|
+
const extractDependencies = require(`./dependencyExtractor`);
|
|
17
|
+
|
|
18
|
+
const dependencyGraph = new Map();
|
|
19
|
+
const fileMetadata = new Map();
|
|
20
|
+
|
|
21
|
+
// Build dependency graph by analyzing imports/exports
|
|
22
|
+
for (const filePath of fileList) {
|
|
23
|
+
const fullPath = path.join(rootDir, filePath);
|
|
24
|
+
const ext = path.extname(filePath).slice(1);
|
|
25
|
+
|
|
26
|
+
try {
|
|
27
|
+
const content = fs.readFileSync(fullPath, `utf8`);
|
|
28
|
+
let metadata = {};
|
|
29
|
+
|
|
30
|
+
if (localVars.CODE_EXTENSIONS.includes(ext)) {
|
|
31
|
+
metadata = parseJSFile(content, filePath);
|
|
32
|
+
} else {
|
|
33
|
+
metadata = parseOtherFile(content, filePath, ext);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
fileMetadata.set(filePath, {
|
|
37
|
+
...metadata,
|
|
38
|
+
type: classifyFile(filePath, ext),
|
|
39
|
+
dependencies: extractDependencies(metadata.Imports || [], filePath, fileList)
|
|
40
|
+
});
|
|
41
|
+
|
|
42
|
+
dependencyGraph.set(filePath, metadata.Imports || []);
|
|
43
|
+
} catch (error) {
|
|
44
|
+
// File read error - skip this file
|
|
45
|
+
dependencyGraph.set(filePath, []);
|
|
46
|
+
}
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Group files by connected components in dependency graph
|
|
50
|
+
const visited = new Set();
|
|
51
|
+
const groups = new Map();
|
|
52
|
+
let groupCounter = 1;
|
|
53
|
+
|
|
54
|
+
function dfs(file, groupName, group) {
|
|
55
|
+
if (visited.has(file)) return;
|
|
56
|
+
visited.add(file);
|
|
57
|
+
group.push(file);
|
|
58
|
+
|
|
59
|
+
// Visit all files that this file imports
|
|
60
|
+
const deps = fileMetadata.get(file)?.dependencies || [];
|
|
61
|
+
for (const dep of deps) {
|
|
62
|
+
if (!visited.has(dep)) {
|
|
63
|
+
dfs(dep, groupName, group);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// Visit all files that import this file
|
|
68
|
+
for (const [otherFile, otherDeps] of fileMetadata) {
|
|
69
|
+
if (!visited.has(otherFile) && otherDeps.dependencies?.includes(file)) {
|
|
70
|
+
dfs(otherFile, groupName, group);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
// Create connected components
|
|
76
|
+
for (const file of fileList) {
|
|
77
|
+
if (!visited.has(file)) {
|
|
78
|
+
const group = [];
|
|
79
|
+
const groupName = `Group-${groupCounter++}`;
|
|
80
|
+
dfs(file, groupName, group);
|
|
81
|
+
|
|
82
|
+
if (group.length > 0) {
|
|
83
|
+
groups.set(groupName, group);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
// SECONDARY: Use filename similarity for files without clear connections
|
|
89
|
+
const ungroupedFiles = fileList.filter(f => !visited.has(f));
|
|
90
|
+
if (ungroupedFiles.length > 0) {
|
|
91
|
+
const similarityGroups = groupBySimilarity(ungroupedFiles);
|
|
92
|
+
for (const [name, files] of similarityGroups) {
|
|
93
|
+
groups.set(`Similarity-${name}`, files);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
// Convert Map to Array format expected by tests
|
|
98
|
+
const groupArray = [];
|
|
99
|
+
for (const [groupName, files] of groups) {
|
|
100
|
+
groupArray.push({
|
|
101
|
+
name: groupName,
|
|
102
|
+
files: files,
|
|
103
|
+
metadata: files.map(f => fileMetadata.get(f)).filter(Boolean)
|
|
104
|
+
});
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return groupArray;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Groups files by filename similarity when no data flow connections exist
|
|
112
|
+
* @param {Array} files - Array of file paths
|
|
113
|
+
* @returns {Map} Map of similarity-based groups
|
|
114
|
+
*/
|
|
115
|
+
function groupBySimilarity(files) {
|
|
116
|
+
const path = require(`path`);
|
|
117
|
+
const groups = new Map();
|
|
118
|
+
|
|
119
|
+
for (const file of files) {
|
|
120
|
+
const basename = path.basename(file, path.extname(file));
|
|
121
|
+
const parts = basename.split(/[-_.]/).filter(p => p.length > 2);
|
|
122
|
+
|
|
123
|
+
let bestGroup = null;
|
|
124
|
+
let maxSimilarity = 0;
|
|
125
|
+
|
|
126
|
+
for (const [groupName, groupFiles] of groups) {
|
|
127
|
+
const groupBasename = path.basename(groupFiles[0], path.extname(groupFiles[0]));
|
|
128
|
+
const groupParts = groupBasename.split(/[-_.]/).filter(p => p.length > 2);
|
|
129
|
+
|
|
130
|
+
const commonParts = parts.filter(p => groupParts.includes(p));
|
|
131
|
+
const similarity = commonParts.length / Math.max(parts.length, groupParts.length);
|
|
132
|
+
|
|
133
|
+
if (similarity > maxSimilarity && similarity > 0.3) {
|
|
134
|
+
maxSimilarity = similarity;
|
|
135
|
+
bestGroup = groupName;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
if (bestGroup) {
|
|
140
|
+
groups.get(bestGroup).push(file);
|
|
141
|
+
} else {
|
|
142
|
+
const key = parts.length > 0 ? parts[0] : basename;
|
|
143
|
+
groups.set(key, [file]);
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
return groups;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
module.exports = groupByDataFlow;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
// Auto-generated unit test for dataFlowGrouper.js - optimized for speed
|
|
2
|
+
const mod = require('./dataFlowGrouper.js');
|
|
3
|
+
|
|
4
|
+
describe('dataFlowGrouper.js', () => {
|
|
5
|
+
test('groupByDataFlow works', async () => {
|
|
6
|
+
// Fast assertion - TODO: implement specific test logic
|
|
7
|
+
expect(typeof mod.groupByDataFlow).toBeDefined();
|
|
8
|
+
});
|
|
9
|
+
test('dfs works', async () => {
|
|
10
|
+
// Fast assertion - TODO: implement specific test logic
|
|
11
|
+
expect(typeof mod.dfs).toBeDefined();
|
|
12
|
+
});
|
|
13
|
+
test('groupBySimilarity works', async () => {
|
|
14
|
+
// Fast assertion - TODO: implement specific test logic
|
|
15
|
+
expect(typeof mod.groupBySimilarity).toBeDefined();
|
|
16
|
+
});
|
|
17
|
+
});
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dependency extraction functionality
|
|
3
|
+
* Extracts and resolves file dependencies from import statements
|
|
4
|
+
* @param {Array} imports - Array of import statements
|
|
5
|
+
* @param {string} currentFile - Current file path
|
|
6
|
+
* @param {Array} fileList - List of all files in the project
|
|
7
|
+
* @returns {Array} Array of resolved dependencies
|
|
8
|
+
*/
|
|
9
|
+
function extractDependencies(imports, currentFile, fileList) {
|
|
10
|
+
const path = require(`path`);
|
|
11
|
+
const dependencies = [];
|
|
12
|
+
|
|
13
|
+
for (const imp of imports) {
|
|
14
|
+
if (imp.startsWith(`.`)) {
|
|
15
|
+
// Relative import - try to resolve to actual file
|
|
16
|
+
const basePath = path.dirname(currentFile);
|
|
17
|
+
let resolvedPath = path.normalize(path.join(basePath, imp));
|
|
18
|
+
|
|
19
|
+
// Convert to forward slashes for cross-platform compatibility
|
|
20
|
+
resolvedPath = resolvedPath.replace(/\\/g, '/');
|
|
21
|
+
|
|
22
|
+
// Handle different resolution scenarios:
|
|
23
|
+
// If resolvedPath starts with project structure, normalize it
|
|
24
|
+
// Remove src/ prefix if it exists and the target doesn't include it
|
|
25
|
+
const pathParts = resolvedPath.split('/');
|
|
26
|
+
|
|
27
|
+
// Try original resolved path first, then variations
|
|
28
|
+
const possibleBasePaths = [
|
|
29
|
+
resolvedPath,
|
|
30
|
+
// Remove 'src/' prefix if present
|
|
31
|
+
pathParts[0] === 'src' ? pathParts.slice(1).join('/') : null,
|
|
32
|
+
// Handle cases where path goes up from src/
|
|
33
|
+
resolvedPath.replace(/^src\//, '')
|
|
34
|
+
].filter(p => p && p !== resolvedPath); // Remove nulls and duplicates
|
|
35
|
+
|
|
36
|
+
const allPossiblePaths = [resolvedPath, ...possibleBasePaths];
|
|
37
|
+
|
|
38
|
+
// Try to find matching file with common extensions for each base path
|
|
39
|
+
for (const basePath of allPossiblePaths) {
|
|
40
|
+
if (!basePath) continue;
|
|
41
|
+
|
|
42
|
+
const possiblePaths = [
|
|
43
|
+
basePath,
|
|
44
|
+
basePath + `.js`,
|
|
45
|
+
basePath + `.ts`,
|
|
46
|
+
basePath + `.jsx`,
|
|
47
|
+
basePath + `.tsx`,
|
|
48
|
+
basePath + `/index.js`,
|
|
49
|
+
basePath + `/index.ts`
|
|
50
|
+
];
|
|
51
|
+
|
|
52
|
+
for (const possiblePath of possiblePaths) {
|
|
53
|
+
if (fileList.includes(possiblePath)) {
|
|
54
|
+
dependencies.push(possiblePath);
|
|
55
|
+
break;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
// If we found a match, stop looking
|
|
60
|
+
if (dependencies.some(dep => allPossiblePaths.some(base => dep.startsWith(base)))) {
|
|
61
|
+
break;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
return dependencies;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
module.exports = extractDependencies;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Auto-generated unit test for dependencyExtractor.js - optimized for speed
|
|
2
|
+
const mod = require('./dependencyExtractor.js');
|
|
3
|
+
|
|
4
|
+
describe('dependencyExtractor.js', () => {
|
|
5
|
+
test('extractDependencies works', async () => {
|
|
6
|
+
// Fast assertion - TODO: implement specific test logic
|
|
7
|
+
expect(typeof mod.extractDependencies).toBeDefined();
|
|
8
|
+
});
|
|
9
|
+
});
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* File classification functionality
|
|
3
|
+
* Classifies files based on their path and extension
|
|
4
|
+
* @param {string} filePath - The file path to classify
|
|
5
|
+
* @param {string} ext - The file extension
|
|
6
|
+
* @returns {string} Classification of the file type
|
|
7
|
+
*/
|
|
8
|
+
function classifyFile(filePath, ext) {
|
|
9
|
+
const localVars = require(`../config/localVars`);
|
|
10
|
+
|
|
11
|
+
if (localVars.CODE_EXTENSIONS.includes(ext)) {
|
|
12
|
+
// TSX files are specifically React/UI components (check first)
|
|
13
|
+
if (ext === `tsx`) return `UI Component`;
|
|
14
|
+
if (filePath.includes(`test`) || filePath.includes(`spec`)) return `Test File`;
|
|
15
|
+
if (filePath.includes(`component`) || filePath.includes(`Component`)) return `UI Component`;
|
|
16
|
+
if (filePath.includes(`api`) || filePath.includes(`route`)) return `API/Route`;
|
|
17
|
+
if (filePath.includes(`util`) || filePath.includes(`helper`)) return `Utility`;
|
|
18
|
+
if (filePath.includes(`config`) || filePath.includes(`setting`)) return `Configuration`;
|
|
19
|
+
if (filePath.includes(`model`) || filePath.includes(`schema`)) return `Data Model`;
|
|
20
|
+
return `Code File`;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
switch (ext) {
|
|
24
|
+
case `json`: return `Configuration/Data`;
|
|
25
|
+
case `md`: return `Documentation`;
|
|
26
|
+
case `yml`:
|
|
27
|
+
case `yaml`: return `Configuration`;
|
|
28
|
+
case `env`: return `Environment`;
|
|
29
|
+
case `html`: return `Template/View`;
|
|
30
|
+
case `css`:
|
|
31
|
+
case `scss`: return `Stylesheet`;
|
|
32
|
+
case `sh`: return `Script`;
|
|
33
|
+
case `graphql`: return `Schema`;
|
|
34
|
+
default: return `Other`;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = classifyFile;
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
// Auto-generated unit test for fileClassifier.js - optimized for speed
|
|
2
|
+
const mod = require('./fileClassifier.js');
|
|
3
|
+
|
|
4
|
+
describe('fileClassifier.js', () => {
|
|
5
|
+
test('classifyFile works', async () => {
|
|
6
|
+
// Fast assertion - TODO: implement specific test logic
|
|
7
|
+
expect(typeof mod.classifyFile).toBeDefined();
|
|
8
|
+
});
|
|
9
|
+
});
|