@tng-sh/js 0.1.8 → 0.1.9
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 +96 -5
- package/binaries/go-ui-darwin-amd64 +0 -0
- package/binaries/go-ui-darwin-arm64 +0 -0
- package/binaries/go-ui-linux-amd64 +0 -0
- package/binaries/go-ui-linux-arm64 +0 -0
- package/index.darwin-arm64.node +0 -0
- package/index.darwin-x64.node +0 -0
- package/index.linux-arm64-gnu.node +0 -0
- package/index.linux-x64-gnu.node +0 -0
- package/lib/generateTestsUi.js +20 -23
- package/lib/goUiSession.js +23 -0
- package/lib/jsonSession.js +4 -0
- package/package.json +1 -1
package/bin/tng.js
CHANGED
|
@@ -28,7 +28,35 @@ process.on('uncaughtException', (err) => {
|
|
|
28
28
|
program
|
|
29
29
|
.name('tng')
|
|
30
30
|
.description('TNG - Advanced Code Audit, Test Generation, Visualization, Clone Detection, and Dead Code Analysis for JavaScript/TypeScript')
|
|
31
|
-
.version('0.1.
|
|
31
|
+
.version('0.1.9');
|
|
32
|
+
|
|
33
|
+
/**
|
|
34
|
+
* Copy text to system clipboard
|
|
35
|
+
*/
|
|
36
|
+
function copyToClipboard(text) {
|
|
37
|
+
const { execSync } = require('child_process');
|
|
38
|
+
try {
|
|
39
|
+
if (process.platform === 'darwin') {
|
|
40
|
+
execSync('pbcopy', { input: text });
|
|
41
|
+
return true;
|
|
42
|
+
} else if (process.platform === 'linux') {
|
|
43
|
+
try {
|
|
44
|
+
execSync('xclip -selection clipboard', { input: text });
|
|
45
|
+
return true;
|
|
46
|
+
} catch (e) {
|
|
47
|
+
try {
|
|
48
|
+
execSync('xsel --clipboard --input', { input: text });
|
|
49
|
+
return true;
|
|
50
|
+
} catch (e2) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
} catch (e) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
32
60
|
|
|
33
61
|
/**
|
|
34
62
|
* @command init
|
|
@@ -153,6 +181,7 @@ program
|
|
|
153
181
|
.description('Generate X-Ray visualization')
|
|
154
182
|
.option('-f, --file <path>', 'Input file path')
|
|
155
183
|
.option('-m, --method <name>', 'Method name to visualize')
|
|
184
|
+
.option('-j, --json', 'Output results in JSON format')
|
|
156
185
|
.action(async (options) => {
|
|
157
186
|
if (!options.file || !options.method) {
|
|
158
187
|
console.log(chalk.red('Error: Both --file and --method are required for X-Ray.'));
|
|
@@ -183,18 +212,28 @@ program
|
|
|
183
212
|
callback
|
|
184
213
|
);
|
|
185
214
|
|
|
215
|
+
if (options.json) {
|
|
216
|
+
console.log(resultJson);
|
|
217
|
+
return;
|
|
218
|
+
}
|
|
219
|
+
|
|
186
220
|
let mermaidCode = "";
|
|
221
|
+
let explanation = "";
|
|
187
222
|
try {
|
|
188
223
|
const parsed = JSON.parse(resultJson);
|
|
189
224
|
mermaidCode = parsed.mermaid_code || resultJson;
|
|
225
|
+
explanation = parsed.explanation || "";
|
|
190
226
|
} catch (e) {
|
|
191
227
|
mermaidCode = resultJson;
|
|
192
228
|
}
|
|
193
229
|
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
230
|
+
// Copy to clipboard
|
|
231
|
+
copyToClipboard(mermaidCode);
|
|
232
|
+
|
|
233
|
+
// Launch Premium UI
|
|
234
|
+
const GoUISession = require('../lib/goUiSession');
|
|
235
|
+
const session = new GoUISession();
|
|
236
|
+
await session.showXrayResults(options.method, '', mermaidCode, explanation);
|
|
198
237
|
|
|
199
238
|
} catch (e) {
|
|
200
239
|
console.log(chalk.red(`Error: ${e.message}`));
|
|
@@ -214,6 +253,7 @@ program
|
|
|
214
253
|
.option('-c, --clones', 'Run duplicate code detection')
|
|
215
254
|
.option('-l, --level <level>', 'Set clone detection level (1: token, 2: structural, 3: fuzzy, or all)', 'all')
|
|
216
255
|
.option('-d, --deadcode', 'Run dead code detection (JS/TS/React)')
|
|
256
|
+
.option('--xray', 'Generate X-Ray visualization (Mermaid flowchart)')
|
|
217
257
|
.option('--json', 'Output results as JSON events (machine-readable)')
|
|
218
258
|
|
|
219
259
|
.action(async (options) => {
|
|
@@ -258,6 +298,52 @@ program
|
|
|
258
298
|
return;
|
|
259
299
|
}
|
|
260
300
|
|
|
301
|
+
if (options.xray) {
|
|
302
|
+
const config = loadConfig();
|
|
303
|
+
const { generateTest: nativeGenerateTest } = require('../index');
|
|
304
|
+
|
|
305
|
+
try {
|
|
306
|
+
const resultJson = nativeGenerateTest(
|
|
307
|
+
path.resolve(options.file),
|
|
308
|
+
options.method,
|
|
309
|
+
null,
|
|
310
|
+
'visualize',
|
|
311
|
+
JSON.stringify(config),
|
|
312
|
+
(msg, percent) => {
|
|
313
|
+
if (options.json) return;
|
|
314
|
+
if (percent % 20 === 0) console.log(chalk.dim(`[${percent}%] ${msg}`));
|
|
315
|
+
}
|
|
316
|
+
);
|
|
317
|
+
|
|
318
|
+
if (options.json) {
|
|
319
|
+
console.log(resultJson);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
// For global --xray, we just launch the Premium UI directly if not JSON
|
|
324
|
+
const GoUISession = require('../lib/goUiSession');
|
|
325
|
+
const session = new GoUISession();
|
|
326
|
+
let mermaidCode = "";
|
|
327
|
+
let explanation = "";
|
|
328
|
+
try {
|
|
329
|
+
const parsed = JSON.parse(resultJson);
|
|
330
|
+
mermaidCode = parsed.mermaid_code || resultJson;
|
|
331
|
+
explanation = parsed.explanation || "";
|
|
332
|
+
} catch (e) {
|
|
333
|
+
mermaidCode = resultJson;
|
|
334
|
+
}
|
|
335
|
+
|
|
336
|
+
// Copy to clipboard
|
|
337
|
+
copyToClipboard(mermaidCode);
|
|
338
|
+
|
|
339
|
+
await session.showXrayResults(options.method, '', mermaidCode, explanation);
|
|
340
|
+
} catch (e) {
|
|
341
|
+
console.log(chalk.red(`X-Ray failed: ${e.message}`));
|
|
342
|
+
process.exit(1);
|
|
343
|
+
}
|
|
344
|
+
return;
|
|
345
|
+
}
|
|
346
|
+
|
|
261
347
|
if (!options.type && !options.audit) {
|
|
262
348
|
console.log(chalk.red('Error: --type <type> is required.'));
|
|
263
349
|
process.exit(1);
|
|
@@ -558,6 +644,11 @@ program.on('--help', () => {
|
|
|
558
644
|
console.log(' 3: Fuzzy (Fuzzy structural, catches patterns with small variations)');
|
|
559
645
|
console.log(' all: Runs all detection levels (default)');
|
|
560
646
|
console.log('');
|
|
647
|
+
console.log('X-Ray Visualization:');
|
|
648
|
+
console.log(' tng src/components/MyComponent.js render --xray');
|
|
649
|
+
console.log(' tng --file=api/handler.js --method=post --xray --json');
|
|
650
|
+
console.log(' tng xray -f src/utils.js -m processData');
|
|
651
|
+
console.log('');
|
|
561
652
|
});
|
|
562
653
|
|
|
563
654
|
program.parse(process.argv);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.darwin-arm64.node
CHANGED
|
Binary file
|
package/index.darwin-x64.node
CHANGED
|
Binary file
|
|
Binary file
|
package/index.linux-x64-gnu.node
CHANGED
|
Binary file
|
package/lib/generateTestsUi.js
CHANGED
|
@@ -461,17 +461,19 @@ class GenerateTestsUI {
|
|
|
461
461
|
// For 'visualize' type, existing backend generates a file or JSON.
|
|
462
462
|
// We should parse it.
|
|
463
463
|
let mermaidCode = "";
|
|
464
|
+
let explanation = "";
|
|
464
465
|
try {
|
|
465
466
|
const parsed = JSON.parse(resultJson);
|
|
466
|
-
|
|
467
|
-
|
|
467
|
+
mermaidCode = parsed.mermaid_code || resultJson;
|
|
468
|
+
explanation = parsed.explanation || "";
|
|
468
469
|
} catch (e) {
|
|
469
470
|
mermaidCode = resultJson;
|
|
470
471
|
}
|
|
471
472
|
|
|
472
473
|
return {
|
|
473
474
|
success: true,
|
|
474
|
-
mermaidCode: mermaidCode
|
|
475
|
+
mermaidCode: mermaidCode,
|
|
476
|
+
explanation: explanation
|
|
475
477
|
};
|
|
476
478
|
} catch (e) {
|
|
477
479
|
progress.error(`Failed to generate X-Ray: ${e.message}`);
|
|
@@ -482,21 +484,16 @@ class GenerateTestsUI {
|
|
|
482
484
|
const result = await this.goUiSession.showProgress(`${actionName} ${displayName}`, progressHandler);
|
|
483
485
|
|
|
484
486
|
if (result && result.mermaidCode) {
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const { execSync } = require('child_process');
|
|
496
|
-
try {
|
|
497
|
-
// Just a pause hack if we want, but showListView might be better.
|
|
498
|
-
// For now, let's just return.
|
|
499
|
-
} catch (e) { }
|
|
487
|
+
// Copy to clipboard first so it's ready for the user
|
|
488
|
+
this._copyToClipboard(result.mermaidCode, true);
|
|
489
|
+
|
|
490
|
+
// Show Premium X-Ray UI
|
|
491
|
+
await this.goUiSession.showXrayResults(
|
|
492
|
+
method.name,
|
|
493
|
+
method.class_name || '',
|
|
494
|
+
result.mermaidCode,
|
|
495
|
+
result.explanation || 'Logic flow visualization generated by TNG.'
|
|
496
|
+
);
|
|
500
497
|
}
|
|
501
498
|
|
|
502
499
|
return result;
|
|
@@ -614,12 +611,12 @@ class GenerateTestsUI {
|
|
|
614
611
|
return { passed, failed, errors, total };
|
|
615
612
|
}
|
|
616
613
|
|
|
617
|
-
_copyToClipboard(text) {
|
|
614
|
+
_copyToClipboard(text, silent = false) {
|
|
618
615
|
const { execSync } = require('child_process');
|
|
619
616
|
try {
|
|
620
617
|
if (process.platform === 'darwin') {
|
|
621
618
|
execSync('pbcopy', { input: text });
|
|
622
|
-
this.goUiSession.showClipboardSuccess(text);
|
|
619
|
+
if (!silent) this.goUiSession.showClipboardSuccess(text);
|
|
623
620
|
} else if (process.platform === 'linux') {
|
|
624
621
|
// Try xclip then xsel
|
|
625
622
|
try {
|
|
@@ -627,12 +624,12 @@ class GenerateTestsUI {
|
|
|
627
624
|
} catch (e) {
|
|
628
625
|
execSync('xsel --clipboard --input', { input: text });
|
|
629
626
|
}
|
|
630
|
-
this.goUiSession.showClipboardSuccess(text);
|
|
627
|
+
if (!silent) this.goUiSession.showClipboardSuccess(text);
|
|
631
628
|
} else {
|
|
632
|
-
console.log(chalk.cyan(`\n📋 Please copy this command: ${text}\n`));
|
|
629
|
+
if (!silent) console.log(chalk.cyan(`\n📋 Please copy this command: ${text}\n`));
|
|
633
630
|
}
|
|
634
631
|
} catch (e) {
|
|
635
|
-
console.error(chalk.yellow(`\n⚠️ Failed to copy to clipboard. Command: ${text}\n`));
|
|
632
|
+
if (!silent) console.error(chalk.yellow(`\n⚠️ Failed to copy to clipboard. Command: ${text}\n`));
|
|
636
633
|
}
|
|
637
634
|
}
|
|
638
635
|
|
package/lib/goUiSession.js
CHANGED
|
@@ -369,6 +369,29 @@ class GoUISession {
|
|
|
369
369
|
}
|
|
370
370
|
}
|
|
371
371
|
|
|
372
|
+
async showXrayResults(methodName, className, mermaidCode, explanation) {
|
|
373
|
+
const data = {
|
|
374
|
+
method_name: methodName,
|
|
375
|
+
class_name: className,
|
|
376
|
+
mermaid_code: mermaidCode,
|
|
377
|
+
explanation: explanation
|
|
378
|
+
};
|
|
379
|
+
const inputFile = this._trackTempFile(this._createTempFile('xray-data', '.json'));
|
|
380
|
+
|
|
381
|
+
try {
|
|
382
|
+
fs.writeFileSync(inputFile, JSON.stringify(data));
|
|
383
|
+
|
|
384
|
+
spawnSync(this._binaryPath, ['xray-results', '--file', inputFile], {
|
|
385
|
+
stdio: 'inherit',
|
|
386
|
+
env: process.env
|
|
387
|
+
});
|
|
388
|
+
} catch (error) {
|
|
389
|
+
console.error('X-Ray results display error:', error.message);
|
|
390
|
+
} finally {
|
|
391
|
+
this._cleanupTempFile(inputFile);
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
372
395
|
async showDeadCodeResults(filePath, resultsJson) {
|
|
373
396
|
const issues = JSON.parse(resultsJson);
|
|
374
397
|
const data = {
|
package/lib/jsonSession.js
CHANGED
|
@@ -66,6 +66,10 @@ class JsonSession {
|
|
|
66
66
|
this.emitEvent('result', auditResult || {});
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
+
showXrayResults(xrayResult) {
|
|
70
|
+
this.emitEvent('result', xrayResult || {});
|
|
71
|
+
}
|
|
72
|
+
|
|
69
73
|
showClones(filePath, results) {
|
|
70
74
|
this.emitEvent('clones', { file_path: filePath, matches: results });
|
|
71
75
|
}
|