@tng-sh/js 0.0.1
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/LICENSE.md +32 -0
- package/bin/tng.js +289 -0
- 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.d.ts +12 -0
- package/index.js +321 -0
- package/lib/config.js +31 -0
- package/lib/generateTestsUi.js +330 -0
- package/lib/goUiSession.js +349 -0
- package/lib/jsonSession.js +156 -0
- package/lib/saveFile.js +87 -0
- package/package.json +47 -0
- package/tng_sh_js.darwin-arm64.node +0 -0
- package/tng_sh_js.darwin-x64.node +0 -0
- package/tng_sh_js.linux-arm64-gnu.node +0 -0
- package/tng_sh_js.linux-x64-gnu.node +0 -0
package/LICENSE.md
ADDED
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
# Commercial License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Binary Dreams LLC. All rights reserved.
|
|
4
|
+
|
|
5
|
+
## License Grant
|
|
6
|
+
|
|
7
|
+
This software is available under a commercial license. You may use this software if you have obtained a valid license from the copyright holder.
|
|
8
|
+
|
|
9
|
+
## Restrictions
|
|
10
|
+
|
|
11
|
+
Without a valid commercial license, you may NOT:
|
|
12
|
+
- Use this software in any commercial or production environment
|
|
13
|
+
- Fork, copy, modify, or create derivative works
|
|
14
|
+
- Distribute, redistribute, sublicense, or sell copies
|
|
15
|
+
- Reverse engineer or decompile the software
|
|
16
|
+
- Remove or alter any copyright notices
|
|
17
|
+
|
|
18
|
+
## Commercial Use
|
|
19
|
+
|
|
20
|
+
To obtain a commercial license for production use, contact: [raluca@tng.sh]
|
|
21
|
+
|
|
22
|
+
## Evaluation Use
|
|
23
|
+
|
|
24
|
+
You may evaluate this software for a period of 30 days for non-commercial purposes only.
|
|
25
|
+
|
|
26
|
+
## Termination
|
|
27
|
+
|
|
28
|
+
Any unauthorized use will result in immediate termination of rights and may result in legal action.
|
|
29
|
+
|
|
30
|
+
## Disclaimer
|
|
31
|
+
|
|
32
|
+
THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED.
|
package/bin/tng.js
ADDED
|
@@ -0,0 +1,289 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
const { program } = require('commander');
|
|
4
|
+
const chalk = require('chalk');
|
|
5
|
+
const fs = require('fs');
|
|
6
|
+
const path = require('path');
|
|
7
|
+
const { loadConfig } = require('../lib/config');
|
|
8
|
+
const { saveTestFile } = require('../lib/saveFile');
|
|
9
|
+
const { ping, getUserStats } = require('../index');
|
|
10
|
+
|
|
11
|
+
program
|
|
12
|
+
.name('tng')
|
|
13
|
+
.description('TNG - Automated Test Generation for JavaScript')
|
|
14
|
+
.version('0.0.1');
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* @command init
|
|
18
|
+
* Initialize TNG configuration - creates tng.config.js
|
|
19
|
+
*/
|
|
20
|
+
program
|
|
21
|
+
.command('init')
|
|
22
|
+
.description('Initialize TNG configuration')
|
|
23
|
+
.action(() => {
|
|
24
|
+
console.log(chalk.blue.bold('\nTNG Configuration Setup'));
|
|
25
|
+
const configPath = path.join(process.cwd(), 'tng.config.js');
|
|
26
|
+
|
|
27
|
+
if (fs.existsSync(configPath)) {
|
|
28
|
+
console.log(chalk.yellow('tng.config.js already exists. Keeping existing config.'));
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
const content = `/**
|
|
33
|
+
* TNG Configuration - Project settings for test generation
|
|
34
|
+
*/
|
|
35
|
+
|
|
36
|
+
module.exports = {
|
|
37
|
+
// API Configuration
|
|
38
|
+
API_KEY: "your-api-key-here",
|
|
39
|
+
API_URL: "https://app.tng.sh/",
|
|
40
|
+
|
|
41
|
+
// Framework Detection
|
|
42
|
+
// Options: express, nextjs, nestjs, generic
|
|
43
|
+
FRAMEWORK: "express",
|
|
44
|
+
|
|
45
|
+
// Testing Configuration
|
|
46
|
+
// Options: jest, mocha, vitest
|
|
47
|
+
TEST_FRAMEWORK: "jest",
|
|
48
|
+
|
|
49
|
+
// Test Directory
|
|
50
|
+
TEST_DIRECTORY: "tests"
|
|
51
|
+
};
|
|
52
|
+
`;
|
|
53
|
+
fs.writeFileSync(configPath, content);
|
|
54
|
+
console.log(chalk.green(`✓ Created tng.config.js`));
|
|
55
|
+
});
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* @command ping
|
|
59
|
+
* Verify API connectivity
|
|
60
|
+
*/
|
|
61
|
+
program
|
|
62
|
+
.command('ping')
|
|
63
|
+
.description('Verify API connectivity')
|
|
64
|
+
.action(() => {
|
|
65
|
+
const config = loadConfig();
|
|
66
|
+
if (!config.API_KEY) {
|
|
67
|
+
console.log(chalk.red('No API key configured. Run: tng init'));
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
console.log(chalk.blue('Pinging TNG API...'));
|
|
72
|
+
try {
|
|
73
|
+
const result = ping(config.API_URL, config.API_KEY);
|
|
74
|
+
console.log(chalk.green(`✓ API Response: ${result}`));
|
|
75
|
+
} catch (error) {
|
|
76
|
+
console.log(chalk.red(`✗ Ping failed: ${error.message}`));
|
|
77
|
+
}
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* @command stats
|
|
82
|
+
* Show user statistics
|
|
83
|
+
*/
|
|
84
|
+
program
|
|
85
|
+
.command('stats')
|
|
86
|
+
.description('Show user statistics')
|
|
87
|
+
.action(() => {
|
|
88
|
+
const config = loadConfig();
|
|
89
|
+
if (!config.API_KEY) {
|
|
90
|
+
console.log(chalk.red('No API key configured. Run: tng init'));
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
console.log(chalk.blue('Fetching user stats...'));
|
|
95
|
+
try {
|
|
96
|
+
const statsJson = getUserStats(config.API_URL, config.API_KEY);
|
|
97
|
+
const stats = JSON.parse(statsJson);
|
|
98
|
+
|
|
99
|
+
console.log(chalk.bold('\n--- TNG User Statistics ---'));
|
|
100
|
+
console.log(`User ID: ${chalk.cyan(stats.user_id || 'N/A')}`);
|
|
101
|
+
console.log(`Email: ${chalk.cyan(stats.email || 'N/A')}`);
|
|
102
|
+
console.log(`Plan: ${chalk.cyan(stats.plan || 'Free')}`);
|
|
103
|
+
console.log(`Generations: ${chalk.green(stats.generations_count || 0)} / ${stats.generations_limit || '∞'}`);
|
|
104
|
+
console.log(`Status: ${stats.active ? chalk.green('Active') : chalk.red('Inactive')}`);
|
|
105
|
+
console.log('---------------------------\n');
|
|
106
|
+
} catch (error) {
|
|
107
|
+
console.log(chalk.red(`✗ Failed to fetch stats: ${error.message}`));
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
const GenerateTestsUI = require('../lib/generateTestsUi');
|
|
112
|
+
|
|
113
|
+
function launchInteractive() {
|
|
114
|
+
const ui = new GenerateTestsUI();
|
|
115
|
+
ui.show().catch(err => {
|
|
116
|
+
console.error(chalk.red('\nInteractive UI Error:'), err.message);
|
|
117
|
+
process.exit(1);
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
program
|
|
122
|
+
.command('i')
|
|
123
|
+
.alias('interactive')
|
|
124
|
+
.description('Launch interactive UI')
|
|
125
|
+
.action(() => {
|
|
126
|
+
launchInteractive();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Main command handler (handles -f and -m)
|
|
131
|
+
*/
|
|
132
|
+
program
|
|
133
|
+
.option('-m, --method <name>', 'Method name to test')
|
|
134
|
+
.option('-f, --file <path>', 'JavaScript file path')
|
|
135
|
+
.option('-t, --type <type>', 'Component type (react_component, express_handler, etc)')
|
|
136
|
+
.option('-a, --audit', 'Run audit mode instead of test generation')
|
|
137
|
+
.option('--json', 'Output results as JSON events (machine-readable)')
|
|
138
|
+
.option('--outline', 'Output file outline (methods/classes) in JSON format')
|
|
139
|
+
.action(async (options) => {
|
|
140
|
+
if (options.file && options.outline) {
|
|
141
|
+
printOutline(options.file);
|
|
142
|
+
} else if (options.method && options.file) {
|
|
143
|
+
generateTest(options.file, options.method, options.type, options.audit, options.json);
|
|
144
|
+
} else if (options.file && !options.method) {
|
|
145
|
+
console.log(chalk.yellow('Specify a method with -m, use --outline to see methods, or run "tng i" for full selection.'));
|
|
146
|
+
} else if (!options.file && !options.method && process.argv.length <= 2) {
|
|
147
|
+
launchInteractive();
|
|
148
|
+
}
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Output file outline (methods)
|
|
153
|
+
*/
|
|
154
|
+
function printOutline(filePath) {
|
|
155
|
+
const absolutePath = path.resolve(filePath);
|
|
156
|
+
if (!fs.existsSync(absolutePath)) {
|
|
157
|
+
console.error(chalk.red(`File not found: ${filePath}`));
|
|
158
|
+
process.exit(1);
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
const { getFileOutline } = require('../index');
|
|
162
|
+
try {
|
|
163
|
+
const outlineJson = getFileOutline(absolutePath);
|
|
164
|
+
console.log(outlineJson);
|
|
165
|
+
} catch (error) {
|
|
166
|
+
console.error(chalk.red(`Error getting outline: ${error.message}`));
|
|
167
|
+
process.exit(1);
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Logic to generate test or run audit (delegates to native binary)
|
|
173
|
+
*/
|
|
174
|
+
async function generateTest(filePath, methodName, testType, auditMode = false, jsonMode = false) {
|
|
175
|
+
const config = loadConfig();
|
|
176
|
+
|
|
177
|
+
// Initialize JSON session if requested
|
|
178
|
+
const jsonSession = jsonMode ? new (require('../lib/jsonSession').JsonSession)() : null;
|
|
179
|
+
|
|
180
|
+
if (jsonSession) {
|
|
181
|
+
jsonSession.start();
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
if (!config.API_KEY) {
|
|
185
|
+
const message = 'No API key configured. Run: tng init';
|
|
186
|
+
if (jsonSession) {
|
|
187
|
+
jsonSession.showConfigError('API_KEY');
|
|
188
|
+
jsonSession.stop();
|
|
189
|
+
} else {
|
|
190
|
+
console.log(chalk.red(message));
|
|
191
|
+
}
|
|
192
|
+
process.exit(1);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
const absolutePath = path.resolve(filePath);
|
|
196
|
+
if (!fs.existsSync(absolutePath)) {
|
|
197
|
+
const message = `File not found: ${filePath}`;
|
|
198
|
+
if (jsonSession) {
|
|
199
|
+
jsonSession.displayError(message);
|
|
200
|
+
jsonSession.stop();
|
|
201
|
+
} else {
|
|
202
|
+
console.log(chalk.red(message));
|
|
203
|
+
}
|
|
204
|
+
process.exit(1);
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
const { submitAndPoll } = require('../index');
|
|
208
|
+
|
|
209
|
+
const action = auditMode ? 'Auditing' : 'Generating test for';
|
|
210
|
+
const startMessage = `🔍 ${action} ${methodName} in ${filePath}...`;
|
|
211
|
+
|
|
212
|
+
if (jsonSession) {
|
|
213
|
+
jsonSession.displayInfo(startMessage);
|
|
214
|
+
if (testType) {
|
|
215
|
+
jsonSession.displayInfo(`Type hint: ${testType}`);
|
|
216
|
+
}
|
|
217
|
+
} else {
|
|
218
|
+
console.log(chalk.blue(startMessage));
|
|
219
|
+
if (testType) {
|
|
220
|
+
console.log(chalk.cyan(`ℹ️ Type hint: ${testType}`));
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
try {
|
|
225
|
+
const resultJson = submitAndPoll(
|
|
226
|
+
absolutePath,
|
|
227
|
+
methodName,
|
|
228
|
+
null, // class_name
|
|
229
|
+
testType || null,
|
|
230
|
+
auditMode, // audit_mode
|
|
231
|
+
JSON.stringify(config),
|
|
232
|
+
(msg, percent) => {
|
|
233
|
+
if (jsonSession) {
|
|
234
|
+
// Emit progress events in JSON mode
|
|
235
|
+
const reporter = new (require('../lib/jsonSession').JsonProgressReporter)();
|
|
236
|
+
reporter.update(msg, percent);
|
|
237
|
+
} else {
|
|
238
|
+
// Simple console progress for CLI mode
|
|
239
|
+
if (percent % 10 === 0 || percent === 100) {
|
|
240
|
+
console.log(chalk.cyan(`[${percent}%] ${msg}`));
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
);
|
|
245
|
+
|
|
246
|
+
if (auditMode) {
|
|
247
|
+
// In audit mode, display the results
|
|
248
|
+
const result = JSON.parse(resultJson);
|
|
249
|
+
if (jsonSession) {
|
|
250
|
+
jsonSession.showAuditResults(result);
|
|
251
|
+
jsonSession.stop();
|
|
252
|
+
} else {
|
|
253
|
+
console.log(chalk.green('\n✓ Audit complete!\n'));
|
|
254
|
+
console.log(JSON.stringify(result, null, 2));
|
|
255
|
+
}
|
|
256
|
+
} else {
|
|
257
|
+
// In test generation mode, save the file
|
|
258
|
+
const saved = await saveTestFile(resultJson);
|
|
259
|
+
|
|
260
|
+
if (jsonSession) {
|
|
261
|
+
if (saved) {
|
|
262
|
+
jsonSession.emitEvent('test_saved', {
|
|
263
|
+
file_path: saved.file_path,
|
|
264
|
+
message: `Test saved to: ${saved.file_path}`
|
|
265
|
+
});
|
|
266
|
+
} else {
|
|
267
|
+
jsonSession.displayError('Failed to save test file');
|
|
268
|
+
}
|
|
269
|
+
jsonSession.stop();
|
|
270
|
+
} else {
|
|
271
|
+
if (saved) {
|
|
272
|
+
console.log(chalk.green(`✓ Test saved to: ${saved.file_path}`));
|
|
273
|
+
} else {
|
|
274
|
+
console.log(chalk.yellow('Failed to save test file'));
|
|
275
|
+
}
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
} catch (error) {
|
|
279
|
+
if (jsonSession) {
|
|
280
|
+
jsonSession.displayError(error.message);
|
|
281
|
+
jsonSession.stop();
|
|
282
|
+
} else {
|
|
283
|
+
console.log(chalk.red(`Error: ${error.message}`));
|
|
284
|
+
}
|
|
285
|
+
process.exit(1);
|
|
286
|
+
}
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
program.parse(process.argv);
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/index.d.ts
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
|
|
4
|
+
/* auto-generated by NAPI-RS */
|
|
5
|
+
|
|
6
|
+
export declare function getFileOutline(filePath: string): string
|
|
7
|
+
export declare function getProjectMetadata(projectRoot: string): string
|
|
8
|
+
export declare function findCallSites(projectRoot: string, methodName: string): string
|
|
9
|
+
export declare function ping(baseUrl: string, apiKey?: string | undefined | null): string
|
|
10
|
+
export declare function submitJob(baseUrl: string, apiKey: string, payloadJson: string): number
|
|
11
|
+
export declare function getUserStats(baseUrl: string, apiKey: string): string
|
|
12
|
+
export declare function submitAndPoll(filePath: string, methodName: string, className: string | undefined | null, testType: string | undefined | null, auditMode: boolean, configJson: string, callback: (...args: any[]) => any): string
|
package/index.js
ADDED
|
@@ -0,0 +1,321 @@
|
|
|
1
|
+
/* tslint:disable */
|
|
2
|
+
/* eslint-disable */
|
|
3
|
+
/* prettier-ignore */
|
|
4
|
+
|
|
5
|
+
/* auto-generated by NAPI-RS */
|
|
6
|
+
|
|
7
|
+
const { existsSync, readFileSync } = require('fs')
|
|
8
|
+
const { join } = require('path')
|
|
9
|
+
|
|
10
|
+
const { platform, arch } = process
|
|
11
|
+
|
|
12
|
+
let nativeBinding = null
|
|
13
|
+
let localFileExisted = false
|
|
14
|
+
let loadError = null
|
|
15
|
+
|
|
16
|
+
function isMusl() {
|
|
17
|
+
// For Node 10
|
|
18
|
+
if (!process.report || typeof process.report.getReport !== 'function') {
|
|
19
|
+
try {
|
|
20
|
+
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
|
21
|
+
return readFileSync(lddPath, 'utf8').includes('musl')
|
|
22
|
+
} catch (e) {
|
|
23
|
+
return true
|
|
24
|
+
}
|
|
25
|
+
} else {
|
|
26
|
+
const { glibcVersionRuntime } = process.report.getReport().header
|
|
27
|
+
return !glibcVersionRuntime
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
switch (platform) {
|
|
32
|
+
case 'android':
|
|
33
|
+
switch (arch) {
|
|
34
|
+
case 'arm64':
|
|
35
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node'))
|
|
36
|
+
try {
|
|
37
|
+
if (localFileExisted) {
|
|
38
|
+
nativeBinding = require('./index.android-arm64.node')
|
|
39
|
+
} else {
|
|
40
|
+
nativeBinding = require('@tng-sh/js-android-arm64')
|
|
41
|
+
}
|
|
42
|
+
} catch (e) {
|
|
43
|
+
loadError = e
|
|
44
|
+
}
|
|
45
|
+
break
|
|
46
|
+
case 'arm':
|
|
47
|
+
localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node'))
|
|
48
|
+
try {
|
|
49
|
+
if (localFileExisted) {
|
|
50
|
+
nativeBinding = require('./index.android-arm-eabi.node')
|
|
51
|
+
} else {
|
|
52
|
+
nativeBinding = require('@tng-sh/js-android-arm-eabi')
|
|
53
|
+
}
|
|
54
|
+
} catch (e) {
|
|
55
|
+
loadError = e
|
|
56
|
+
}
|
|
57
|
+
break
|
|
58
|
+
default:
|
|
59
|
+
throw new Error(`Unsupported architecture on Android ${arch}`)
|
|
60
|
+
}
|
|
61
|
+
break
|
|
62
|
+
case 'win32':
|
|
63
|
+
switch (arch) {
|
|
64
|
+
case 'x64':
|
|
65
|
+
localFileExisted = existsSync(
|
|
66
|
+
join(__dirname, 'index.win32-x64-msvc.node')
|
|
67
|
+
)
|
|
68
|
+
try {
|
|
69
|
+
if (localFileExisted) {
|
|
70
|
+
nativeBinding = require('./index.win32-x64-msvc.node')
|
|
71
|
+
} else {
|
|
72
|
+
nativeBinding = require('@tng-sh/js-win32-x64-msvc')
|
|
73
|
+
}
|
|
74
|
+
} catch (e) {
|
|
75
|
+
loadError = e
|
|
76
|
+
}
|
|
77
|
+
break
|
|
78
|
+
case 'ia32':
|
|
79
|
+
localFileExisted = existsSync(
|
|
80
|
+
join(__dirname, 'index.win32-ia32-msvc.node')
|
|
81
|
+
)
|
|
82
|
+
try {
|
|
83
|
+
if (localFileExisted) {
|
|
84
|
+
nativeBinding = require('./index.win32-ia32-msvc.node')
|
|
85
|
+
} else {
|
|
86
|
+
nativeBinding = require('@tng-sh/js-win32-ia32-msvc')
|
|
87
|
+
}
|
|
88
|
+
} catch (e) {
|
|
89
|
+
loadError = e
|
|
90
|
+
}
|
|
91
|
+
break
|
|
92
|
+
case 'arm64':
|
|
93
|
+
localFileExisted = existsSync(
|
|
94
|
+
join(__dirname, 'index.win32-arm64-msvc.node')
|
|
95
|
+
)
|
|
96
|
+
try {
|
|
97
|
+
if (localFileExisted) {
|
|
98
|
+
nativeBinding = require('./index.win32-arm64-msvc.node')
|
|
99
|
+
} else {
|
|
100
|
+
nativeBinding = require('@tng-sh/js-win32-arm64-msvc')
|
|
101
|
+
}
|
|
102
|
+
} catch (e) {
|
|
103
|
+
loadError = e
|
|
104
|
+
}
|
|
105
|
+
break
|
|
106
|
+
default:
|
|
107
|
+
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
|
108
|
+
}
|
|
109
|
+
break
|
|
110
|
+
case 'darwin':
|
|
111
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node'))
|
|
112
|
+
try {
|
|
113
|
+
if (localFileExisted) {
|
|
114
|
+
nativeBinding = require('./index.darwin-universal.node')
|
|
115
|
+
} else {
|
|
116
|
+
nativeBinding = require('@tng-sh/js-darwin-universal')
|
|
117
|
+
}
|
|
118
|
+
break
|
|
119
|
+
} catch {}
|
|
120
|
+
switch (arch) {
|
|
121
|
+
case 'x64':
|
|
122
|
+
localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node'))
|
|
123
|
+
try {
|
|
124
|
+
if (localFileExisted) {
|
|
125
|
+
nativeBinding = require('./index.darwin-x64.node')
|
|
126
|
+
} else {
|
|
127
|
+
nativeBinding = require('@tng-sh/js-darwin-x64')
|
|
128
|
+
}
|
|
129
|
+
} catch (e) {
|
|
130
|
+
loadError = e
|
|
131
|
+
}
|
|
132
|
+
break
|
|
133
|
+
case 'arm64':
|
|
134
|
+
localFileExisted = existsSync(
|
|
135
|
+
join(__dirname, 'index.darwin-arm64.node')
|
|
136
|
+
)
|
|
137
|
+
try {
|
|
138
|
+
if (localFileExisted) {
|
|
139
|
+
nativeBinding = require('./index.darwin-arm64.node')
|
|
140
|
+
} else {
|
|
141
|
+
nativeBinding = require('@tng-sh/js-darwin-arm64')
|
|
142
|
+
}
|
|
143
|
+
} catch (e) {
|
|
144
|
+
loadError = e
|
|
145
|
+
}
|
|
146
|
+
break
|
|
147
|
+
default:
|
|
148
|
+
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
|
149
|
+
}
|
|
150
|
+
break
|
|
151
|
+
case 'freebsd':
|
|
152
|
+
if (arch !== 'x64') {
|
|
153
|
+
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
|
154
|
+
}
|
|
155
|
+
localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node'))
|
|
156
|
+
try {
|
|
157
|
+
if (localFileExisted) {
|
|
158
|
+
nativeBinding = require('./index.freebsd-x64.node')
|
|
159
|
+
} else {
|
|
160
|
+
nativeBinding = require('@tng-sh/js-freebsd-x64')
|
|
161
|
+
}
|
|
162
|
+
} catch (e) {
|
|
163
|
+
loadError = e
|
|
164
|
+
}
|
|
165
|
+
break
|
|
166
|
+
case 'linux':
|
|
167
|
+
switch (arch) {
|
|
168
|
+
case 'x64':
|
|
169
|
+
if (isMusl()) {
|
|
170
|
+
localFileExisted = existsSync(
|
|
171
|
+
join(__dirname, 'index.linux-x64-musl.node')
|
|
172
|
+
)
|
|
173
|
+
try {
|
|
174
|
+
if (localFileExisted) {
|
|
175
|
+
nativeBinding = require('./index.linux-x64-musl.node')
|
|
176
|
+
} else {
|
|
177
|
+
nativeBinding = require('@tng-sh/js-linux-x64-musl')
|
|
178
|
+
}
|
|
179
|
+
} catch (e) {
|
|
180
|
+
loadError = e
|
|
181
|
+
}
|
|
182
|
+
} else {
|
|
183
|
+
localFileExisted = existsSync(
|
|
184
|
+
join(__dirname, 'index.linux-x64-gnu.node')
|
|
185
|
+
)
|
|
186
|
+
try {
|
|
187
|
+
if (localFileExisted) {
|
|
188
|
+
nativeBinding = require('./index.linux-x64-gnu.node')
|
|
189
|
+
} else {
|
|
190
|
+
nativeBinding = require('@tng-sh/js-linux-x64-gnu')
|
|
191
|
+
}
|
|
192
|
+
} catch (e) {
|
|
193
|
+
loadError = e
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
break
|
|
197
|
+
case 'arm64':
|
|
198
|
+
if (isMusl()) {
|
|
199
|
+
localFileExisted = existsSync(
|
|
200
|
+
join(__dirname, 'index.linux-arm64-musl.node')
|
|
201
|
+
)
|
|
202
|
+
try {
|
|
203
|
+
if (localFileExisted) {
|
|
204
|
+
nativeBinding = require('./index.linux-arm64-musl.node')
|
|
205
|
+
} else {
|
|
206
|
+
nativeBinding = require('@tng-sh/js-linux-arm64-musl')
|
|
207
|
+
}
|
|
208
|
+
} catch (e) {
|
|
209
|
+
loadError = e
|
|
210
|
+
}
|
|
211
|
+
} else {
|
|
212
|
+
localFileExisted = existsSync(
|
|
213
|
+
join(__dirname, 'index.linux-arm64-gnu.node')
|
|
214
|
+
)
|
|
215
|
+
try {
|
|
216
|
+
if (localFileExisted) {
|
|
217
|
+
nativeBinding = require('./index.linux-arm64-gnu.node')
|
|
218
|
+
} else {
|
|
219
|
+
nativeBinding = require('@tng-sh/js-linux-arm64-gnu')
|
|
220
|
+
}
|
|
221
|
+
} catch (e) {
|
|
222
|
+
loadError = e
|
|
223
|
+
}
|
|
224
|
+
}
|
|
225
|
+
break
|
|
226
|
+
case 'arm':
|
|
227
|
+
if (isMusl()) {
|
|
228
|
+
localFileExisted = existsSync(
|
|
229
|
+
join(__dirname, 'index.linux-arm-musleabihf.node')
|
|
230
|
+
)
|
|
231
|
+
try {
|
|
232
|
+
if (localFileExisted) {
|
|
233
|
+
nativeBinding = require('./index.linux-arm-musleabihf.node')
|
|
234
|
+
} else {
|
|
235
|
+
nativeBinding = require('@tng-sh/js-linux-arm-musleabihf')
|
|
236
|
+
}
|
|
237
|
+
} catch (e) {
|
|
238
|
+
loadError = e
|
|
239
|
+
}
|
|
240
|
+
} else {
|
|
241
|
+
localFileExisted = existsSync(
|
|
242
|
+
join(__dirname, 'index.linux-arm-gnueabihf.node')
|
|
243
|
+
)
|
|
244
|
+
try {
|
|
245
|
+
if (localFileExisted) {
|
|
246
|
+
nativeBinding = require('./index.linux-arm-gnueabihf.node')
|
|
247
|
+
} else {
|
|
248
|
+
nativeBinding = require('@tng-sh/js-linux-arm-gnueabihf')
|
|
249
|
+
}
|
|
250
|
+
} catch (e) {
|
|
251
|
+
loadError = e
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
break
|
|
255
|
+
case 'riscv64':
|
|
256
|
+
if (isMusl()) {
|
|
257
|
+
localFileExisted = existsSync(
|
|
258
|
+
join(__dirname, 'index.linux-riscv64-musl.node')
|
|
259
|
+
)
|
|
260
|
+
try {
|
|
261
|
+
if (localFileExisted) {
|
|
262
|
+
nativeBinding = require('./index.linux-riscv64-musl.node')
|
|
263
|
+
} else {
|
|
264
|
+
nativeBinding = require('@tng-sh/js-linux-riscv64-musl')
|
|
265
|
+
}
|
|
266
|
+
} catch (e) {
|
|
267
|
+
loadError = e
|
|
268
|
+
}
|
|
269
|
+
} else {
|
|
270
|
+
localFileExisted = existsSync(
|
|
271
|
+
join(__dirname, 'index.linux-riscv64-gnu.node')
|
|
272
|
+
)
|
|
273
|
+
try {
|
|
274
|
+
if (localFileExisted) {
|
|
275
|
+
nativeBinding = require('./index.linux-riscv64-gnu.node')
|
|
276
|
+
} else {
|
|
277
|
+
nativeBinding = require('@tng-sh/js-linux-riscv64-gnu')
|
|
278
|
+
}
|
|
279
|
+
} catch (e) {
|
|
280
|
+
loadError = e
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
break
|
|
284
|
+
case 's390x':
|
|
285
|
+
localFileExisted = existsSync(
|
|
286
|
+
join(__dirname, 'index.linux-s390x-gnu.node')
|
|
287
|
+
)
|
|
288
|
+
try {
|
|
289
|
+
if (localFileExisted) {
|
|
290
|
+
nativeBinding = require('./index.linux-s390x-gnu.node')
|
|
291
|
+
} else {
|
|
292
|
+
nativeBinding = require('@tng-sh/js-linux-s390x-gnu')
|
|
293
|
+
}
|
|
294
|
+
} catch (e) {
|
|
295
|
+
loadError = e
|
|
296
|
+
}
|
|
297
|
+
break
|
|
298
|
+
default:
|
|
299
|
+
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
|
300
|
+
}
|
|
301
|
+
break
|
|
302
|
+
default:
|
|
303
|
+
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
if (!nativeBinding) {
|
|
307
|
+
if (loadError) {
|
|
308
|
+
throw loadError
|
|
309
|
+
}
|
|
310
|
+
throw new Error(`Failed to load native binding`)
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
const { getFileOutline, getProjectMetadata, findCallSites, ping, submitJob, getUserStats, submitAndPoll } = nativeBinding
|
|
314
|
+
|
|
315
|
+
module.exports.getFileOutline = getFileOutline
|
|
316
|
+
module.exports.getProjectMetadata = getProjectMetadata
|
|
317
|
+
module.exports.findCallSites = findCallSites
|
|
318
|
+
module.exports.ping = ping
|
|
319
|
+
module.exports.submitJob = submitJob
|
|
320
|
+
module.exports.getUserStats = getUserStats
|
|
321
|
+
module.exports.submitAndPoll = submitAndPoll
|
package/lib/config.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
const path = require('path');
|
|
2
|
+
const fs = require('fs');
|
|
3
|
+
|
|
4
|
+
const loadConfig = () => {
|
|
5
|
+
const configFile = path.join(process.cwd(), 'tng.config.js');
|
|
6
|
+
|
|
7
|
+
if (!fs.existsSync(configFile)) {
|
|
8
|
+
return {};
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
try {
|
|
12
|
+
// Clear cache to allow reloading config in same process if needed (rare for CLI but good practice)
|
|
13
|
+
delete require.cache[require.resolve(configFile)];
|
|
14
|
+
const config = require(configFile);
|
|
15
|
+
|
|
16
|
+
// Filter for uppercase keys to match Python's convention,
|
|
17
|
+
// but fallback to the whole object if none are uppercase.
|
|
18
|
+
const filtered = {};
|
|
19
|
+
for (const [key, value] of Object.entries(config)) {
|
|
20
|
+
if (key === key.toUpperCase()) {
|
|
21
|
+
filtered[key] = value;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
return Object.keys(filtered).length > 0 ? filtered : config;
|
|
26
|
+
} catch (error) {
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
module.exports = { loadConfig };
|