fileflows 1.0.3 → 1.0.5

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.
Files changed (51) hide show
  1. package/README.md +19 -11
  2. package/cli.mjs +7 -0
  3. package/config/jest-require-polyfill.cjs +20 -0
  4. package/config/jest-setup.mjs +28 -0
  5. package/config/jest.config.mjs +72 -0
  6. package/config/localVars.js +2 -109
  7. package/dist/cli.js +76 -0
  8. package/dist/config/localVars.js +76 -0
  9. package/dist/index.js +7 -0
  10. package/dist/lib/dataFlowGrouper.js +137 -0
  11. package/dist/lib/dependencyExtractor.js +46 -0
  12. package/dist/lib/fileClassifier.js +78 -0
  13. package/dist/lib/fileFlowsGenerator.js +301 -0
  14. package/dist/lib/fileIO.js +35 -0
  15. package/dist/lib/graphUtils.js +89 -0
  16. package/dist/lib/index.js +50 -0
  17. package/dist/lib/jsParser.js +131 -0
  18. package/dist/lib/otherFileParser.js +131 -0
  19. package/index.mjs +2 -0
  20. package/package.json +31 -14
  21. package/scripts/broadcast.sh +26 -0
  22. package/scripts/clean-bun-cache.mjs +14 -0
  23. package/scripts/clean-dist.mjs +7 -0
  24. package/scripts/ensure-runner.mjs +9 -0
  25. package/scripts/kill-agent.sh +24 -0
  26. package/scripts/kill-all-agents.sh +31 -0
  27. package/scripts/list-agents.sh +16 -0
  28. package/scripts/send-to-agent.sh +28 -0
  29. package/scripts/spawn-agent.sh +62 -0
  30. package/cli.js +0 -81
  31. package/config/localVars.test.js +0 -37
  32. package/index.js +0 -13
  33. package/lib/SUMMARY.md +0 -53
  34. package/lib/dataFlowGrouper.js +0 -150
  35. package/lib/dataFlowGrouper.test.js +0 -17
  36. package/lib/dependencyExtractor.js +0 -70
  37. package/lib/dependencyExtractor.test.js +0 -9
  38. package/lib/fileClassifier.js +0 -38
  39. package/lib/fileClassifier.test.js +0 -9
  40. package/lib/fileFlowsGenerator.js +0 -156
  41. package/lib/fileFlowsGenerator.test.js +0 -17
  42. package/lib/fileIO.js +0 -60
  43. package/lib/fileIO.test.js +0 -13
  44. package/lib/graphUtils.js +0 -139
  45. package/lib/graphUtils.test.js +0 -25
  46. package/lib/index.js +0 -29
  47. package/lib/index.test.js +0 -53
  48. package/lib/jsParser.js +0 -132
  49. package/lib/jsParser.test.js +0 -13
  50. package/lib/otherFileParser.js +0 -103
  51. package/lib/otherFileParser.test.js +0 -9
package/README.md CHANGED
@@ -56,16 +56,16 @@ npx fileflows
56
56
  npm run generate
57
57
 
58
58
  # Direct node execution
59
- node node_modules/fileflows/cli.js
59
+ node node_modules/fileflows/cli.mjs
60
60
  ```
61
61
 
62
62
  ### Development/Direct Use
63
63
  ```bash
64
64
  # Clone or download the repository, then:
65
- node cli.js # Analyze current directory
66
- node cli.js --dir ./src # Analyze src directory
67
- node cli.js --output flows.md # Custom output file
68
- node cli.js --help # Show help
65
+ node cli.mjs # Analyze current directory
66
+ node cli.mjs --dir ./src # Analyze src directory
67
+ node cli.mjs --output flows.md # Custom output file
68
+ node cli.mjs --help # Show help
69
69
  ```
70
70
 
71
71
  ## How It Works
@@ -92,6 +92,14 @@ The generated `FILE_FLOWS.md` includes:
92
92
  - File type classification
93
93
  - Extracted metadata (imports, exports, functions, etc.)
94
94
  - Clear structure for understanding project architecture
95
+ - Companion `FILE_FLOWS.json` containing the same flow groups, each file's metadata, hints about dominant directories/role scores, and cross-flow dependencies for machine consumption
96
+
97
+ ## Machine-readable Output
98
+
99
+ - Every run now emits `FILE_FLOWS.json` beside `FILE_FLOWS.md`. It mirrors the Markdown groups and provides structured hints that allow downstream agents to identify which files belong together, which directories dominate a flow, how tightly coupled the group is, and what other flows it depends on.
100
+ - When using `--output my-flows.md`, FileFlows also writes `my-flows.json` beside it.
101
+ - Flow numbering matches the Markdown (`Flow Group [n]`) so orchestrators and humans can refer to the same labels.
102
+ - **LLM agents should read `FILE_FLOWS.json` first** before consulting the Markdown. The structured JSON is the authoritative source for machine workflows; treat `FILE_FLOWS.md` as supplemental human-friendly documentation once the JSON is understood.
95
103
 
96
104
  ## Example Output
97
105
 
@@ -100,7 +108,7 @@ The generated `FILE_FLOWS.md` includes:
100
108
  > Auto-generated. Do not edit directly.
101
109
  > Files grouped by PRIMARY: actual data flow relationships, SECONDARY: filename similarity.
102
110
 
103
- ### 🧩 Flow Group: `auth-flow`
111
+ ### 🧩 Flow Group: [1] `auth-flow`
104
112
 
105
113
  ## [1] `src/auth/login.js`
106
114
  **Type:** Feature Logic/UI
@@ -114,7 +122,7 @@ The generated `FILE_FLOWS.md` includes:
114
122
  ## Command Line Options
115
123
 
116
124
  ```
117
- Usage: node cli.js [options]
125
+ Usage: fileflows [options]
118
126
 
119
127
  Options:
120
128
  --dir <path> Directory to analyze (default: current directory)
@@ -122,9 +130,9 @@ Options:
122
130
  --help, -h Show this help message
123
131
 
124
132
  Examples:
125
- node cli.js # Analyze current directory
126
- node cli.js --dir ./src # Analyze src directory
127
- node cli.js --output flows.md # Custom output file
133
+ fileflows # Analyze current directory
134
+ fileflows --dir ./src # Analyze src directory
135
+ fileflows --output flows.md # Custom output file
128
136
  ```
129
137
 
130
- This tool preserves all the sophisticated analysis capabilities of the original system while providing a clean, focused CLI interface.
138
+ This tool preserves all the sophisticated analysis capabilities of the original system while providing a clean, focused CLI interface.
package/cli.mjs ADDED
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env node
2
+ import { main } from './dist/cli.js';
3
+
4
+ main().catch(error => {
5
+ console.error(error);
6
+ process.exit(1);
7
+ });
@@ -0,0 +1,20 @@
1
+ // Ensure a global require exists for ESM tests that use CommonJS require().
2
+ // Executed by Jest via setupFiles BEFORE test files are evaluated.
3
+ try {
4
+ if (typeof global.require === 'undefined') {
5
+ // eslint-disable-next-line @typescript-eslint/no-var-requires
6
+ const { createRequire } = require('module');
7
+ let req;
8
+ try {
9
+ req = createRequire(process.cwd() + '/package.json');
10
+ } catch {
11
+ req = createRequire(__filename);
12
+ }
13
+ Object.defineProperty(global, 'require', {
14
+ value: req,
15
+ writable: false,
16
+ configurable: true,
17
+ enumerable: false,
18
+ });
19
+ }
20
+ } catch {}
@@ -0,0 +1,28 @@
1
+ import 'qtests/setup';
2
+ import { afterEach, beforeAll, jest as jestFromGlobals } from '@jest/globals';
3
+ import { createRequire } from 'module';
4
+
5
+ process.env.NODE_ENV = 'test';
6
+
7
+ const J = jestFromGlobals ?? globalThis.jest;
8
+ if (!globalThis.jest && J) {
9
+ globalThis.jest = J;
10
+ }
11
+
12
+ if (typeof globalThis.require !== 'function') {
13
+ globalThis.require = createRequire(import.meta.url);
14
+ }
15
+
16
+ beforeAll(() => {
17
+ const j = globalThis.jest ?? J;
18
+ if (j && typeof j.setTimeout === 'function') {
19
+ j.setTimeout(10000);
20
+ }
21
+ });
22
+
23
+ afterEach(() => {
24
+ const j = globalThis.jest ?? J;
25
+ if (j && typeof j.clearAllMocks === 'function') {
26
+ j.clearAllMocks();
27
+ }
28
+ });
@@ -0,0 +1,72 @@
1
+ // jest.config.mjs - TypeScript ES Module configuration (React-enabled)
2
+ // Use ESM export to avoid CommonJS issues under "type": "module"
3
+ import path from 'path';
4
+ import { fileURLToPath } from 'url';
5
+ const __filename = fileURLToPath(import.meta.url);
6
+ const __dirname = path.dirname(__filename);
7
+ const PROJECT_ROOT = path.resolve(__dirname, '..');
8
+
9
+ export default {
10
+ preset: 'ts-jest/presets/default-esm',
11
+ rootDir: PROJECT_ROOT,
12
+ testEnvironment: 'node',
13
+ globals: {
14
+ 'ts-jest': {
15
+ useESM: true,
16
+ tsconfig: 'tsconfig.jest.json'
17
+ }
18
+ },
19
+ // Ensure CommonJS require() exists in ESM tests
20
+ setupFiles: [path.join(PROJECT_ROOT, 'config', 'jest-require-polyfill.cjs')],
21
+ setupFilesAfterEnv: [path.join(PROJECT_ROOT, 'config', 'jest-setup.mjs')],
22
+ roots: [PROJECT_ROOT],
23
+ testMatch: [
24
+ "**/*.test.ts",
25
+ "**/*.test.tsx",
26
+ "**/*.spec.ts",
27
+ "**/*.spec.tsx",
28
+ "**/*.GenerateTest.test.ts",
29
+ "**/*.GenerateTest.test.tsx",
30
+ "**/*.GeneratedTest.test.ts",
31
+ "**/*.GeneratedTest.test.tsx",
32
+ "**/manual-tests/**/*.test.ts",
33
+ "**/generated-tests/**/*GeneratedTest*.test.ts",
34
+ "**/generated-tests/**/*GeneratedTest*.test.tsx"
35
+ ],
36
+ testPathIgnorePatterns: [
37
+ "/node_modules/",
38
+ "/dist/",
39
+ "/build/",
40
+ "/__mocks__/"
41
+ ],
42
+ // Harden ignores to avoid duplicate manual mocks and compiled artifacts
43
+ modulePathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/build/'],
44
+ watchPathIgnorePatterns: ['<rootDir>/dist/', '<rootDir>/build/'],
45
+ moduleFileExtensions: ["ts","tsx","js","jsx","json"],
46
+ transform: {
47
+ "^.+\\.(js|jsx)$": [
48
+ "babel-jest",
49
+ {}
50
+ ]
51
+ },
52
+ extensionsToTreatAsEsm: [".ts",".tsx"],
53
+ transformIgnorePatterns: ['node_modules/(?!(?:qtests|@tanstack|@radix-ui|lucide-react|react-resizable-panels|cmdk|vaul)/)'],
54
+ moduleNameMapper: {
55
+ "^\\.\\./index\\.js$": "<rootDir>/index.ts",
56
+ "^\\.\\./setup\\.js$": "<rootDir>/setup.ts",
57
+ "^\\.\\./lib/(.*)\\.js$": "<rootDir>/lib/$1.ts",
58
+ "^\\.\\./lib/(.*)$": "<rootDir>/lib/$1.ts",
59
+ "^\\.\\./utils/httpTest\\.shim\\.js$": "<rootDir>/utils/httpTest.shim.js",
60
+ "^\\.\\./utils/(.*)\\.js$": "<rootDir>/utils/$1.ts",
61
+ "^(.*/httpTest\\.shim)\\.js$": "$1.js",
62
+ "^external-service-client$": "<rootDir>/utils/jest-proxies/external-service-client.cjs",
63
+ "^feature-x$": "<rootDir>/utils/jest-proxies/feature-x.cjs",
64
+ "^(\\.{1,2}/.*)\\.js$": "$1",
65
+ "^qtests/(.*)$": "<rootDir>/node_modules/qtests/dist/$1.js",
66
+ "^mongoose$": "<rootDir>/__mocks__/mongoose.js",
67
+ "^.+\\\\.(css|less|scss|sass)$": "<rootDir>/__mocks__/fileMock.js",
68
+ "^.+\\\\.(png|jpg|jpeg|gif|svg|webp|avif|ico|bmp)$": "<rootDir>/__mocks__/fileMock.js",
69
+ "^qtests$": "<rootDir>/types/qtests",
70
+ "^qerrors$": "<rootDir>/types/qerrors"
71
+ }
72
+ };
@@ -1,109 +1,2 @@
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
- // === CENTRALIZED DEPENDENCIES ===
39
- // All require statements moved from global scope to centralized configuration
40
- function getDependencies() {
41
- return {
42
- // Core library modules (from lib/index.js)
43
- generateFileFlows: require(`../lib/fileFlowsGenerator`),
44
- groupByDataFlow: require(`../lib/dataFlowGrouper`),
45
- classifyFile: require(`../lib/fileClassifier`),
46
- parseJSFile: require(`../lib/jsParser`),
47
- parseOtherFile: require(`../lib/otherFileParser`),
48
- extractDependencies: require(`../lib/dependencyExtractor`),
49
- fileIO: require(`../lib/fileIO`),
50
- graphUtils: require(`../lib/graphUtils`),
51
-
52
- // System dependencies (from qtests-runner.js)
53
- fs: require(`fs`),
54
- path: require(`path`),
55
- childProcess: require(`child_process`),
56
- os: require(`os`)
57
- };
58
- }
59
-
60
- // === DEVELOPMENT DEPENDENCIES ===
61
- // Async loading for ES module dependencies (qtests is an ES module)
62
- async function getDevDependencies() {
63
- // Check if this is a development environment and qtests is available
64
- if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
65
- try {
66
- // Use dynamic import for ES modules
67
- const qtests = await import('qtests');
68
- return {
69
- qtests: qtests
70
- };
71
- } catch (error) {
72
- // qtests not available
73
- return {
74
- qtests: null
75
- };
76
- }
77
- }
78
-
79
- // Production environment - don't load qtests at all
80
- return {
81
- qtests: null
82
- };
83
- }
84
-
85
- // === ENVIRONMENT VARIABLES ===
86
- // Centralized environment variable access using qerrors utilities
87
- const { getEnv } = require(`qerrors`);
88
-
89
- function getEnvironmentConfig() {
90
- return {
91
- NODE_ENV: getEnv(`NODE_ENV`, `development`),
92
- DEBUG_TESTS: getEnv(`DEBUG_TESTS`, `false`) === `true`
93
- };
94
- }
95
-
96
- module.exports = {
97
- CODE_EXTENSIONS,
98
- ALL_EXTENSIONS,
99
- DEFAULT_ROOT_DIR,
100
- DEFAULT_OUTPUT_FILE,
101
- IGNORE_PATTERNS,
102
- MAX_JSON_KEYS,
103
- MAX_YAML_KEYS,
104
- MAX_SHELL_COMMANDS,
105
- MAX_HTML_TAGS,
106
- getDependencies,
107
- getDevDependencies,
108
- getEnvironmentConfig
109
- };
1
+ // This file proxies to the TypeScript-compiled configuration to maintain existing import paths.
2
+ module.exports = require('../dist/config/localVars.js');
package/dist/cli.js ADDED
@@ -0,0 +1,76 @@
1
+ #!/usr/bin/env node
2
+ "use strict";
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.showUsage = showUsage;
5
+ exports.main = main;
6
+ const localVars_1 = require("./config/localVars");
7
+ const index_1 = require("./lib/index");
8
+ function showUsage() {
9
+ console.log('Usage: fileflows [options]');
10
+ console.log('');
11
+ console.log('Options:');
12
+ console.log(' --dir <path> Directory to analyze (default: current directory)');
13
+ console.log(' --output <file> Output file path (default: FILE_FLOWS.md)');
14
+ console.log(' --help, -h Show this help message');
15
+ console.log('');
16
+ console.log('Examples:');
17
+ console.log(' fileflows # Analyze current directory');
18
+ console.log(' fileflows --dir ./src # Analyze src directory');
19
+ console.log(' fileflows --output flows.md # Custom output file');
20
+ }
21
+ async function main(argv = process.argv.slice(2)) {
22
+ let rootDir = localVars_1.DEFAULT_ROOT_DIR;
23
+ let outputFile = null;
24
+ for (let i = 0; i < argv.length; i += 1) {
25
+ const arg = argv[i];
26
+ if (arg === '--help' || arg === '-h') {
27
+ showUsage();
28
+ process.exitCode = 0;
29
+ return;
30
+ }
31
+ if (arg === '--dir') {
32
+ if (i + 1 < argv.length) {
33
+ rootDir = argv[++i];
34
+ }
35
+ else {
36
+ console.error('Error: --dir requires a directory path');
37
+ process.exitCode = 1;
38
+ return;
39
+ }
40
+ continue;
41
+ }
42
+ if (arg === '--output') {
43
+ if (i + 1 < argv.length) {
44
+ outputFile = argv[++i];
45
+ }
46
+ else {
47
+ console.error('Error: --output requires a file path');
48
+ process.exitCode = 1;
49
+ return;
50
+ }
51
+ continue;
52
+ }
53
+ console.error(`Error: Unknown argument '${arg}'`);
54
+ showUsage();
55
+ process.exitCode = 1;
56
+ return;
57
+ }
58
+ try {
59
+ console.log('🚀 Generating FILE_FLOWS.md...');
60
+ const result = await (0, index_1.generateFileFlows)(rootDir, outputFile);
61
+ if (result.outputFile && result.jsonOutputFile) {
62
+ console.log(`🧾 Wrote ${result.outputFile} and ${result.jsonOutputFile}`);
63
+ }
64
+ console.log('🎉 Generation complete!');
65
+ }
66
+ catch (error) {
67
+ console.error('❌ Error:', error.message);
68
+ process.exitCode = 1;
69
+ }
70
+ }
71
+ if (typeof require !== 'undefined' && require.main === module) {
72
+ main().catch(error => {
73
+ console.error(error);
74
+ process.exit(1);
75
+ });
76
+ }
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MAX_HTML_TAGS = exports.MAX_SHELL_COMMANDS = exports.MAX_YAML_KEYS = exports.MAX_JSON_KEYS = exports.IGNORE_PATTERNS = exports.DEFAULT_OUTPUT_FILE = exports.DEFAULT_ROOT_DIR = exports.ALL_EXTENSIONS = exports.CODE_EXTENSIONS = void 0;
4
+ exports.getDevDependencies = getDevDependencies;
5
+ exports.getEnvironmentConfig = getEnvironmentConfig;
6
+ exports.getDependencies = getDependencies;
7
+ /**
8
+ * Centralized configuration values and helpers for the FileFlows CLI
9
+ * Exports environment helpers, ignore lists, and other shared constants
10
+ */
11
+ const qerrors_1 = require("qerrors");
12
+ exports.CODE_EXTENSIONS = ['js', 'ts', 'jsx', 'tsx'];
13
+ exports.ALL_EXTENSIONS = [
14
+ ...exports.CODE_EXTENSIONS,
15
+ 'json',
16
+ 'md',
17
+ 'yml',
18
+ 'yaml',
19
+ 'env',
20
+ 'html',
21
+ 'css',
22
+ 'scss',
23
+ 'sh',
24
+ 'graphql'
25
+ ];
26
+ exports.DEFAULT_ROOT_DIR = '.';
27
+ exports.DEFAULT_OUTPUT_FILE = 'FILE_FLOWS.md';
28
+ exports.IGNORE_PATTERNS = [
29
+ '**/node_modules/**',
30
+ '**/.config/**',
31
+ '**/logs/**',
32
+ '**/.git/**',
33
+ '**/tmp/**',
34
+ '**/temp/**',
35
+ '**/.npm/**',
36
+ '**/.cache/**',
37
+ '**/dist/**',
38
+ '**/build/**',
39
+ '**/.next/**',
40
+ '**/.nuxt/**'
41
+ ];
42
+ exports.MAX_JSON_KEYS = 10;
43
+ exports.MAX_YAML_KEYS = 5;
44
+ exports.MAX_SHELL_COMMANDS = 5;
45
+ exports.MAX_HTML_TAGS = 5;
46
+ async function getDevDependencies() {
47
+ if (process.env.NODE_ENV === 'development' || process.env.NODE_ENV === 'test') {
48
+ try {
49
+ const qtests = await import('qtests/dist/index.js');
50
+ return { qtests };
51
+ }
52
+ catch {
53
+ return { qtests: null };
54
+ }
55
+ }
56
+ return { qtests: null };
57
+ }
58
+ function getEnvironmentConfig() {
59
+ return {
60
+ NODE_ENV: (0, qerrors_1.getEnv)('NODE_ENV', 'development'),
61
+ DEBUG_TESTS: (0, qerrors_1.getEnv)('DEBUG_TESTS', 'false') === 'true'
62
+ };
63
+ }
64
+ async function getDependencies() {
65
+ const { generateFileFlows, groupByDataFlow, classifyFile, parseJSFile, parseOtherFile, extractDependencies, fileIO, graphUtils } = await import('../lib/index.js');
66
+ return {
67
+ generateFileFlows,
68
+ groupByDataFlow,
69
+ classifyFile,
70
+ parseJSFile,
71
+ parseOtherFile,
72
+ extractDependencies,
73
+ fileIO,
74
+ graphUtils
75
+ };
76
+ }
package/dist/index.js ADDED
@@ -0,0 +1,7 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateFileFlows = void 0;
4
+ var index_1 = require("./lib/index");
5
+ Object.defineProperty(exports, "generateFileFlows", { enumerable: true, get: function () { return index_1.generateFileFlows; } });
6
+ const index_2 = require("./lib/index");
7
+ exports.default = index_2.generateFileFlows;
@@ -0,0 +1,137 @@
1
+ "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
35
+ var __importDefault = (this && this.__importDefault) || function (mod) {
36
+ return (mod && mod.__esModule) ? mod : { "default": mod };
37
+ };
38
+ Object.defineProperty(exports, "__esModule", { value: true });
39
+ exports.groupByDataFlow = groupByDataFlow;
40
+ const fs_1 = require("fs");
41
+ const path_1 = __importDefault(require("path"));
42
+ const localVars = __importStar(require("../config/localVars"));
43
+ const jsParser_1 = require("./jsParser");
44
+ const otherFileParser_1 = require("./otherFileParser");
45
+ const fileClassifier_1 = require("./fileClassifier");
46
+ const dependencyExtractor_1 = require("./dependencyExtractor");
47
+ const graphUtils = __importStar(require("./graphUtils"));
48
+ async function groupByDataFlow(fileList, rootDir) {
49
+ const fileMetadata = new Map();
50
+ for (const filePath of fileList) {
51
+ const fullPath = path_1.default.join(rootDir, filePath);
52
+ const ext = path_1.default.extname(filePath).slice(1);
53
+ try {
54
+ const content = (0, fs_1.readFileSync)(fullPath, 'utf8');
55
+ const metadata = (localVars.CODE_EXTENSIONS.includes(ext)
56
+ ? (0, jsParser_1.parseJSFile)(content, filePath)
57
+ : (0, otherFileParser_1.parseOtherFile)(content, filePath, ext));
58
+ const roleScore = graphUtils.calculateRoleScore(filePath);
59
+ const metadataImports = Array.isArray(metadata.Imports) ? metadata.Imports : [];
60
+ fileMetadata.set(filePath, {
61
+ ...metadata,
62
+ type: (0, fileClassifier_1.classifyFile)(filePath, ext),
63
+ dependencies: (0, dependencyExtractor_1.extractDependencies)(metadataImports, filePath, fileList),
64
+ roleScore
65
+ });
66
+ }
67
+ catch {
68
+ fileMetadata.set(filePath, {
69
+ Imports: [],
70
+ Exports: [],
71
+ Functions: [],
72
+ Components: [],
73
+ ApiCalls: [],
74
+ ReduxActions: [],
75
+ Routes: [],
76
+ type: (0, fileClassifier_1.classifyFile)(filePath, ext),
77
+ dependencies: [],
78
+ roleScore: graphUtils.calculateRoleScore(filePath)
79
+ });
80
+ }
81
+ }
82
+ const dependencyGraph = graphUtils.buildDependencyGraph(fileList, fileMetadata);
83
+ const connectedComponents = graphUtils.findConnectedComponents(dependencyGraph);
84
+ const primaryGroups = [];
85
+ const similarityCandidates = [];
86
+ for (const component of connectedComponents) {
87
+ if (component.length > 1) {
88
+ primaryGroups.push(component);
89
+ }
90
+ else if (component.length === 1) {
91
+ similarityCandidates.push(component[0]);
92
+ }
93
+ }
94
+ const groupedResults = [];
95
+ let groupCounter = 1;
96
+ for (const component of primaryGroups) {
97
+ const previousName = buildFlowGroupName(component, groupCounter++, graphUtils);
98
+ groupedResults.push({
99
+ name: previousName,
100
+ files: component,
101
+ metadata: component
102
+ .map(f => fileMetadata.get(f))
103
+ .filter((item) => Boolean(item))
104
+ });
105
+ }
106
+ if (similarityCandidates.length > 0) {
107
+ const similarityGroups = graphUtils.groupBySimilarity(similarityCandidates);
108
+ for (const [name, files] of similarityGroups) {
109
+ groupedResults.push({
110
+ name: `Similarity-${name}`,
111
+ files,
112
+ metadata: files
113
+ .map(f => fileMetadata.get(f))
114
+ .filter((item) => Boolean(item))
115
+ });
116
+ }
117
+ }
118
+ const result = groupedResults;
119
+ result.fileMetadata = fileMetadata;
120
+ return result;
121
+ }
122
+ function buildFlowGroupName(component, counter, graph) {
123
+ const sorted = [...component].sort((a, b) => {
124
+ const scoreB = graph.calculateRoleScore(b);
125
+ const scoreA = graph.calculateRoleScore(a);
126
+ if (scoreB !== scoreA)
127
+ return scoreB - scoreA;
128
+ return a.localeCompare(b);
129
+ });
130
+ const primary = sorted[0];
131
+ const baseName = path_1.default
132
+ .basename(primary, path_1.default.extname(primary))
133
+ .replace(/[^a-zA-Z0-9]+/g, '-')
134
+ .replace(/^-|-$/g, '');
135
+ const normalized = baseName || 'flow';
136
+ return `${normalized}-${counter}`;
137
+ }
@@ -0,0 +1,46 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.extractDependencies = extractDependencies;
7
+ const path_1 = __importDefault(require("path"));
8
+ function extractDependencies(imports, currentFile, fileList) {
9
+ const dependencies = [];
10
+ for (const imp of imports) {
11
+ if (!imp.startsWith('.')) {
12
+ continue;
13
+ }
14
+ const basePath = path_1.default.dirname(currentFile);
15
+ let resolvedPath = path_1.default.normalize(path_1.default.join(basePath, imp));
16
+ resolvedPath = resolvedPath.replace(/\\/g, '/');
17
+ const pathParts = resolvedPath.split('/');
18
+ const possibleBasePaths = [
19
+ resolvedPath,
20
+ pathParts[0] === 'src' ? pathParts.slice(1).join('/') : null,
21
+ resolvedPath.replace(/^src\//, '')
22
+ ].filter((value) => Boolean(value));
23
+ const allPossiblePaths = [resolvedPath, ...possibleBasePaths];
24
+ for (const basePathCandidate of allPossiblePaths) {
25
+ const possiblePaths = [
26
+ basePathCandidate,
27
+ `${basePathCandidate}.js`,
28
+ `${basePathCandidate}.ts`,
29
+ `${basePathCandidate}.jsx`,
30
+ `${basePathCandidate}.tsx`,
31
+ `${basePathCandidate}/index.js`,
32
+ `${basePathCandidate}/index.ts`
33
+ ];
34
+ for (const possiblePath of possiblePaths) {
35
+ if (fileList.includes(possiblePath)) {
36
+ dependencies.push(possiblePath);
37
+ break;
38
+ }
39
+ }
40
+ if (dependencies.some(dep => allPossiblePaths.some(base => dep.startsWith(base)))) {
41
+ break;
42
+ }
43
+ }
44
+ }
45
+ return dependencies;
46
+ }