@nahisaho/musubix-dfg 3.4.5 → 3.4.6

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 (2) hide show
  1. package/bin/musubix-dfg.js +158 -0
  2. package/package.json +2 -1
@@ -0,0 +1,158 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * MUSUBIX DFG CLI
4
+ * Data Flow Graph and Control Flow Graph analysis
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+
9
+ import { program } from 'commander';
10
+ import { createDFGAnalyzer, createCFGAnalyzer } from '../dist/index.js';
11
+ import { readFileSync, writeFileSync } from 'fs';
12
+ import { resolve } from 'path';
13
+
14
+ const VERSION = '3.4.6';
15
+
16
+ program
17
+ .name('musubix-dfg')
18
+ .description('MUSUBIX Data Flow Graph and Control Flow Graph analysis')
19
+ .version(VERSION);
20
+
21
+ program
22
+ .command('analyze')
23
+ .description('Analyze code and generate DFG/CFG')
24
+ .argument('<file>', 'Source file to analyze')
25
+ .option('-t, --type <type>', 'Analysis type (dfg|cfg|both)', 'both')
26
+ .option('-o, --output <file>', 'Output file (default: stdout)')
27
+ .option('-f, --format <format>', 'Output format (json|dot|mermaid)', 'json')
28
+ .action(async (file, options) => {
29
+ try {
30
+ const filePath = resolve(process.cwd(), file);
31
+ const code = readFileSync(filePath, 'utf-8');
32
+
33
+ const results = {};
34
+
35
+ if (options.type === 'dfg' || options.type === 'both') {
36
+ const dfgAnalyzer = createDFGAnalyzer();
37
+ results.dfg = await dfgAnalyzer.analyze(code, { filePath });
38
+ }
39
+
40
+ if (options.type === 'cfg' || options.type === 'both') {
41
+ const cfgAnalyzer = createCFGAnalyzer();
42
+ results.cfg = await cfgAnalyzer.analyze(code, { filePath });
43
+ }
44
+
45
+ let output;
46
+ switch (options.format) {
47
+ case 'json':
48
+ output = JSON.stringify(results, null, 2);
49
+ break;
50
+ case 'dot':
51
+ output = formatAsDot(results);
52
+ break;
53
+ case 'mermaid':
54
+ output = formatAsMermaid(results);
55
+ break;
56
+ default:
57
+ output = JSON.stringify(results, null, 2);
58
+ }
59
+
60
+ if (options.output) {
61
+ writeFileSync(options.output, output);
62
+ console.log(`Output written to ${options.output}`);
63
+ } else {
64
+ console.log(output);
65
+ }
66
+ } catch (error) {
67
+ console.error(`Error: ${error.message}`);
68
+ process.exit(1);
69
+ }
70
+ });
71
+
72
+ program
73
+ .command('dependencies')
74
+ .description('Extract variable dependencies from code')
75
+ .argument('<file>', 'Source file to analyze')
76
+ .option('-v, --variable <name>', 'Focus on specific variable')
77
+ .action(async (file, options) => {
78
+ try {
79
+ const filePath = resolve(process.cwd(), file);
80
+ const code = readFileSync(filePath, 'utf-8');
81
+
82
+ const dfgAnalyzer = createDFGAnalyzer();
83
+ const dfg = await dfgAnalyzer.analyze(code, { filePath });
84
+
85
+ if (options.variable) {
86
+ const deps = dfg.getDependencies(options.variable);
87
+ console.log(`Dependencies for '${options.variable}':`);
88
+ deps.forEach(dep => console.log(` - ${dep}`));
89
+ } else {
90
+ console.log('All dependencies:');
91
+ console.log(JSON.stringify(dfg.getAllDependencies(), null, 2));
92
+ }
93
+ } catch (error) {
94
+ console.error(`Error: ${error.message}`);
95
+ process.exit(1);
96
+ }
97
+ });
98
+
99
+ function formatAsDot(results) {
100
+ const lines = ['digraph G {'];
101
+
102
+ if (results.dfg) {
103
+ lines.push(' subgraph cluster_dfg {');
104
+ lines.push(' label = "Data Flow Graph";');
105
+ results.dfg.nodes?.forEach(node => {
106
+ lines.push(` "${node.id}" [label="${node.label || node.id}"];`);
107
+ });
108
+ results.dfg.edges?.forEach(edge => {
109
+ lines.push(` "${edge.source}" -> "${edge.target}";`);
110
+ });
111
+ lines.push(' }');
112
+ }
113
+
114
+ if (results.cfg) {
115
+ lines.push(' subgraph cluster_cfg {');
116
+ lines.push(' label = "Control Flow Graph";');
117
+ results.cfg.nodes?.forEach(node => {
118
+ lines.push(` "${node.id}" [label="${node.label || node.id}"];`);
119
+ });
120
+ results.cfg.edges?.forEach(edge => {
121
+ lines.push(` "${edge.source}" -> "${edge.target}";`);
122
+ });
123
+ lines.push(' }');
124
+ }
125
+
126
+ lines.push('}');
127
+ return lines.join('\n');
128
+ }
129
+
130
+ function formatAsMermaid(results) {
131
+ const lines = ['flowchart TD'];
132
+
133
+ if (results.dfg) {
134
+ lines.push(' subgraph DFG["Data Flow Graph"]');
135
+ results.dfg.nodes?.forEach(node => {
136
+ lines.push(` ${node.id}["${node.label || node.id}"]`);
137
+ });
138
+ results.dfg.edges?.forEach(edge => {
139
+ lines.push(` ${edge.source} --> ${edge.target}`);
140
+ });
141
+ lines.push(' end');
142
+ }
143
+
144
+ if (results.cfg) {
145
+ lines.push(' subgraph CFG["Control Flow Graph"]');
146
+ results.cfg.nodes?.forEach(node => {
147
+ lines.push(` ${node.id}["${node.label || node.id}"]`);
148
+ });
149
+ results.cfg.edges?.forEach(edge => {
150
+ lines.push(` ${edge.source} --> ${edge.target}`);
151
+ });
152
+ lines.push(' end');
153
+ }
154
+
155
+ return lines.join('\n');
156
+ }
157
+
158
+ program.parse();
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nahisaho/musubix-dfg",
3
- "version": "3.4.5",
3
+ "version": "3.4.6",
4
4
  "description": "MUSUBIX Data Flow Graph and Control Flow Graph analysis for neuro-symbolic code understanding",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -61,6 +61,7 @@
61
61
  "node": ">=20.0.0"
62
62
  },
63
63
  "dependencies": {
64
+ "commander": "^11.1.0",
64
65
  "typescript": "^5.7.2"
65
66
  },
66
67
  "devDependencies": {