@tng-sh/js 0.1.4 → 0.1.7

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 CHANGED
@@ -4,69 +4,87 @@ High-performance test generation and context analysis for JavaScript/TypeScript,
4
4
 
5
5
  ## Installation
6
6
 
7
+ Install the package as a development dependency in your project:
8
+
7
9
  ```bash
8
10
  npm install @tng-sh/js --save-dev
9
11
  ```
10
12
 
11
- ## Quick Start
13
+ ## Usage
12
14
 
13
15
  ### 1. Initialize
14
- Run the init command to create a `tng.config.js` configuration file in your project:
16
+ First, run the init command to create a `tng.config.js` configuration file. This file stores your API keys and project settings.
15
17
 
16
18
  ```bash
17
- npx -p @tng-sh/js tng init
19
+ npx tng init
18
20
  ```
19
21
 
20
- ### 2. Generate Tests
21
- Generate a test for a specific function in a file:
22
+ ### 2. Interactive Mode (TUI)
23
+ The most powerful way to use TNG is via the high-performance terminal interface. It provides a guided experience for all analysis tasks.
22
24
 
23
25
  ```bash
24
- npx -p @tng-sh/js tng -f path/to/file.js -m functionName -t react_component
26
+ npx tng i
27
+ ```
28
+
29
+ **Capabilities in TUI:**
30
+ * **Generate Tests**: Guided test creation for methods, components, and utilities.
31
+ * **Audit Method**: Deep security, performance, and best-practice auditing.
32
+ * **Trace Method**: Symbolic execution and logic flow visualization.
33
+ * **X-Ray Method**: Deep dependency and side-effect analysis.
34
+ * **Check Duplicates**: High-performance clone detection across the codebase.
35
+ * **Dead Code**: Identify unreachable logic and unused variables/parameters.
36
+ * **User Stats**: Review your usage metrics and generation history.
37
+
38
+ ### 3. Command Line Interface (CLI) ⚙️
39
+ For direct execution or integration into scripts.
40
+
41
+ ```bash
42
+ # See file outline and method list
43
+ npx tng -f path/to/file.js --outline
44
+
45
+ # Generate tests for a specific method
46
+ npx tng -f path/to/file.js -m functionName -t react_component
47
+
48
+ # Check for code clones
49
+ npx tng -f path/to/file.js --clones
25
50
  ```
26
51
 
27
52
  **Supported Types (`-t`):**
28
- - `react_component`
29
- - `express_handler`
30
- - `graphql_resolver`
31
- - `nest_js` (Service/Controller)
32
- - `orm_model`
33
- - `background_job`
34
- - `mailer`
35
- - `utility`
36
-
37
- ### 3. Interactive Mode
38
- Launch the interactive UI to explore and generate tests visually:
53
+ `react_component`, `express_handler`, `graphql_resolver`, `nest_js`, `orm_model`, `background_job`, `mailer`, `utility`.
54
+
55
+ ### 4. Machine-Readable Output (`--json`) 🤖
56
+ Add the `--json` flag to any command to receive output as structured JSON events. This is ideal for CI/CD pipelines or custom integrations.
39
57
 
40
58
  ```bash
41
- npx -p @tng-sh/js tng i
59
+ npx tng -f path/to/file.js --clones --json
60
+ ```
61
+
62
+ ### 4. Dead Code Analysis
63
+ Identify unreachable code, unused variables, and unused imports in your project:
64
+
65
+ ```bash
66
+ npx -p @tng-sh/js tng --deadcode -f path/to/file.js
42
67
  ```
43
68
 
44
69
  ## Features
45
70
 
46
- - ⚡️ **Fast AST Analysis**: Powered by Rust and the `oxc` parser for blazing fast static analysis.
47
- - 🖥️ **Interactive UI**: Rich Go-based terminal UI for managing test generation.
48
- - 🎨 **Prettier Integration**: Automatically formats generated tests to match your project style.
49
- - 📘 **TypeScript Support**: First-class support for TypeScript analysis.
71
+ - **Blazing Fast Static Analysis**: Powered by Rust and the `oxc` parser for near-instant AST processing.
72
+ - **Interactive Terminal UI**: Dual-pane keyboard-driven interface for deep code exploration.
73
+ - **Smart Visualization**: Generate logic flow diagrams using Mermaid.js integration.
74
+ - **Dead Code Cleanup**: Find and remove unused imports, variables, and unreachable logic.
75
+ - **First-Class TS & React**: Native support for TypeScript, JSX, and TSX.
50
76
 
51
- ## Configuration
77
+ ## ⚙️ Configuration
52
78
 
53
- The `tng.config.js` file allows you to customize the behavior:
79
+ Your `tng.config.js` allows for full customization:
54
80
 
55
81
  ```javascript
56
82
  module.exports = {
57
- // API Configuration
58
83
  API_KEY: "your-api-key-here",
59
84
  API_URL: "https://app.tng.sh/",
60
-
61
- // Framework Detection
62
- // Options: express, nextjs, nestjs, generic
63
- FRAMEWORK: "express",
64
-
65
- // Testing Configuration
66
- // Options: jest, mocha, vitest
67
- TEST_FRAMEWORK: "jest",
68
-
69
- // Test Directory
70
- TEST_DIRECTORY: "tests"
85
+ FRAMEWORK: "express", // Options: express, nextjs, nestjs, generic
86
+ TESTS_PATH: "tests", // Where to save generated tests
87
+ TEST_FRAMEWORK: "jest" // Options: jest, mocha, vitest
71
88
  };
72
89
  ```
90
+
package/bin/tng.js CHANGED
@@ -27,8 +27,8 @@ process.on('uncaughtException', (err) => {
27
27
 
28
28
  program
29
29
  .name('tng')
30
- .description('TNG - Automated Test Generation, and audit generation for JavaScript')
31
- .version('0.1.4');
30
+ .description('TNG - Advanced Code Audit, Test Generation, Visualization, and Dead Code Analysis for JavaScript/TypeScript')
31
+ .version('0.1.7');
32
32
 
33
33
  /**
34
34
  * @command init
@@ -138,7 +138,7 @@ function launchInteractive() {
138
138
  program
139
139
  .command('i')
140
140
  .alias('interactive')
141
- .description('Launch interactive UI')
141
+ .description('Launch interactive UI for code audit, test generation, and visualization')
142
142
  .action(() => {
143
143
  launchInteractive();
144
144
  });
@@ -213,6 +213,7 @@ program
213
213
  .option('--trace', 'Run symbolic trace visualization')
214
214
  .option('-c, --clones', 'Run duplicate code detection')
215
215
  .option('-l, --level <level>', 'Set clone detection level (1, 2, or all)', 'all')
216
+ .option('-d, --deadcode', 'Run dead code detection (JS/TS/React)')
216
217
  .option('--json', 'Output results as JSON events (machine-readable)')
217
218
 
218
219
  .action(async (options) => {
@@ -264,7 +265,9 @@ program
264
265
  generateTest(options.file, options.method, options.type, options.audit, options.json);
265
266
  } else if (options.file && !options.method) {
266
267
  if (options.clones) {
267
- runClones(options.file, options.level || 'all', options.json);
268
+ await runClones(options.file, options.level || 'all', options.json);
269
+ } else if (options.deadcode) {
270
+ await runDeadCode(options.file, options.json);
268
271
  } else {
269
272
  console.log(chalk.yellow('Specify a method with -m, use --outline to see methods, or run "tng i" for full selection.'));
270
273
  }
@@ -321,7 +324,58 @@ async function runClones(filePath, level, jsonMode = false) {
321
324
  });
322
325
 
323
326
  if (matches) {
324
- session.showClones(absolutePath, matches);
327
+ await session.showClones(absolutePath, matches);
328
+ }
329
+ } catch (e) {
330
+ console.log(chalk.red(`Error: ${e.message}`));
331
+ process.exit(1);
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Logic to run dead code detection
337
+ */
338
+ async function runDeadCode(filePath, jsonMode = false) {
339
+ const { detectDeadCode } = require('../index');
340
+ const absolutePath = path.resolve(filePath);
341
+
342
+ if (!fs.existsSync(absolutePath)) {
343
+ console.log(chalk.red(`File not found: ${filePath}`));
344
+ process.exit(1);
345
+ }
346
+
347
+ const GoUISession = require('../lib/goUiSession');
348
+ const session = new GoUISession();
349
+
350
+ if (jsonMode) {
351
+ const { JsonSession } = require('../lib/jsonSession');
352
+ const jsonSession = new JsonSession();
353
+ jsonSession.start();
354
+ try {
355
+ const resultJson = detectDeadCode(absolutePath);
356
+ jsonSession.emitEvent('dead_code', JSON.parse(resultJson));
357
+ jsonSession.stop();
358
+ } catch (e) {
359
+ jsonSession.displayError(e.message);
360
+ jsonSession.stop();
361
+ process.exit(1);
362
+ }
363
+ return;
364
+ }
365
+
366
+ console.log(chalk.blue(`🔍 Analyzing dead code in ${filePath}...`));
367
+
368
+ try {
369
+ const issuesJson = await session.showProgress('Analyzing dead code...', async (progress) => {
370
+ progress.update('Parsing AST...', { percent: 30 });
371
+ const resultJson = detectDeadCode(absolutePath);
372
+ progress.update('Identifying issues...', { percent: 70 });
373
+ progress.update('Done!', { percent: 100 });
374
+ return resultJson;
375
+ });
376
+
377
+ if (issuesJson) {
378
+ await session.showDeadCodeResults(absolutePath, issuesJson);
325
379
  }
326
380
  } catch (e) {
327
381
  console.log(chalk.red(`Error: ${e.message}`));
Binary file
Binary file
Binary file
Binary file
package/index.d.ts CHANGED
@@ -61,3 +61,5 @@ export declare function getSymbolicTrace(filePath: string, methodName: string, c
61
61
  * Returns a JSON string containing the matches found.
62
62
  */
63
63
  export declare function analyzeClones(projectRoot: string, filePath: string, level: string): string
64
+ /** Analyzes a file for dead code. */
65
+ export declare function detectDeadCode(filePath: string): string
package/index.js CHANGED
@@ -310,7 +310,7 @@ if (!nativeBinding) {
310
310
  throw new Error(`Failed to load native binding`)
311
311
  }
312
312
 
313
- const { getFileOutline, getProjectMetadata, findCallSites, ping, submitJob, getUserStats, runAudit, applyEdit, applyEditsAtomic, generateTest, getSymbolicTrace, analyzeClones } = nativeBinding
313
+ const { getFileOutline, getProjectMetadata, findCallSites, ping, submitJob, getUserStats, runAudit, applyEdit, applyEditsAtomic, generateTest, getSymbolicTrace, analyzeClones, detectDeadCode } = nativeBinding
314
314
 
315
315
  module.exports.getFileOutline = getFileOutline
316
316
  module.exports.getProjectMetadata = getProjectMetadata
@@ -324,3 +324,4 @@ module.exports.applyEditsAtomic = applyEditsAtomic
324
324
  module.exports.generateTest = generateTest
325
325
  module.exports.getSymbolicTrace = getSymbolicTrace
326
326
  module.exports.analyzeClones = analyzeClones
327
+ module.exports.detectDeadCode = detectDeadCode
Binary file
@@ -43,6 +43,9 @@ class GenerateTestsUI {
43
43
  } else if (choice === 'clones') {
44
44
  const result = await this._showClonesSelection();
45
45
  if (result === 'exit') return 'exit';
46
+ } else if (choice === 'deadcode') {
47
+ const result = await this._showDeadCodeSelection();
48
+ if (result === 'exit') return 'exit';
46
49
  } else if (choice === 'stats') {
47
50
  await this._showStats();
48
51
  } else if (choice === 'about') {
@@ -761,7 +764,55 @@ class GenerateTestsUI {
761
764
  });
762
765
 
763
766
  if (matches) {
764
- this.goUiSession.showClones(absolutePath, matches);
767
+ await this.goUiSession.showClones(absolutePath, matches);
768
+ }
769
+ } catch (e) {
770
+ console.log(chalk.red(`Error: ${e.message}`));
771
+ }
772
+ }
773
+
774
+ async _showDeadCodeSelection() {
775
+ const files = await this._getUserFiles();
776
+
777
+ if (files.length === 0) {
778
+ console.log(chalk.yellow('\nNo JavaScript or TypeScript files found in your project.\n'));
779
+ return 'back';
780
+ }
781
+
782
+ const cwd = process.cwd();
783
+ const items = files.map(file => ({
784
+ name: path.relative(cwd, file),
785
+ path: path.dirname(file)
786
+ }));
787
+
788
+ const selectedName = this.goUiSession.showListView('Select File for Dead Code Detection', items);
789
+
790
+ if (selectedName === 'back') return 'back';
791
+ if (!selectedName || selectedName === 'exit') return 'exit';
792
+
793
+ const selectedFile = path.resolve(cwd, selectedName);
794
+ await this._runDeadCode(selectedFile);
795
+ return 'main_menu';
796
+ }
797
+
798
+ async _runDeadCode(filePath) {
799
+ const { detectDeadCode } = require('../index');
800
+ const absolutePath = path.resolve(filePath);
801
+ const projectRoot = process.cwd();
802
+
803
+ console.log(chalk.blue(`🔍 Analyzing dead code in ${path.relative(projectRoot, filePath)}...`));
804
+
805
+ try {
806
+ const issuesJson = await this.goUiSession.showProgress('Analyzing dead code...', async (progress) => {
807
+ progress.update('Parsing AST...', { percent: 30 });
808
+ const resultJson = detectDeadCode(absolutePath);
809
+ progress.update('Identifying issues...', { percent: 70 });
810
+ progress.update('Done!', { percent: 100 });
811
+ return resultJson;
812
+ });
813
+
814
+ if (issuesJson) {
815
+ await this.goUiSession.showDeadCodeResults(absolutePath, issuesJson);
765
816
  }
766
817
  } catch (e) {
767
818
  console.log(chalk.red(`Error: ${e.message}`));
@@ -369,6 +369,35 @@ class GoUISession {
369
369
  }
370
370
  }
371
371
 
372
+ async showDeadCodeResults(filePath, resultsJson) {
373
+ const issues = JSON.parse(resultsJson);
374
+ const data = {
375
+ file: filePath,
376
+ dead_code: issues.map(issue => ({
377
+ type: issue.issue_type,
378
+ line: issue.line,
379
+ message: issue.message,
380
+ code: issue.code_snippet
381
+ }))
382
+ };
383
+ const inputFile = this._trackTempFile(this._createTempFile('dead-code-data', '.json'));
384
+
385
+ try {
386
+ fs.writeFileSync(inputFile, JSON.stringify(data));
387
+
388
+ spawnSync(this._binaryPath, ['deadcode', '--file', inputFile], {
389
+ stdio: 'inherit',
390
+ env: process.env
391
+ });
392
+ } catch (error) {
393
+ console.error('Dead code results display error:', error.message);
394
+ } finally {
395
+ this._cleanupTempFile(inputFile);
396
+ }
397
+ }
398
+
399
+
400
+
372
401
  async showStreamingAuditResults(methodName, className, sourceCode) {
373
402
  const outputFile = this._trackTempFile(this._createTempFile('audit-choice', '.txt'));
374
403
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tng-sh/js",
3
- "version": "0.1.4",
3
+ "version": "0.1.7",
4
4
  "description": "TNG JavaScript CLI",
5
5
  "repository": {
6
6
  "type": "git",
@@ -1 +0,0 @@
1
- {"file_path":"/Users/claudiu/work/tng-inc/js-pie/test_duplicates.js","matches":[{"start1":1,"end1":13,"start2":16,"end2":28,"line_count":13,"node_count":12,"complexity_score":245,"algo":"structural"}]}
@@ -1 +0,0 @@
1
- {"type":"step","step":1,"message":"Done!","percent":100}
@@ -1,13 +0,0 @@
1
- tng_sh_js:{"kind": "interface", "name": "CloneMatch", "js_doc": "", "def": "start1: number\nend1: number\nstart2: number\nend2: number\nlineCount: number\nnodeCount: number\ncomplexityScore: number\nalgo: string", "original_name": "CloneMatch"}
2
- tng_sh_js:{"kind": "fn", "name": "getFileOutline", "js_doc": "/**\n * Analyzes a JavaScript/TypeScript file and returns its structural outline as a JSON string.\n * Contains information about classes and methods found in the file.\n */\n", "def": "export declare function getFileOutline(filePath: string): string"}
3
- tng_sh_js:{"kind": "fn", "name": "getProjectMetadata", "js_doc": "/**\n * Gathers project-wide metadata from package.json and related files.\n * Returns a JSON string containing dependencies, frameworks, and project type.\n */\n", "def": "export declare function getProjectMetadata(projectRoot: string): string"}
4
- tng_sh_js:{"kind": "fn", "name": "findCallSites", "js_doc": "/**\n * Searches the project for all locations where a specific method is called.\n * Uses ripgrep under the hood for high performance.\n */\n", "def": "export declare function findCallSites(projectRoot: string, methodName: string): string"}
5
- tng_sh_js:{"kind": "fn", "name": "ping", "js_doc": "/** Pings the TNG API to verify connectivity and API key validity. */\n", "def": "export declare function ping(baseUrl: string, apiKey?: string | undefined | null): string"}
6
- tng_sh_js:{"kind": "fn", "name": "submitJob", "js_doc": "/** Submits a test generation job to the API and returns the numeric job ID. */\n", "def": "export declare function submitJob(baseUrl: string, apiKey: string, payloadJson: string): number"}
7
- tng_sh_js:{"kind": "fn", "name": "getUserStats", "js_doc": "/** Fetches usage statistics for the authenticated user from the API. */\n", "def": "export declare function getUserStats(baseUrl: string, apiKey: string): string"}
8
- tng_sh_js:{"kind": "fn", "name": "runAudit", "js_doc": "/**\n * Orchestrates the code audit process.\n * Analyzes the source, builds context, and streams results via the provided callback.\n */\n", "def": "export declare function runAudit(filePath: string, methodName: string, className: string | undefined | null, testType: string | undefined | null, configJson: string, callback: (...args: any[]) => any): string"}
9
- tng_sh_js:{"kind": "fn", "name": "applyEdit", "js_doc": "/**\n * Applies a single edit operation to a file.\n * Uses backup and atomic write for safety.\n */\n", "def": "export declare function applyEdit(filePath: string, search: string, replace: string, lineHint?: number | undefined | null): string"}
10
- tng_sh_js:{"kind": "fn", "name": "applyEditsAtomic", "js_doc": "/**\n * Applies multiple edit operations atomically.\n * All succeed or all fail (with rollback).\n */\n", "def": "export declare function applyEditsAtomic(operationsJson: string): string"}
11
- tng_sh_js:{"kind": "fn", "name": "generateTest", "js_doc": "/**\n * Orchestrates the test generation process.\n * Analyzes code, submits a job, and polls for the final generated test.\n */\n", "def": "export declare function generateTest(filePath: string, methodName: string, className: string | undefined | null, testType: string | undefined | null, configJson: string, callback: (...args: any[]) => any): string"}
12
- tng_sh_js:{"kind": "fn", "name": "getSymbolicTrace", "js_doc": "/** Analyzes a method and generates a symbolic execution trace. */\n", "def": "export declare function getSymbolicTrace(filePath: string, methodName: string, className?: string | undefined | null): string"}
13
- tng_sh_js:{"kind": "fn", "name": "analyzeClones", "js_doc": "/**\n * Analyzes a file for code clones (duplicates).\n * Returns a JSON string containing the matches found.\n */\n", "def": "export declare function analyzeClones(projectRoot: string, filePath: string, level: string): string"}
@@ -1,13 +0,0 @@
1
- tng_sh_js: __napi_register__CloneMatch_struct_0
2
- tng_sh_js: __napi_register__get_file_outline_1
3
- tng_sh_js: __napi_register__get_project_metadata_2
4
- tng_sh_js: __napi_register__find_call_sites_3
5
- tng_sh_js: __napi_register__ping_4
6
- tng_sh_js: __napi_register__submit_job_5
7
- tng_sh_js: __napi_register__get_user_stats_6
8
- tng_sh_js: __napi_register__run_audit_7
9
- tng_sh_js: __napi_register__apply_edit_8
10
- tng_sh_js: __napi_register__apply_edits_atomic_9
11
- tng_sh_js: __napi_register__generate_test_10
12
- tng_sh_js: __napi_register__get_symbolic_trace_11
13
- tng_sh_js: __napi_register__analyze_clones_12
package/out.log DELETED
File without changes
Binary file