neex 0.6.73 → 0.6.80
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/dist/src/cli.js +11 -13
- package/dist/src/commands/dev-commands.js +88 -10
- package/dist/src/commands/index.js +3 -1
- package/dist/src/commands/init-commands.js +7 -16
- package/dist/src/dev-manager.js +234 -65
- package/package.json +1 -1
package/dist/src/cli.js
CHANGED
|
@@ -10,6 +10,14 @@ const chalk_1 = __importDefault(require("chalk"));
|
|
|
10
10
|
const figures_1 = __importDefault(require("figures"));
|
|
11
11
|
const { version } = require('../../package.json');
|
|
12
12
|
function cli() {
|
|
13
|
+
const args = process.argv.slice(2);
|
|
14
|
+
// Handle the 'init' command as a special case before anything else.
|
|
15
|
+
// This makes 'neex' and 'neex init' act as aliases for 'npx create-neex'.
|
|
16
|
+
if (args.length === 0 || args[0] === 'init') {
|
|
17
|
+
const initArgs = args.slice(1); // Get all arguments after 'init'
|
|
18
|
+
(0, index_js_1.runInit)(initArgs);
|
|
19
|
+
return; // Exit early, do not proceed with the rest of the CLI
|
|
20
|
+
}
|
|
13
21
|
const program = new commander_1.Command();
|
|
14
22
|
// Initialize cleanup handlers
|
|
15
23
|
const cleanupHandlers = [];
|
|
@@ -17,8 +25,7 @@ function cli() {
|
|
|
17
25
|
.name('neex')
|
|
18
26
|
.description('Professional script runner with nodemon and PM2 functionality')
|
|
19
27
|
.version(version);
|
|
20
|
-
// Add all command groups
|
|
21
|
-
(0, index_js_1.addInitCommand)(program); // Add the new init command
|
|
28
|
+
// Add all other command groups
|
|
22
29
|
(0, index_js_1.addRunCommands)(program);
|
|
23
30
|
(0, index_js_1.addServerCommands)(program);
|
|
24
31
|
const devCommands = (0, index_js_1.addDevCommands)(program);
|
|
@@ -27,18 +34,9 @@ function cli() {
|
|
|
27
34
|
cleanupHandlers.push(buildCommands.cleanupBuild);
|
|
28
35
|
const startCommands = (0, index_js_1.addStartCommands)(program);
|
|
29
36
|
cleanupHandlers.push(startCommands.cleanupStart);
|
|
30
|
-
// If no command is specified, or 'init' is the command, run init logic.
|
|
31
|
-
// The first argument is the executable, the second is the script path.
|
|
32
|
-
const args = process.argv.slice(2);
|
|
33
|
-
if (args.length === 0) {
|
|
34
|
-
// If 'neex' is run alone, treat it as 'neex init'
|
|
35
|
-
args.push('init');
|
|
36
|
-
}
|
|
37
37
|
program.parse(process.argv);
|
|
38
|
-
// Show help if no commands
|
|
39
|
-
|
|
40
|
-
if (program.args.length === 0 && process.argv.slice(2).length > 0) {
|
|
41
|
-
// This case might happen if only options are passed without a command
|
|
38
|
+
// Show help if no commands specified
|
|
39
|
+
if (program.args.length === 0) {
|
|
42
40
|
program.help();
|
|
43
41
|
}
|
|
44
42
|
// Graceful shutdown handling
|
|
@@ -7,16 +7,17 @@ exports.addDevCommands = void 0;
|
|
|
7
7
|
const dev_manager_js_1 = require("../dev-manager.js");
|
|
8
8
|
const logger_manager_js_1 = require("../logger-manager.js");
|
|
9
9
|
const chalk_1 = __importDefault(require("chalk"));
|
|
10
|
+
const figures_1 = __importDefault(require("figures"));
|
|
10
11
|
function addDevCommands(program) {
|
|
11
12
|
let devManager = null;
|
|
12
|
-
//
|
|
13
|
+
// Enhanced dev command with built-in TypeScript compilation
|
|
13
14
|
program
|
|
14
15
|
.command('dev [file]')
|
|
15
|
-
.description('Start development server with hot reloading (default: src/index.ts)')
|
|
16
|
+
.description('Start TypeScript development server with hot reloading (default: src/index.ts)')
|
|
16
17
|
.option('-w, --watch <patterns>', 'Watch additional patterns (comma-separated)', 'src/**/*')
|
|
17
|
-
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git')
|
|
18
|
-
.option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,js,json')
|
|
19
|
-
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt,
|
|
18
|
+
.option('-i, --ignore <patterns>', 'Ignore patterns (comma-separated)', 'node_modules,dist,build,.git,coverage')
|
|
19
|
+
.option('-e, --ext <extensions>', 'File extensions to watch (comma-separated)', 'ts,tsx,js,jsx,json')
|
|
20
|
+
.option('-d, --delay <ms>', 'Delay before restart (ms)', parseInt, 800)
|
|
20
21
|
.option('-c, --no-color', 'Disable colored output')
|
|
21
22
|
.option('-q, --quiet', 'Reduce output verbosity')
|
|
22
23
|
.option('-v, --verbose', 'Verbose output')
|
|
@@ -24,11 +25,25 @@ function addDevCommands(program) {
|
|
|
24
25
|
.option('--inspect', 'Enable Node.js inspector')
|
|
25
26
|
.option('--inspect-brk', 'Enable Node.js inspector with break')
|
|
26
27
|
.option('--env <file>', 'Load environment variables from file', '.env')
|
|
27
|
-
.option('--exec <command>', 'Command to execute instead of
|
|
28
|
+
.option('--exec <command>', 'Command to execute instead of built-in TypeScript compilation')
|
|
29
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
30
|
+
.option('--no-source-maps', 'Disable source maps')
|
|
31
|
+
.option('--transpile-only', 'Skip type checking for faster compilation')
|
|
32
|
+
.option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
|
|
28
33
|
.action(async (file, options) => {
|
|
29
34
|
try {
|
|
30
35
|
const targetFile = file || 'src/index.ts';
|
|
31
|
-
|
|
36
|
+
if (!options.quiet) {
|
|
37
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting ${chalk_1.default.cyan('neex dev')} for ${chalk_1.default.cyan(targetFile)}`, 'info');
|
|
38
|
+
if (options.verbose) {
|
|
39
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
|
|
40
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Built-in TypeScript compilation`, 'info');
|
|
41
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reloading with intelligent caching`, 'info');
|
|
42
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
|
|
43
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Fast transpilation mode`, 'info');
|
|
44
|
+
logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Dependency tracking`, 'info');
|
|
45
|
+
}
|
|
46
|
+
}
|
|
32
47
|
devManager = new dev_manager_js_1.DevManager({
|
|
33
48
|
file: targetFile,
|
|
34
49
|
watch: options.watch.split(',').map((p) => p.trim()),
|
|
@@ -42,20 +57,68 @@ function addDevCommands(program) {
|
|
|
42
57
|
inspect: options.inspect,
|
|
43
58
|
inspectBrk: options.inspectBrk,
|
|
44
59
|
envFile: options.env,
|
|
45
|
-
execCommand: options.exec
|
|
60
|
+
execCommand: options.exec,
|
|
61
|
+
tsConfig: options.tsconfig,
|
|
62
|
+
sourceMaps: options.sourceMaps,
|
|
63
|
+
transpileOnly: options.transpileOnly,
|
|
64
|
+
nodeArgs: options.nodeArgs ? options.nodeArgs.split(',').map((arg) => arg.trim()) : []
|
|
46
65
|
});
|
|
47
66
|
await devManager.start();
|
|
48
67
|
}
|
|
49
68
|
catch (error) {
|
|
50
69
|
if (error instanceof Error) {
|
|
51
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
70
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Development server error: ${error.message}`, 'error');
|
|
52
71
|
}
|
|
53
72
|
else {
|
|
54
|
-
logger_manager_js_1.loggerManager.printLine(
|
|
73
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown development server error occurred`, 'error');
|
|
55
74
|
}
|
|
56
75
|
process.exit(1);
|
|
57
76
|
}
|
|
58
77
|
});
|
|
78
|
+
// Additional helper commands
|
|
79
|
+
program
|
|
80
|
+
.command('dev:clean')
|
|
81
|
+
.description('Clean development server cache and temporary files')
|
|
82
|
+
.action(() => {
|
|
83
|
+
const path = require('path');
|
|
84
|
+
const fs = require('fs');
|
|
85
|
+
const tempDir = path.join(process.cwd(), '.neex-temp');
|
|
86
|
+
if (fs.existsSync(tempDir)) {
|
|
87
|
+
fs.rmSync(tempDir, { recursive: true, force: true });
|
|
88
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
|
|
89
|
+
}
|
|
90
|
+
else {
|
|
91
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.info)} No cache to clean`, 'info');
|
|
92
|
+
}
|
|
93
|
+
});
|
|
94
|
+
program
|
|
95
|
+
.command('dev:check')
|
|
96
|
+
.description('Check TypeScript configuration and dependencies')
|
|
97
|
+
.option('--tsconfig <path>', 'Path to TypeScript configuration file')
|
|
98
|
+
.action((options) => {
|
|
99
|
+
const path = require('path');
|
|
100
|
+
const fs = require('fs');
|
|
101
|
+
const configPath = options.tsconfig || 'tsconfig.json';
|
|
102
|
+
if (!fs.existsSync(configPath)) {
|
|
103
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
|
|
104
|
+
process.exit(1);
|
|
105
|
+
}
|
|
106
|
+
try {
|
|
107
|
+
const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
|
|
108
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
|
|
109
|
+
if (config.compilerOptions) {
|
|
110
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
|
|
111
|
+
logger_manager_js_1.loggerManager.printLine(` Target: ${config.compilerOptions.target || 'default'}`, 'info');
|
|
112
|
+
logger_manager_js_1.loggerManager.printLine(` Module: ${config.compilerOptions.module || 'default'}`, 'info');
|
|
113
|
+
logger_manager_js_1.loggerManager.printLine(` Strict: ${config.compilerOptions.strict || 'false'}`, 'info');
|
|
114
|
+
logger_manager_js_1.loggerManager.printLine(` Source Maps: ${config.compilerOptions.sourceMap || 'false'}`, 'info');
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
catch (error) {
|
|
118
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Invalid TypeScript config: ${error.message}`, 'error');
|
|
119
|
+
process.exit(1);
|
|
120
|
+
}
|
|
121
|
+
});
|
|
59
122
|
// Cleanup function
|
|
60
123
|
const cleanupDev = () => {
|
|
61
124
|
if (devManager) {
|
|
@@ -63,6 +126,21 @@ function addDevCommands(program) {
|
|
|
63
126
|
devManager = null;
|
|
64
127
|
}
|
|
65
128
|
};
|
|
129
|
+
// Handle process termination
|
|
130
|
+
process.on('SIGINT', () => {
|
|
131
|
+
if (devManager) {
|
|
132
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGINT, shutting down gracefully...`, 'info');
|
|
133
|
+
cleanupDev();
|
|
134
|
+
process.exit(0);
|
|
135
|
+
}
|
|
136
|
+
});
|
|
137
|
+
process.on('SIGTERM', () => {
|
|
138
|
+
if (devManager) {
|
|
139
|
+
logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGTERM, shutting down gracefully...`, 'info');
|
|
140
|
+
cleanupDev();
|
|
141
|
+
process.exit(0);
|
|
142
|
+
}
|
|
143
|
+
});
|
|
66
144
|
return { cleanupDev };
|
|
67
145
|
}
|
|
68
146
|
exports.addDevCommands = addDevCommands;
|
|
@@ -14,10 +14,12 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
14
14
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
15
15
|
};
|
|
16
16
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
17
|
+
exports.runInit = void 0;
|
|
17
18
|
// src/commands/index.ts - Export all commands
|
|
18
19
|
__exportStar(require("./run-commands.js"), exports);
|
|
19
20
|
__exportStar(require("./dev-commands.js"), exports);
|
|
20
21
|
__exportStar(require("./server-commands.js"), exports);
|
|
21
22
|
__exportStar(require("./start-commands.js"), exports);
|
|
22
23
|
__exportStar(require("./build-commands.js"), exports);
|
|
23
|
-
|
|
24
|
+
var init_commands_js_1 = require("./init-commands.js");
|
|
25
|
+
Object.defineProperty(exports, "runInit", { enumerable: true, get: function () { return init_commands_js_1.runInit; } });
|
|
@@ -1,30 +1,21 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
exports.
|
|
3
|
+
exports.runInit = void 0;
|
|
4
|
+
// src/commands/init-commands.ts
|
|
4
5
|
const child_process_1 = require("child_process");
|
|
5
6
|
function runInit(args) {
|
|
6
|
-
|
|
7
|
+
// No extra logs, just run the command.
|
|
7
8
|
const child = (0, child_process_1.spawn)('npx', ['create-neex', ...args], {
|
|
8
9
|
stdio: 'inherit',
|
|
9
10
|
shell: true
|
|
10
11
|
});
|
|
11
12
|
child.on('close', (code) => {
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
}
|
|
13
|
+
// The process exit code will be inherited from the child process.
|
|
14
|
+
process.exit(code !== null && code !== void 0 ? code : 1);
|
|
15
15
|
});
|
|
16
16
|
child.on('error', (err) => {
|
|
17
17
|
console.error('Failed to start npx create-neex:', err);
|
|
18
|
+
process.exit(1);
|
|
18
19
|
});
|
|
19
20
|
}
|
|
20
|
-
|
|
21
|
-
program
|
|
22
|
-
.command('init')
|
|
23
|
-
.description('Initializes a new project using create-neex. Alias for `npx create-neex`.')
|
|
24
|
-
.argument('[args...]', 'Arguments to pass to create-neex')
|
|
25
|
-
.allowUnknownOption(true) // Pass through options like --debug
|
|
26
|
-
.action((args) => {
|
|
27
|
-
runInit(args);
|
|
28
|
-
});
|
|
29
|
-
}
|
|
30
|
-
exports.addInitCommand = addInitCommand;
|
|
21
|
+
exports.runInit = runInit;
|
package/dist/src/dev-manager.js
CHANGED
|
@@ -27,7 +27,7 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
|
27
27
|
};
|
|
28
28
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
29
29
|
exports.DevManager = void 0;
|
|
30
|
-
// src/dev-manager.ts -
|
|
30
|
+
// src/dev-manager.ts - Enhanced TypeScript development server with built-in compilation
|
|
31
31
|
const child_process_1 = require("child_process");
|
|
32
32
|
const chokidar_1 = require("chokidar");
|
|
33
33
|
const logger_manager_js_1 = require("./logger-manager.js");
|
|
@@ -36,19 +36,7 @@ const figures_1 = __importDefault(require("figures"));
|
|
|
36
36
|
const path_1 = __importDefault(require("path"));
|
|
37
37
|
const fs_1 = __importDefault(require("fs"));
|
|
38
38
|
const lodash_1 = require("lodash");
|
|
39
|
-
|
|
40
|
-
try {
|
|
41
|
-
const { exec } = await Promise.resolve().then(() => __importStar(require('child_process')));
|
|
42
|
-
return new Promise((resolve) => {
|
|
43
|
-
exec(`command -v ${command}`, (error) => {
|
|
44
|
-
resolve(!error);
|
|
45
|
-
});
|
|
46
|
-
});
|
|
47
|
-
}
|
|
48
|
-
catch (e) {
|
|
49
|
-
return false;
|
|
50
|
-
}
|
|
51
|
-
}
|
|
39
|
+
const ts = __importStar(require("typescript"));
|
|
52
40
|
class DevManager {
|
|
53
41
|
constructor(options) {
|
|
54
42
|
this.process = null;
|
|
@@ -56,8 +44,55 @@ class DevManager {
|
|
|
56
44
|
this.isRestarting = false;
|
|
57
45
|
this.restartCount = 0;
|
|
58
46
|
this.startTime = null;
|
|
47
|
+
this.moduleCache = new Map();
|
|
48
|
+
this.fileWatcher = new Map();
|
|
59
49
|
this.options = options;
|
|
60
50
|
this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), options.delay);
|
|
51
|
+
this.tsCompilerOptions = this.loadTsConfig();
|
|
52
|
+
}
|
|
53
|
+
loadTsConfig() {
|
|
54
|
+
const configPath = this.options.tsConfig || 'tsconfig.json';
|
|
55
|
+
const defaultOptions = {
|
|
56
|
+
target: ts.ScriptTarget.ES2022,
|
|
57
|
+
module: ts.ModuleKind.CommonJS,
|
|
58
|
+
moduleResolution: ts.ModuleResolutionKind.NodeJs,
|
|
59
|
+
allowJs: true,
|
|
60
|
+
outDir: undefined,
|
|
61
|
+
rootDir: undefined,
|
|
62
|
+
strict: false,
|
|
63
|
+
esModuleInterop: true,
|
|
64
|
+
skipLibCheck: true,
|
|
65
|
+
forceConsistentCasingInFileNames: true,
|
|
66
|
+
resolveJsonModule: true,
|
|
67
|
+
declaration: false,
|
|
68
|
+
sourceMap: this.options.sourceMaps,
|
|
69
|
+
inlineSourceMap: false,
|
|
70
|
+
inlineSources: false,
|
|
71
|
+
};
|
|
72
|
+
if (fs_1.default.existsSync(configPath)) {
|
|
73
|
+
try {
|
|
74
|
+
const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
|
|
75
|
+
if (configFile.error) {
|
|
76
|
+
logger_manager_js_1.loggerManager.printLine(`Error reading tsconfig.json: ${configFile.error.messageText}`, 'warn');
|
|
77
|
+
return defaultOptions;
|
|
78
|
+
}
|
|
79
|
+
const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path_1.default.dirname(configPath));
|
|
80
|
+
if (parsedConfig.errors.length > 0) {
|
|
81
|
+
logger_manager_js_1.loggerManager.printLine(`Error parsing tsconfig.json: ${parsedConfig.errors[0].messageText}`, 'warn');
|
|
82
|
+
return defaultOptions;
|
|
83
|
+
}
|
|
84
|
+
// Override some options for development
|
|
85
|
+
const options = { ...parsedConfig.options, ...defaultOptions };
|
|
86
|
+
if (this.options.verbose) {
|
|
87
|
+
logger_manager_js_1.loggerManager.printLine(`Loaded TypeScript config from ${configPath}`, 'info');
|
|
88
|
+
}
|
|
89
|
+
return options;
|
|
90
|
+
}
|
|
91
|
+
catch (error) {
|
|
92
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to load tsconfig.json: ${error.message}`, 'warn');
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
return defaultOptions;
|
|
61
96
|
}
|
|
62
97
|
loadEnvFile() {
|
|
63
98
|
if (this.options.envFile && fs_1.default.existsSync(this.options.envFile)) {
|
|
@@ -69,7 +104,7 @@ class DevManager {
|
|
|
69
104
|
if (trimmed && !trimmed.startsWith('#')) {
|
|
70
105
|
const [key, ...values] = trimmed.split('=');
|
|
71
106
|
if (key && values.length > 0) {
|
|
72
|
-
process.env[key.trim()] = values.join('=').trim();
|
|
107
|
+
process.env[key.trim()] = values.join('=').trim().replace(/^["']|["']$/g, '');
|
|
73
108
|
}
|
|
74
109
|
}
|
|
75
110
|
}
|
|
@@ -82,24 +117,123 @@ class DevManager {
|
|
|
82
117
|
}
|
|
83
118
|
}
|
|
84
119
|
}
|
|
120
|
+
compileTypeScript(filePath) {
|
|
121
|
+
const absolutePath = path_1.default.resolve(filePath);
|
|
122
|
+
// Check cache first
|
|
123
|
+
const cached = this.moduleCache.get(absolutePath);
|
|
124
|
+
if (cached && !this.options.transpileOnly) {
|
|
125
|
+
return cached;
|
|
126
|
+
}
|
|
127
|
+
try {
|
|
128
|
+
const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
|
|
129
|
+
const dependencies = new Set();
|
|
130
|
+
// Extract import/require dependencies
|
|
131
|
+
const importRegex = /(?:import|require)\s*(?:\(.*?\)|.*?from\s+)['"`]([^'"`]+)['"`]/g;
|
|
132
|
+
let match;
|
|
133
|
+
while ((match = importRegex.exec(sourceCode)) !== null) {
|
|
134
|
+
if (!match[1].startsWith('.'))
|
|
135
|
+
continue;
|
|
136
|
+
const depPath = path_1.default.resolve(path_1.default.dirname(absolutePath), match[1]);
|
|
137
|
+
dependencies.add(depPath);
|
|
138
|
+
}
|
|
139
|
+
let result;
|
|
140
|
+
if (this.options.transpileOnly) {
|
|
141
|
+
// Fast transpile without type checking
|
|
142
|
+
result = ts.transpileModule(sourceCode, {
|
|
143
|
+
compilerOptions: this.tsCompilerOptions,
|
|
144
|
+
fileName: absolutePath,
|
|
145
|
+
reportDiagnostics: false
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
else {
|
|
149
|
+
// Full compilation with type checking
|
|
150
|
+
const program = ts.createProgram([absolutePath], this.tsCompilerOptions);
|
|
151
|
+
const sourceFile = program.getSourceFile(absolutePath);
|
|
152
|
+
if (!sourceFile) {
|
|
153
|
+
throw new Error(`Could not load source file: ${absolutePath}`);
|
|
154
|
+
}
|
|
155
|
+
// Check for errors
|
|
156
|
+
const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
|
|
157
|
+
if (diagnostics.length > 0) {
|
|
158
|
+
const errors = diagnostics.map(diagnostic => {
|
|
159
|
+
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
|
|
160
|
+
if (diagnostic.file && diagnostic.start !== undefined) {
|
|
161
|
+
const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
|
|
162
|
+
return `${path_1.default.relative(process.cwd(), diagnostic.file.fileName)}:${line + 1}:${character + 1} - ${message}`;
|
|
163
|
+
}
|
|
164
|
+
return message;
|
|
165
|
+
});
|
|
166
|
+
logger_manager_js_1.loggerManager.printLine(`TypeScript compilation errors:\n${errors.join('\n')}`, 'error');
|
|
167
|
+
if (!this.options.quiet) {
|
|
168
|
+
process.exit(1);
|
|
169
|
+
}
|
|
170
|
+
}
|
|
171
|
+
result = ts.transpileModule(sourceCode, {
|
|
172
|
+
compilerOptions: this.tsCompilerOptions,
|
|
173
|
+
fileName: absolutePath,
|
|
174
|
+
reportDiagnostics: true
|
|
175
|
+
});
|
|
176
|
+
}
|
|
177
|
+
const compiled = {
|
|
178
|
+
code: result.outputText,
|
|
179
|
+
map: result.sourceMapText,
|
|
180
|
+
dependencies
|
|
181
|
+
};
|
|
182
|
+
this.moduleCache.set(absolutePath, compiled);
|
|
183
|
+
return compiled;
|
|
184
|
+
}
|
|
185
|
+
catch (error) {
|
|
186
|
+
logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
|
|
187
|
+
throw error;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
createTempFile(compiled, originalPath) {
|
|
191
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
192
|
+
if (!fs_1.default.existsSync(tempDir)) {
|
|
193
|
+
fs_1.default.mkdirSync(tempDir, { recursive: true });
|
|
194
|
+
}
|
|
195
|
+
const tempFile = path_1.default.join(tempDir, `${path_1.default.basename(originalPath, path_1.default.extname(originalPath))}-${Date.now()}.js`);
|
|
196
|
+
let code = compiled.code;
|
|
197
|
+
// Handle source maps
|
|
198
|
+
if (compiled.map && this.options.sourceMaps) {
|
|
199
|
+
const mapFile = tempFile + '.map';
|
|
200
|
+
fs_1.default.writeFileSync(mapFile, compiled.map);
|
|
201
|
+
code += `\n//# sourceMappingURL=${path_1.default.basename(mapFile)}`;
|
|
202
|
+
}
|
|
203
|
+
fs_1.default.writeFileSync(tempFile, code);
|
|
204
|
+
return tempFile;
|
|
205
|
+
}
|
|
206
|
+
cleanupTempFiles() {
|
|
207
|
+
const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
|
|
208
|
+
if (fs_1.default.existsSync(tempDir)) {
|
|
209
|
+
try {
|
|
210
|
+
fs_1.default.rmSync(tempDir, { recursive: true, force: true });
|
|
211
|
+
}
|
|
212
|
+
catch (error) {
|
|
213
|
+
// Ignore cleanup errors
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
}
|
|
85
217
|
async getExecuteCommand() {
|
|
86
218
|
if (this.options.execCommand) {
|
|
87
219
|
const parts = this.options.execCommand.split(' ');
|
|
88
|
-
return { command: parts[0], args: [...parts.slice(1)
|
|
220
|
+
return { command: parts[0], args: [...parts.slice(1)] };
|
|
89
221
|
}
|
|
90
|
-
//
|
|
91
|
-
const
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
}
|
|
95
|
-
const args = [this.options.file];
|
|
222
|
+
// Compile TypeScript file
|
|
223
|
+
const compiled = this.compileTypeScript(this.options.file);
|
|
224
|
+
const tempFile = this.createTempFile(compiled, this.options.file);
|
|
225
|
+
const args = [...this.options.nodeArgs, tempFile];
|
|
96
226
|
if (this.options.inspect) {
|
|
97
227
|
args.unshift('--inspect');
|
|
98
228
|
}
|
|
99
229
|
if (this.options.inspectBrk) {
|
|
100
230
|
args.unshift('--inspect-brk');
|
|
101
231
|
}
|
|
102
|
-
|
|
232
|
+
// Enable source map support
|
|
233
|
+
if (this.options.sourceMaps) {
|
|
234
|
+
args.unshift('--enable-source-maps');
|
|
235
|
+
}
|
|
236
|
+
return { command: 'node', args };
|
|
103
237
|
}
|
|
104
238
|
clearConsole() {
|
|
105
239
|
if (this.options.clearConsole && process.stdout.isTTY) {
|
|
@@ -112,50 +246,58 @@ class DevManager {
|
|
|
112
246
|
return;
|
|
113
247
|
}
|
|
114
248
|
this.loadEnvFile();
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
this.process = (0, child_process_1.spawn)(command, args, {
|
|
120
|
-
stdio: ['ignore', 'pipe', 'pipe'],
|
|
121
|
-
shell: false,
|
|
122
|
-
env: {
|
|
123
|
-
...process.env,
|
|
124
|
-
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
125
|
-
FORCE_COLOR: this.options.color ? '1' : '0'
|
|
126
|
-
},
|
|
127
|
-
detached: true
|
|
128
|
-
});
|
|
129
|
-
this.startTime = new Date();
|
|
130
|
-
this.restartCount++;
|
|
131
|
-
if (!this.options.quiet) {
|
|
132
|
-
const timestamp = new Date().toLocaleTimeString();
|
|
133
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(this.options.file)} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
|
|
134
|
-
}
|
|
135
|
-
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
136
|
-
if (!this.options.quiet) {
|
|
137
|
-
process.stdout.write(data);
|
|
249
|
+
try {
|
|
250
|
+
const { command, args } = await this.getExecuteCommand();
|
|
251
|
+
if (this.options.verbose) {
|
|
252
|
+
logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
|
|
138
253
|
}
|
|
139
|
-
|
|
140
|
-
|
|
254
|
+
this.process = (0, child_process_1.spawn)(command, args, {
|
|
255
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
256
|
+
shell: false,
|
|
257
|
+
env: {
|
|
258
|
+
...process.env,
|
|
259
|
+
NODE_ENV: process.env.NODE_ENV || 'development',
|
|
260
|
+
FORCE_COLOR: this.options.color ? '1' : '0',
|
|
261
|
+
TS_NODE_DEV: '1',
|
|
262
|
+
NEEX_DEV: '1'
|
|
263
|
+
},
|
|
264
|
+
detached: true
|
|
265
|
+
});
|
|
266
|
+
this.startTime = new Date();
|
|
267
|
+
this.restartCount++;
|
|
141
268
|
if (!this.options.quiet) {
|
|
142
|
-
|
|
269
|
+
const timestamp = new Date().toLocaleTimeString();
|
|
270
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.play)} Started ${chalk_1.default.cyan(path_1.default.relative(process.cwd(), this.options.file))} ${chalk_1.default.dim(`(${timestamp})`)}`, 'info');
|
|
143
271
|
}
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
272
|
+
(_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
|
|
273
|
+
if (!this.options.quiet) {
|
|
274
|
+
process.stdout.write(data);
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
(_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
|
|
278
|
+
if (!this.options.quiet) {
|
|
279
|
+
process.stderr.write(data);
|
|
280
|
+
}
|
|
281
|
+
});
|
|
282
|
+
this.process.on('error', (error) => {
|
|
283
|
+
logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
|
|
284
|
+
});
|
|
285
|
+
this.process.on('exit', (code, signal) => {
|
|
286
|
+
if (this.process) {
|
|
287
|
+
this.process = null;
|
|
288
|
+
if (!this.isRestarting) {
|
|
289
|
+
if (code !== 0) {
|
|
290
|
+
const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
|
|
291
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
|
|
292
|
+
}
|
|
155
293
|
}
|
|
156
294
|
}
|
|
157
|
-
}
|
|
158
|
-
}
|
|
295
|
+
});
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
|
|
299
|
+
throw error;
|
|
300
|
+
}
|
|
159
301
|
}
|
|
160
302
|
async stopProcess() {
|
|
161
303
|
if (!this.process) {
|
|
@@ -172,6 +314,7 @@ class DevManager {
|
|
|
172
314
|
if (!this.options.quiet) {
|
|
173
315
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Stopped process`, 'info');
|
|
174
316
|
}
|
|
317
|
+
this.cleanupTempFiles();
|
|
175
318
|
resolve();
|
|
176
319
|
};
|
|
177
320
|
proc.on('exit', cleanup);
|
|
@@ -190,7 +333,7 @@ class DevManager {
|
|
|
190
333
|
// Ignore
|
|
191
334
|
}
|
|
192
335
|
}
|
|
193
|
-
},
|
|
336
|
+
}, 3000);
|
|
194
337
|
}
|
|
195
338
|
}
|
|
196
339
|
catch (error) {
|
|
@@ -199,6 +342,17 @@ class DevManager {
|
|
|
199
342
|
}
|
|
200
343
|
});
|
|
201
344
|
}
|
|
345
|
+
invalidateCache(filePath) {
|
|
346
|
+
const absolutePath = path_1.default.resolve(filePath);
|
|
347
|
+
// Remove from cache
|
|
348
|
+
this.moduleCache.delete(absolutePath);
|
|
349
|
+
// Remove dependent modules from cache
|
|
350
|
+
for (const [cachedPath, module] of this.moduleCache.entries()) {
|
|
351
|
+
if (module.dependencies.has(absolutePath)) {
|
|
352
|
+
this.moduleCache.delete(cachedPath);
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
202
356
|
async restart() {
|
|
203
357
|
if (this.isRestarting) {
|
|
204
358
|
return;
|
|
@@ -210,7 +364,11 @@ class DevManager {
|
|
|
210
364
|
if (!this.options.quiet) {
|
|
211
365
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting due to changes...`, 'info');
|
|
212
366
|
}
|
|
367
|
+
// Clear module cache
|
|
368
|
+
this.moduleCache.clear();
|
|
213
369
|
await this.stopProcess();
|
|
370
|
+
// Small delay to ensure cleanup
|
|
371
|
+
await new Promise(resolve => setTimeout(resolve, 100));
|
|
214
372
|
await this.startProcess();
|
|
215
373
|
this.isRestarting = false;
|
|
216
374
|
}
|
|
@@ -221,7 +379,9 @@ class DevManager {
|
|
|
221
379
|
'**/.git/**',
|
|
222
380
|
'**/dist/**',
|
|
223
381
|
'**/build/**',
|
|
382
|
+
'**/.neex-temp/**',
|
|
224
383
|
'**/*.log',
|
|
384
|
+
'**/*.d.ts',
|
|
225
385
|
...this.options.ignore.map(pattern => `**/${pattern}/**`)
|
|
226
386
|
];
|
|
227
387
|
this.watcher = (0, chokidar_1.watch)(watchPatterns, {
|
|
@@ -232,6 +392,7 @@ class DevManager {
|
|
|
232
392
|
atomic: 300
|
|
233
393
|
});
|
|
234
394
|
this.watcher.on('change', (filePath) => {
|
|
395
|
+
this.invalidateCache(filePath);
|
|
235
396
|
if (this.options.verbose) {
|
|
236
397
|
logger_manager_js_1.loggerManager.printLine(`File changed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
237
398
|
}
|
|
@@ -244,6 +405,7 @@ class DevManager {
|
|
|
244
405
|
this.debouncedRestart();
|
|
245
406
|
});
|
|
246
407
|
this.watcher.on('unlink', (filePath) => {
|
|
408
|
+
this.invalidateCache(filePath);
|
|
247
409
|
if (this.options.verbose) {
|
|
248
410
|
logger_manager_js_1.loggerManager.printLine(`File removed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
|
|
249
411
|
}
|
|
@@ -262,16 +424,23 @@ class DevManager {
|
|
|
262
424
|
if (!fs_1.default.existsSync(this.options.file)) {
|
|
263
425
|
throw new Error(`Target file not found: ${this.options.file}`);
|
|
264
426
|
}
|
|
265
|
-
|
|
427
|
+
// Validate TypeScript file
|
|
428
|
+
const ext = path_1.default.extname(this.options.file);
|
|
429
|
+
if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
|
|
430
|
+
throw new Error(`Unsupported file extension: ${ext}`);
|
|
431
|
+
}
|
|
432
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting TypeScript development server...`, 'info');
|
|
266
433
|
// Show configuration in verbose mode
|
|
267
434
|
if (this.options.verbose) {
|
|
268
435
|
logger_manager_js_1.loggerManager.printLine(`Target file: ${this.options.file}`, 'info');
|
|
269
436
|
logger_manager_js_1.loggerManager.printLine(`Watch patterns: ${this.options.watch.join(', ')}`, 'info');
|
|
270
437
|
logger_manager_js_1.loggerManager.printLine(`Restart delay: ${this.options.delay}ms`, 'info');
|
|
438
|
+
logger_manager_js_1.loggerManager.printLine(`Transpile only: ${this.options.transpileOnly}`, 'info');
|
|
439
|
+
logger_manager_js_1.loggerManager.printLine(`Source maps: ${this.options.sourceMaps}`, 'info');
|
|
271
440
|
}
|
|
272
441
|
this.setupWatcher();
|
|
273
442
|
await this.startProcess();
|
|
274
|
-
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)}
|
|
443
|
+
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript development server started. Watching for changes...`, 'info');
|
|
275
444
|
}
|
|
276
445
|
async stop() {
|
|
277
446
|
logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping development server...`, 'info');
|