projax 0.1.29
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/LINKING.md +86 -0
- package/README.md +141 -0
- package/dist/core/database.d.ts +66 -0
- package/dist/core/database.js +312 -0
- package/dist/core/detector.d.ts +9 -0
- package/dist/core/detector.js +149 -0
- package/dist/core/index.d.ts +11 -0
- package/dist/core/index.js +43 -0
- package/dist/core/scanner.d.ts +8 -0
- package/dist/core/scanner.js +114 -0
- package/dist/electron/main.d.ts +1 -0
- package/dist/electron/main.js +310 -0
- package/dist/electron/port-extractor.d.ts +9 -0
- package/dist/electron/port-extractor.js +351 -0
- package/dist/electron/port-scanner.d.ts +13 -0
- package/dist/electron/port-scanner.js +93 -0
- package/dist/electron/port-utils.d.ts +21 -0
- package/dist/electron/port-utils.js +200 -0
- package/dist/electron/preload.d.ts +49 -0
- package/dist/electron/preload.js +21 -0
- package/dist/electron/renderer/assets/index-BZ6USRnW.js +42 -0
- package/dist/electron/renderer/assets/index-DNtxfrZe.js +42 -0
- package/dist/electron/renderer/assets/index-khk3K-qG.css +1 -0
- package/dist/electron/renderer/index.html +15 -0
- package/dist/electron/script-runner.d.ts +40 -0
- package/dist/electron/script-runner.js +651 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +971 -0
- package/dist/port-extractor.d.ts +9 -0
- package/dist/port-extractor.js +351 -0
- package/dist/port-scanner.d.ts +13 -0
- package/dist/port-scanner.js +93 -0
- package/dist/port-utils.d.ts +21 -0
- package/dist/port-utils.js +200 -0
- package/dist/script-runner.d.ts +40 -0
- package/dist/script-runner.js +651 -0
- package/package.json +40 -0
- package/rebuild-sqlite.js +82 -0
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.FRAMEWORKS = void 0;
|
|
37
|
+
exports.detectTestFramework = detectTestFramework;
|
|
38
|
+
exports.isTestFile = isTestFile;
|
|
39
|
+
const fs = __importStar(require("fs"));
|
|
40
|
+
const path = __importStar(require("path"));
|
|
41
|
+
exports.FRAMEWORKS = [
|
|
42
|
+
{
|
|
43
|
+
name: 'jest',
|
|
44
|
+
configFiles: ['jest.config.js', 'jest.config.ts', 'jest.config.json', 'jest.config.mjs', 'jest.config.cjs'],
|
|
45
|
+
testPatterns: [
|
|
46
|
+
/\.test\.(js|ts|jsx|tsx)$/i,
|
|
47
|
+
/\.spec\.(js|ts|jsx|tsx)$/i,
|
|
48
|
+
],
|
|
49
|
+
testDirs: ['__tests__', '__test__'],
|
|
50
|
+
},
|
|
51
|
+
{
|
|
52
|
+
name: 'vitest',
|
|
53
|
+
configFiles: ['vitest.config.ts', 'vitest.config.js', 'vitest.config.mjs'],
|
|
54
|
+
testPatterns: [
|
|
55
|
+
/\.test\.(js|ts|jsx|tsx)$/i,
|
|
56
|
+
/\.spec\.(js|ts|jsx|tsx)$/i,
|
|
57
|
+
],
|
|
58
|
+
testDirs: ['__tests__'],
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'mocha',
|
|
62
|
+
configFiles: ['.mocharc.js', '.mocharc.json', '.mocharc.yaml', '.mocharc.yml', 'mocha.opts'],
|
|
63
|
+
testPatterns: [
|
|
64
|
+
/\.test\.(js|ts|jsx|tsx)$/i,
|
|
65
|
+
/\.spec\.(js|ts|jsx|tsx)$/i,
|
|
66
|
+
],
|
|
67
|
+
testDirs: ['test', 'tests'],
|
|
68
|
+
},
|
|
69
|
+
];
|
|
70
|
+
function detectTestFramework(projectPath) {
|
|
71
|
+
const packageJsonPath = path.join(projectPath, 'package.json');
|
|
72
|
+
// Check package.json for test scripts and dependencies
|
|
73
|
+
if (fs.existsSync(packageJsonPath)) {
|
|
74
|
+
try {
|
|
75
|
+
const packageJson = JSON.parse(fs.readFileSync(packageJsonPath, 'utf-8'));
|
|
76
|
+
// Check dependencies and devDependencies
|
|
77
|
+
const deps = { ...packageJson.dependencies, ...packageJson.devDependencies };
|
|
78
|
+
if (deps.jest)
|
|
79
|
+
return 'jest';
|
|
80
|
+
if (deps.vitest)
|
|
81
|
+
return 'vitest';
|
|
82
|
+
if (deps.mocha)
|
|
83
|
+
return 'mocha';
|
|
84
|
+
// Check for jest config in package.json
|
|
85
|
+
if (packageJson.jest)
|
|
86
|
+
return 'jest';
|
|
87
|
+
// Check test scripts
|
|
88
|
+
if (packageJson.scripts) {
|
|
89
|
+
const testScript = packageJson.scripts.test || '';
|
|
90
|
+
if (testScript.includes('jest'))
|
|
91
|
+
return 'jest';
|
|
92
|
+
if (testScript.includes('vitest'))
|
|
93
|
+
return 'vitest';
|
|
94
|
+
if (testScript.includes('mocha'))
|
|
95
|
+
return 'mocha';
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
catch (error) {
|
|
99
|
+
// Invalid JSON, continue with file-based detection
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
// Check for config files
|
|
103
|
+
for (const framework of exports.FRAMEWORKS) {
|
|
104
|
+
for (const configFile of framework.configFiles) {
|
|
105
|
+
const configPath = path.join(projectPath, configFile);
|
|
106
|
+
if (fs.existsSync(configPath)) {
|
|
107
|
+
return framework.name;
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
function isTestFile(filePath, detectedFramework = null) {
|
|
114
|
+
const fileName = path.basename(filePath);
|
|
115
|
+
const dirName = path.dirname(filePath);
|
|
116
|
+
const parentDirName = path.basename(dirName);
|
|
117
|
+
// If framework is detected, use its specific patterns
|
|
118
|
+
if (detectedFramework) {
|
|
119
|
+
const framework = exports.FRAMEWORKS.find(f => f.name === detectedFramework);
|
|
120
|
+
if (framework) {
|
|
121
|
+
// Check test patterns
|
|
122
|
+
for (const pattern of framework.testPatterns) {
|
|
123
|
+
if (pattern.test(fileName)) {
|
|
124
|
+
return true;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Check test directories
|
|
128
|
+
for (const testDir of framework.testDirs) {
|
|
129
|
+
if (parentDirName === testDir) {
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
// Fallback: check all common patterns
|
|
136
|
+
for (const framework of exports.FRAMEWORKS) {
|
|
137
|
+
for (const pattern of framework.testPatterns) {
|
|
138
|
+
if (pattern.test(fileName)) {
|
|
139
|
+
return true;
|
|
140
|
+
}
|
|
141
|
+
}
|
|
142
|
+
for (const testDir of framework.testDirs) {
|
|
143
|
+
if (parentDirName === testDir) {
|
|
144
|
+
return true;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
return false;
|
|
149
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './database';
|
|
2
|
+
export * from './detector';
|
|
3
|
+
export * from './scanner';
|
|
4
|
+
export { getDatabaseManager } from './database';
|
|
5
|
+
import { Project, Test } from './database';
|
|
6
|
+
import { scanProject, scanAllProjects } from './scanner';
|
|
7
|
+
export declare function getAllProjects(): Project[];
|
|
8
|
+
export declare function addProject(name: string, projectPath: string): Project;
|
|
9
|
+
export declare function removeProject(id: number): void;
|
|
10
|
+
export declare function getTestsByProject(projectId: number): Test[];
|
|
11
|
+
export { scanProject, scanAllProjects };
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
14
|
+
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
|
+
};
|
|
16
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.scanAllProjects = exports.scanProject = exports.getDatabaseManager = void 0;
|
|
18
|
+
exports.getAllProjects = getAllProjects;
|
|
19
|
+
exports.addProject = addProject;
|
|
20
|
+
exports.removeProject = removeProject;
|
|
21
|
+
exports.getTestsByProject = getTestsByProject;
|
|
22
|
+
__exportStar(require("./database"), exports);
|
|
23
|
+
__exportStar(require("./detector"), exports);
|
|
24
|
+
__exportStar(require("./scanner"), exports);
|
|
25
|
+
var database_1 = require("./database");
|
|
26
|
+
Object.defineProperty(exports, "getDatabaseManager", { enumerable: true, get: function () { return database_1.getDatabaseManager; } });
|
|
27
|
+
// Convenience functions for common operations
|
|
28
|
+
const database_2 = require("./database");
|
|
29
|
+
const scanner_1 = require("./scanner");
|
|
30
|
+
Object.defineProperty(exports, "scanProject", { enumerable: true, get: function () { return scanner_1.scanProject; } });
|
|
31
|
+
Object.defineProperty(exports, "scanAllProjects", { enumerable: true, get: function () { return scanner_1.scanAllProjects; } });
|
|
32
|
+
function getAllProjects() {
|
|
33
|
+
return (0, database_2.getDatabaseManager)().getAllProjects();
|
|
34
|
+
}
|
|
35
|
+
function addProject(name, projectPath) {
|
|
36
|
+
return (0, database_2.getDatabaseManager)().addProject(name, projectPath);
|
|
37
|
+
}
|
|
38
|
+
function removeProject(id) {
|
|
39
|
+
(0, database_2.getDatabaseManager)().removeProject(id);
|
|
40
|
+
}
|
|
41
|
+
function getTestsByProject(projectId) {
|
|
42
|
+
return (0, database_2.getDatabaseManager)().getTestsByProject(projectId);
|
|
43
|
+
}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { Project, Test } from './database';
|
|
2
|
+
export interface ScanResult {
|
|
3
|
+
project: Project;
|
|
4
|
+
testsFound: number;
|
|
5
|
+
tests: Test[];
|
|
6
|
+
}
|
|
7
|
+
export declare function scanProject(projectId: number): ScanResult;
|
|
8
|
+
export declare function scanAllProjects(): ScanResult[];
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.scanProject = scanProject;
|
|
37
|
+
exports.scanAllProjects = scanAllProjects;
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
const path = __importStar(require("path"));
|
|
40
|
+
const detector_1 = require("./detector");
|
|
41
|
+
const database_1 = require("./database");
|
|
42
|
+
function scanProject(projectId) {
|
|
43
|
+
const db = (0, database_1.getDatabaseManager)();
|
|
44
|
+
const project = db.getProject(projectId);
|
|
45
|
+
if (!project) {
|
|
46
|
+
throw new Error(`Project with id ${projectId} not found`);
|
|
47
|
+
}
|
|
48
|
+
if (!fs.existsSync(project.path)) {
|
|
49
|
+
throw new Error(`Project path does not exist: ${project.path}`);
|
|
50
|
+
}
|
|
51
|
+
// Detect framework first
|
|
52
|
+
const framework = (0, detector_1.detectTestFramework)(project.path);
|
|
53
|
+
// Remove existing tests for this project
|
|
54
|
+
db.removeTestsByProject(projectId);
|
|
55
|
+
// Scan for test files
|
|
56
|
+
const tests = [];
|
|
57
|
+
const testFiles = findTestFiles(project.path, framework);
|
|
58
|
+
for (const testFile of testFiles) {
|
|
59
|
+
const relativePath = path.relative(project.path, testFile);
|
|
60
|
+
const test = db.addTest(projectId, relativePath, framework);
|
|
61
|
+
tests.push(test);
|
|
62
|
+
}
|
|
63
|
+
// Update last scanned timestamp
|
|
64
|
+
db.updateProjectLastScanned(projectId);
|
|
65
|
+
return {
|
|
66
|
+
project: db.getProject(projectId),
|
|
67
|
+
testsFound: tests.length,
|
|
68
|
+
tests,
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
function findTestFiles(dir, framework, results = []) {
|
|
72
|
+
if (!fs.existsSync(dir)) {
|
|
73
|
+
return results;
|
|
74
|
+
}
|
|
75
|
+
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
|
76
|
+
for (const entry of entries) {
|
|
77
|
+
const fullPath = path.join(dir, entry.name);
|
|
78
|
+
// Skip node_modules, .git, and other common ignore directories
|
|
79
|
+
if (entry.isDirectory()) {
|
|
80
|
+
if (entry.name === 'node_modules' ||
|
|
81
|
+
entry.name === '.git' ||
|
|
82
|
+
entry.name === 'dist' ||
|
|
83
|
+
entry.name === 'build' ||
|
|
84
|
+
entry.name === '.next' ||
|
|
85
|
+
entry.name === '.nuxt' ||
|
|
86
|
+
entry.name === 'coverage' ||
|
|
87
|
+
entry.name.startsWith('.')) {
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
findTestFiles(fullPath, framework, results);
|
|
91
|
+
}
|
|
92
|
+
else if (entry.isFile()) {
|
|
93
|
+
if ((0, detector_1.isTestFile)(fullPath, framework)) {
|
|
94
|
+
results.push(fullPath);
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
return results;
|
|
99
|
+
}
|
|
100
|
+
function scanAllProjects() {
|
|
101
|
+
const db = (0, database_1.getDatabaseManager)();
|
|
102
|
+
const projects = db.getAllProjects();
|
|
103
|
+
const results = [];
|
|
104
|
+
for (const project of projects) {
|
|
105
|
+
try {
|
|
106
|
+
const result = scanProject(project.id);
|
|
107
|
+
results.push(result);
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
console.error(`Error scanning project ${project.name}:`, error);
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
return results;
|
|
114
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,310 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
const electron_1 = require("electron");
|
|
37
|
+
const path = __importStar(require("path"));
|
|
38
|
+
const fs = __importStar(require("fs"));
|
|
39
|
+
// Import from bundled core in CLI package, or fallback to @projax/core
|
|
40
|
+
let coreModule;
|
|
41
|
+
try {
|
|
42
|
+
// Try relative import first (when bundled in CLI: dist/electron/main.js -> dist/core)
|
|
43
|
+
coreModule = require('../core');
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
try {
|
|
47
|
+
// Try alternative path (local development: packages/electron/dist/main.js -> packages/cli/dist/core)
|
|
48
|
+
coreModule = require('../../cli/dist/core');
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// Fallback to package import
|
|
52
|
+
coreModule = require('@projax/core');
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
const { getDatabaseManager, getAllProjects, addProject, removeProject, scanProject, scanAllProjects, getTestsByProject, } = coreModule;
|
|
56
|
+
let mainWindow = null;
|
|
57
|
+
// Prevent multiple instances
|
|
58
|
+
const gotTheLock = electron_1.app.requestSingleInstanceLock();
|
|
59
|
+
if (!gotTheLock) {
|
|
60
|
+
electron_1.app.quit();
|
|
61
|
+
}
|
|
62
|
+
else {
|
|
63
|
+
electron_1.app.on('second-instance', () => {
|
|
64
|
+
// Someone tried to run a second instance, focus our window instead
|
|
65
|
+
if (mainWindow) {
|
|
66
|
+
if (mainWindow.isMinimized())
|
|
67
|
+
mainWindow.restore();
|
|
68
|
+
mainWindow.focus();
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
function createWindow() {
|
|
72
|
+
// Don't create a new window if one already exists
|
|
73
|
+
if (mainWindow) {
|
|
74
|
+
mainWindow.focus();
|
|
75
|
+
return;
|
|
76
|
+
}
|
|
77
|
+
const isDev = process.env.NODE_ENV === 'development';
|
|
78
|
+
mainWindow = new electron_1.BrowserWindow({
|
|
79
|
+
width: 1200,
|
|
80
|
+
height: 800,
|
|
81
|
+
frame: false,
|
|
82
|
+
titleBarStyle: process.platform === 'darwin' ? 'hidden' : 'hidden',
|
|
83
|
+
webPreferences: {
|
|
84
|
+
preload: path.join(__dirname, 'preload.js'),
|
|
85
|
+
nodeIntegration: false,
|
|
86
|
+
contextIsolation: true,
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
// Load the app
|
|
90
|
+
if (isDev) {
|
|
91
|
+
mainWindow.loadURL('http://localhost:7898');
|
|
92
|
+
mainWindow.webContents.openDevTools();
|
|
93
|
+
}
|
|
94
|
+
else {
|
|
95
|
+
// Try bundled renderer path first (when bundled in CLI: dist/electron/renderer/index.html)
|
|
96
|
+
// Then try local dev path (packages/electron/dist/renderer/index.html)
|
|
97
|
+
const bundledRenderer = path.join(__dirname, 'renderer', 'index.html');
|
|
98
|
+
const localRenderer = path.join(__dirname, '..', 'renderer', 'index.html');
|
|
99
|
+
if (fs.existsSync(bundledRenderer)) {
|
|
100
|
+
mainWindow.loadFile(bundledRenderer);
|
|
101
|
+
}
|
|
102
|
+
else if (fs.existsSync(localRenderer)) {
|
|
103
|
+
mainWindow.loadFile(localRenderer);
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
console.error('Error: Renderer index.html not found');
|
|
107
|
+
console.error('Bundled path:', bundledRenderer);
|
|
108
|
+
console.error('Local path:', localRenderer);
|
|
109
|
+
electron_1.app.quit();
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
mainWindow.on('closed', () => {
|
|
113
|
+
mainWindow = null;
|
|
114
|
+
});
|
|
115
|
+
}
|
|
116
|
+
electron_1.app.whenReady().then(() => {
|
|
117
|
+
createWindow();
|
|
118
|
+
electron_1.app.on('activate', () => {
|
|
119
|
+
// On macOS, re-create window when dock icon is clicked and no windows are open
|
|
120
|
+
if (electron_1.BrowserWindow.getAllWindows().length === 0) {
|
|
121
|
+
createWindow();
|
|
122
|
+
}
|
|
123
|
+
else if (mainWindow) {
|
|
124
|
+
mainWindow.focus();
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
});
|
|
128
|
+
}
|
|
129
|
+
electron_1.app.on('window-all-closed', () => {
|
|
130
|
+
if (process.platform !== 'darwin') {
|
|
131
|
+
electron_1.app.quit();
|
|
132
|
+
}
|
|
133
|
+
});
|
|
134
|
+
// IPC Handlers
|
|
135
|
+
electron_1.ipcMain.handle('get-projects', async () => {
|
|
136
|
+
try {
|
|
137
|
+
console.log('Getting projects from database...');
|
|
138
|
+
const projects = getAllProjects();
|
|
139
|
+
console.log(`Found ${projects.length} project(s)`);
|
|
140
|
+
return projects;
|
|
141
|
+
}
|
|
142
|
+
catch (error) {
|
|
143
|
+
console.error('Error getting projects:', error);
|
|
144
|
+
throw error;
|
|
145
|
+
}
|
|
146
|
+
});
|
|
147
|
+
electron_1.ipcMain.handle('add-project', async (_, projectPath) => {
|
|
148
|
+
if (!fs.existsSync(projectPath)) {
|
|
149
|
+
throw new Error('Path does not exist');
|
|
150
|
+
}
|
|
151
|
+
if (!fs.statSync(projectPath).isDirectory()) {
|
|
152
|
+
throw new Error('Path must be a directory');
|
|
153
|
+
}
|
|
154
|
+
const db = getDatabaseManager();
|
|
155
|
+
const existingProject = db.getProjectByPath(projectPath);
|
|
156
|
+
if (existingProject) {
|
|
157
|
+
throw new Error('Project already exists');
|
|
158
|
+
}
|
|
159
|
+
const projectName = path.basename(projectPath);
|
|
160
|
+
return db.addProject(projectName, projectPath);
|
|
161
|
+
});
|
|
162
|
+
electron_1.ipcMain.handle('remove-project', async (_, projectId) => {
|
|
163
|
+
removeProject(projectId);
|
|
164
|
+
});
|
|
165
|
+
electron_1.ipcMain.handle('scan-project', async (_, projectId) => {
|
|
166
|
+
return scanProject(projectId);
|
|
167
|
+
});
|
|
168
|
+
electron_1.ipcMain.handle('scan-all-projects', async () => {
|
|
169
|
+
return scanAllProjects();
|
|
170
|
+
});
|
|
171
|
+
electron_1.ipcMain.handle('get-tests', async (_, projectId) => {
|
|
172
|
+
try {
|
|
173
|
+
const db = getDatabaseManager();
|
|
174
|
+
return getTestsByProject(projectId);
|
|
175
|
+
}
|
|
176
|
+
catch (error) {
|
|
177
|
+
console.error('Error getting tests:', error);
|
|
178
|
+
throw error;
|
|
179
|
+
}
|
|
180
|
+
});
|
|
181
|
+
electron_1.ipcMain.handle('select-directory', async () => {
|
|
182
|
+
if (!mainWindow)
|
|
183
|
+
return null;
|
|
184
|
+
const result = await electron_1.dialog.showOpenDialog(mainWindow, {
|
|
185
|
+
properties: ['openDirectory'],
|
|
186
|
+
});
|
|
187
|
+
if (result.canceled || result.filePaths.length === 0) {
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
return result.filePaths[0];
|
|
191
|
+
});
|
|
192
|
+
// Window controls
|
|
193
|
+
electron_1.ipcMain.handle('minimize-window', () => {
|
|
194
|
+
if (mainWindow) {
|
|
195
|
+
mainWindow.minimize();
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
electron_1.ipcMain.handle('maximize-window', () => {
|
|
199
|
+
if (mainWindow) {
|
|
200
|
+
if (mainWindow.isMaximized()) {
|
|
201
|
+
mainWindow.unmaximize();
|
|
202
|
+
}
|
|
203
|
+
else {
|
|
204
|
+
mainWindow.maximize();
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
});
|
|
208
|
+
electron_1.ipcMain.handle('close-window', () => {
|
|
209
|
+
if (mainWindow) {
|
|
210
|
+
mainWindow.close();
|
|
211
|
+
}
|
|
212
|
+
});
|
|
213
|
+
// Rename project
|
|
214
|
+
electron_1.ipcMain.handle('rename-project', async (_, projectId, newName) => {
|
|
215
|
+
const db = getDatabaseManager();
|
|
216
|
+
return db.updateProjectName(projectId, newName);
|
|
217
|
+
});
|
|
218
|
+
// Get project scripts
|
|
219
|
+
electron_1.ipcMain.handle('get-project-scripts', async (_, projectPath) => {
|
|
220
|
+
// Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
|
|
221
|
+
// Then try local dev path (packages/electron/dist/main.js -> packages/cli/dist/script-runner.js)
|
|
222
|
+
const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
|
|
223
|
+
const localScriptRunnerPath = path.join(__dirname, '..', '..', '..', 'cli', 'dist', 'script-runner.js');
|
|
224
|
+
let scriptRunnerPath;
|
|
225
|
+
if (fs.existsSync(bundledScriptRunnerPath)) {
|
|
226
|
+
scriptRunnerPath = bundledScriptRunnerPath;
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
scriptRunnerPath = localScriptRunnerPath;
|
|
230
|
+
}
|
|
231
|
+
const { getProjectScripts } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
|
|
232
|
+
const result = getProjectScripts(projectPath);
|
|
233
|
+
// Convert Map to array for IPC serialization
|
|
234
|
+
const scriptsArray = Array.from(result.scripts.entries()).map(([name, script]) => ({
|
|
235
|
+
name,
|
|
236
|
+
...script,
|
|
237
|
+
}));
|
|
238
|
+
return {
|
|
239
|
+
type: result.type,
|
|
240
|
+
scripts: scriptsArray,
|
|
241
|
+
};
|
|
242
|
+
});
|
|
243
|
+
// Run script
|
|
244
|
+
electron_1.ipcMain.handle('run-script', async (_, projectPath, scriptName, args = [], background = false) => {
|
|
245
|
+
// Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/script-runner.js)
|
|
246
|
+
// Then try local dev path (packages/electron/dist/main.js -> packages/cli/dist/script-runner.js)
|
|
247
|
+
const bundledScriptRunnerPath = path.join(__dirname, '..', 'script-runner.js');
|
|
248
|
+
const localScriptRunnerPath = path.join(__dirname, '..', '..', '..', 'cli', 'dist', 'script-runner.js');
|
|
249
|
+
let scriptRunnerPath;
|
|
250
|
+
if (fs.existsSync(bundledScriptRunnerPath)) {
|
|
251
|
+
scriptRunnerPath = bundledScriptRunnerPath;
|
|
252
|
+
}
|
|
253
|
+
else {
|
|
254
|
+
scriptRunnerPath = localScriptRunnerPath;
|
|
255
|
+
}
|
|
256
|
+
const { runScriptInBackground } = await Promise.resolve(`${scriptRunnerPath}`).then(s => __importStar(require(s)));
|
|
257
|
+
const db = getDatabaseManager();
|
|
258
|
+
const project = db.getProjectByPath(projectPath);
|
|
259
|
+
if (!project) {
|
|
260
|
+
throw new Error('Project not found');
|
|
261
|
+
}
|
|
262
|
+
// Run in background (foreground scripts would need IPC streaming for output)
|
|
263
|
+
await runScriptInBackground(projectPath, project.name, scriptName, args, false);
|
|
264
|
+
return { success: true, background: true };
|
|
265
|
+
});
|
|
266
|
+
// Scan ports
|
|
267
|
+
electron_1.ipcMain.handle('scan-project-ports', async (_, projectId) => {
|
|
268
|
+
// Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/port-scanner.js)
|
|
269
|
+
// Then try local dev path (packages/electron/dist/main.js -> packages/cli/dist/port-scanner.js)
|
|
270
|
+
const bundledPortScannerPath = path.join(__dirname, '..', 'port-scanner.js');
|
|
271
|
+
const localPortScannerPath = path.join(__dirname, '..', '..', '..', 'cli', 'dist', 'port-scanner.js');
|
|
272
|
+
let portScannerPath;
|
|
273
|
+
if (fs.existsSync(bundledPortScannerPath)) {
|
|
274
|
+
portScannerPath = bundledPortScannerPath;
|
|
275
|
+
}
|
|
276
|
+
else {
|
|
277
|
+
portScannerPath = localPortScannerPath;
|
|
278
|
+
}
|
|
279
|
+
const { scanProjectPorts } = await Promise.resolve(`${portScannerPath}`).then(s => __importStar(require(s)));
|
|
280
|
+
await scanProjectPorts(projectId);
|
|
281
|
+
const db = getDatabaseManager();
|
|
282
|
+
return db.getProjectPorts(projectId);
|
|
283
|
+
});
|
|
284
|
+
electron_1.ipcMain.handle('scan-all-ports', async () => {
|
|
285
|
+
// Try bundled path first (when bundled in CLI: dist/electron/main.js -> dist/port-scanner.js)
|
|
286
|
+
// Then try local dev path (packages/electron/dist/main.js -> packages/cli/dist/port-scanner.js)
|
|
287
|
+
const bundledPortScannerPath = path.join(__dirname, '..', 'port-scanner.js');
|
|
288
|
+
const localPortScannerPath = path.join(__dirname, '..', '..', '..', 'cli', 'dist', 'port-scanner.js');
|
|
289
|
+
let portScannerPath;
|
|
290
|
+
if (fs.existsSync(bundledPortScannerPath)) {
|
|
291
|
+
portScannerPath = bundledPortScannerPath;
|
|
292
|
+
}
|
|
293
|
+
else {
|
|
294
|
+
portScannerPath = localPortScannerPath;
|
|
295
|
+
}
|
|
296
|
+
const { scanAllProjectPorts } = await Promise.resolve(`${portScannerPath}`).then(s => __importStar(require(s)));
|
|
297
|
+
await scanAllProjectPorts();
|
|
298
|
+
const db = getDatabaseManager();
|
|
299
|
+
const projects = getAllProjects();
|
|
300
|
+
const result = {};
|
|
301
|
+
for (const project of projects) {
|
|
302
|
+
result[project.id] = db.getProjectPorts(project.id);
|
|
303
|
+
}
|
|
304
|
+
return result;
|
|
305
|
+
});
|
|
306
|
+
// Get project ports
|
|
307
|
+
electron_1.ipcMain.handle('get-project-ports', async (_, projectId) => {
|
|
308
|
+
const db = getDatabaseManager();
|
|
309
|
+
return db.getProjectPorts(projectId);
|
|
310
|
+
});
|