@tng-sh/js 0.1.1 → 0.1.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/bin/tng.js CHANGED
@@ -28,7 +28,7 @@ process.on('uncaughtException', (err) => {
28
28
  program
29
29
  .name('tng')
30
30
  .description('TNG - Automated Test Generation, and audit generation for JavaScript')
31
- .version('0.1.1');
31
+ .version('0.1.2');
32
32
 
33
33
  /**
34
34
  * @command init
@@ -143,6 +143,65 @@ program
143
143
  launchInteractive();
144
144
  });
145
145
 
146
+ /**
147
+ * @command xray
148
+ * Generate X-Ray (Mermaid Visualization)
149
+ */
150
+ program
151
+ .command('xray')
152
+ .alias('x')
153
+ .description('Generate X-Ray visualization')
154
+ .option('-f, --file <path>', 'Input file path')
155
+ .option('-m, --method <name>', 'Method name to visualize')
156
+ .action(async (options) => {
157
+ if (!options.file || !options.method) {
158
+ console.log(chalk.red('Error: Both --file and --method are required for X-Ray.'));
159
+ console.log(chalk.yellow('Usage: tng xray -f <file> -m <method>'));
160
+ process.exit(1);
161
+ }
162
+
163
+ console.log(chalk.blue(`🔍 Generating X-Ray for ${options.method} in ${options.file}...`));
164
+
165
+ try {
166
+ const config = loadConfig();
167
+
168
+ // Re-use logic similar to _handleXrayFlow but tailored for CLI non-interactive output
169
+ const { generateTest } = require('../index');
170
+
171
+ // We use a custom callback to show progress
172
+ const callback = (msg, percent) => {
173
+ if (percent % 20 === 0) console.log(chalk.dim(`[${percent}%] ${msg}`));
174
+ };
175
+
176
+ // We pass 'visualize' as the test type
177
+ const resultJson = generateTest(
178
+ path.resolve(options.file),
179
+ options.method,
180
+ null,
181
+ 'visualize',
182
+ JSON.stringify(config),
183
+ callback
184
+ );
185
+
186
+ let mermaidCode = "";
187
+ try {
188
+ const parsed = JSON.parse(resultJson);
189
+ mermaidCode = parsed.mermaid_code || resultJson;
190
+ } catch (e) {
191
+ mermaidCode = resultJson;
192
+ }
193
+
194
+ console.log(chalk.bold('\n--- X-Ray Result (Mermaid.js) ---\n'));
195
+ console.log(chalk.blue(mermaidCode));
196
+ console.log(chalk.bold('\n---------------------------------\n'));
197
+ console.log(chalk.green('✓ Copy the code above and paste into https://mermaid.live'));
198
+
199
+ } catch (e) {
200
+ console.log(chalk.red(`Error: ${e.message}`));
201
+ process.exit(1);
202
+ }
203
+ });
204
+
146
205
  /**
147
206
  * Main command handler (handles -f and -m)
148
207
  */
Binary file
Binary file
Binary file
Binary file
@@ -34,6 +34,9 @@ class GenerateTestsUI {
34
34
  } else if (choice === 'audit') {
35
35
  const result = await this._showFileSelection(true);
36
36
  if (result === 'exit') return 'exit';
37
+ } else if (choice === 'xray') {
38
+ const result = await this._showFileSelection(false, true);
39
+ if (result === 'exit') return 'exit';
37
40
  } else if (choice === 'stats') {
38
41
  await this._showStats();
39
42
  } else if (choice === 'about') {
@@ -95,7 +98,7 @@ class GenerateTestsUI {
95
98
  });
96
99
  }
97
100
 
98
- async _showFileSelection(isAudit = false) {
101
+ async _showFileSelection(isAudit = false, isXray = false) {
99
102
  const files = await this._getUserFiles();
100
103
 
101
104
  if (files.length === 0) {
@@ -109,19 +112,19 @@ class GenerateTestsUI {
109
112
  path: path.dirname(file)
110
113
  }));
111
114
 
112
- const title = isAudit ? 'Select JavaScript File to Audit' : 'Select JavaScript File';
115
+ const title = isXray ? 'Select File for X-Ray' : (isAudit ? 'Select JavaScript File to Audit' : 'Select JavaScript File');
113
116
  const selectedName = this.goUiSession.showListView(title, items);
114
117
 
115
118
  if (selectedName === 'back') return 'back';
116
119
  if (!selectedName || selectedName === 'exit') return 'exit';
117
120
 
118
121
  const selectedFile = path.resolve(cwd, selectedName);
119
- const result = await this._showMethodsForFile(selectedFile, isAudit);
122
+ const result = await this._showMethodsForFile(selectedFile, isAudit, isXray);
120
123
  if (result === 'main_menu') return 'main_menu';
121
124
  return result;
122
125
  }
123
126
 
124
- async _showMethodsForFile(filePath, isAudit = false) {
127
+ async _showMethodsForFile(filePath, isAudit = false, isXray = false) {
125
128
  let outline;
126
129
  try {
127
130
  const result = getFileOutline(filePath);
@@ -144,33 +147,39 @@ class GenerateTestsUI {
144
147
  methodData: m
145
148
  }));
146
149
 
147
- const title = isAudit ? `Select Method to Audit for ${fileName}` : `Select Method for ${fileName}`;
150
+ const title = isXray ? `Select Method to X-Ray for ${fileName}` : (isAudit ? `Select Method to Audit for ${fileName}` : `Select Method for ${fileName}`);
148
151
  const selectedDisplay = this.goUiSession.showListView(title, items);
149
152
 
150
- if (selectedDisplay === 'back' || !selectedDisplay) return this._showFileSelection(isAudit);
153
+ if (selectedDisplay === 'back' || !selectedDisplay) return this._showFileSelection(isAudit, isXray);
151
154
 
152
155
  const selectedMethod = items.find(i => i.name === selectedDisplay)?.methodData;
153
156
 
154
157
  if (selectedMethod) {
158
+ if (isXray) {
159
+ const choice = await this._generateTestsForMethod(filePath, selectedMethod, 'visualize', false, true);
160
+ if (choice === 'main_menu') return 'main_menu';
161
+ return this._showFileSelection(isAudit, isXray);
162
+ }
163
+
155
164
  const testType = this.goUiSession.showJsTestMenu();
156
- if (testType === 'back') return this._showFileSelection(isAudit);
165
+ if (testType === 'back') return this._showFileSelection(isAudit, isXray);
157
166
 
158
167
  const finalType = testType === 'auto' ? null : testType;
159
168
  const choice = await this._generateTestsForMethod(filePath, selectedMethod, finalType, isAudit);
160
169
 
161
170
  if (isAudit) {
162
171
  if (choice === 'main_menu') return 'main_menu';
163
- return this._showFileSelection(isAudit);
172
+ return this._showFileSelection(isAudit, isXray);
164
173
  }
165
174
 
166
175
  if (choice && choice.file_path && !choice.error) {
167
176
  this._showPostGenerationMenu(choice);
168
177
  }
169
178
  }
170
- return this._showFileSelection(isAudit);
179
+ return this._showFileSelection(isAudit, isXray);
171
180
  }
172
181
 
173
- async _generateTestsForMethod(filePath, method, testType, isAudit = false) {
182
+ async _generateTestsForMethod(filePath, method, testType, isAudit = false, isXray = false) {
174
183
  if (!this._hasApiKey()) {
175
184
  return { error: 'No API key' };
176
185
  }
@@ -179,6 +188,10 @@ class GenerateTestsUI {
179
188
  return this._handleAuditFlow(filePath, method, testType);
180
189
  }
181
190
 
191
+ if (isXray) {
192
+ return this._handleXrayFlow(filePath, method);
193
+ }
194
+
182
195
  const fileName = path.basename(filePath);
183
196
  const displayName = method.class_name ? `${method.class_name}#${method.name}` : `${fileName}#${method.name}`;
184
197
  return this._handleTestGenerationFlow(filePath, method, testType, displayName);
@@ -395,6 +408,78 @@ class GenerateTestsUI {
395
408
  return uiResult || null;
396
409
  }
397
410
 
411
+ async _handleXrayFlow(filePath, method) {
412
+ const actionName = 'Generating X-Ray for';
413
+ const displayName = method.name;
414
+
415
+ const progressHandler = async (progress) => {
416
+ progress.update('Analyzing method structure...');
417
+
418
+ try {
419
+ const config = loadConfig();
420
+ // Override test_type to 'visualize' which behaves like test generation but returns Mermaid code
421
+ const resultJson = generateTest(
422
+ filePath,
423
+ method.name,
424
+ method.class_name || null,
425
+ 'visualize',
426
+ JSON.stringify(config),
427
+ (msg, percent) => {
428
+ // Simple progress updates
429
+ progress.update(msg, { percent });
430
+ }
431
+ );
432
+
433
+ // The result is expected to be a JSON string containing the mermaid definition
434
+ // But generateTest returns the full file content usually.
435
+ // We need to clarify if Backend returns just Mermaid or a file.
436
+ // Assuming Backend returns JSON with { "visualize_result": "mermaid code..." } or similar
437
+ // or if it returns raw text, we handle it.
438
+
439
+ // For 'visualize' type, existing backend generates a file or JSON.
440
+ // We should parse it.
441
+ let mermaidCode = "";
442
+ try {
443
+ const parsed = JSON.parse(resultJson);
444
+ if (parsed.mermaid_code) mermaidCode = parsed.mermaid_code;
445
+ else mermaidCode = resultJson; // Fallback
446
+ } catch (e) {
447
+ mermaidCode = resultJson;
448
+ }
449
+
450
+ return {
451
+ success: true,
452
+ mermaidCode: mermaidCode
453
+ };
454
+ } catch (e) {
455
+ progress.error(`Failed to generate X-Ray: ${e.message}`);
456
+ return { error: e.message };
457
+ }
458
+ };
459
+
460
+ const result = await this.goUiSession.showProgress(`${actionName} ${displayName}`, progressHandler);
461
+
462
+ if (result && result.mermaidCode) {
463
+ console.log(chalk.bold('\n--- X-Ray Result (Mermaid.js) ---\n'));
464
+ // Simple highlighting for terminal
465
+ console.log(chalk.blue(result.mermaidCode));
466
+ console.log(chalk.bold('\n---------------------------------\n'));
467
+
468
+ // Prompt user action
469
+ this._copyToClipboard(result.mermaidCode);
470
+ console.log(chalk.green('✓ Copied to clipboard! Paste into https://mermaid.live'));
471
+
472
+ // Wait for user confirmation to return
473
+ const { execSync } = require('child_process');
474
+ try {
475
+ // Just a pause hack if we want, but showListView might be better.
476
+ // For now, let's just return.
477
+ } catch (e) { }
478
+ }
479
+
480
+ return result;
481
+ }
482
+
398
483
  _updateProgress(progress, msg, percent) {
399
484
  const agentMap = {
400
485
  'context_agent_status': { label: 'Context Builder', step: 1 },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tng-sh/js",
3
- "version": "0.1.1",
3
+ "version": "0.1.2",
4
4
  "description": "TNG JavaScript CLI",
5
5
  "repository": {
6
6
  "type": "git",
Binary file
Binary file
Binary file
Binary file