neex 0.6.89 → 0.6.90

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.
@@ -7,36 +7,45 @@ 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
- // Ultra-fast dev command optimized for speed
13
+ // Enhanced dev command with built-in TypeScript compilation
13
14
  program
14
15
  .command('dev [file]')
15
- .description('Start ultra-fast TypeScript development server (like tsx)')
16
- .option('-w, --watch <patterns>', 'Watch 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', 'ts,tsx,js,jsx')
19
- .option('-d, --delay <ms>', 'Restart delay in milliseconds', parseInt, 100)
20
- .option('--fast', 'Ultra-fast mode (50ms delay)')
16
+ .description('Start TypeScript development server with hot reloading (default: src/index.ts)')
17
+ .option('-w, --watch <patterns>', 'Watch additional patterns (comma-separated)', 'src/**/*')
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, 500)
21
+ .option('--fast', 'Enable fast hot reload (shorter delays)')
22
+ .option('-c, --no-color', 'Disable colored output')
23
+ .option('-q, --quiet', 'Reduce output verbosity')
24
+ .option('-v, --verbose', 'Verbose output')
21
25
  .option('--no-clear', 'Don\'t clear console on restart')
22
- .option('--no-color', 'Disable colored output')
23
- .option('-q, --quiet', 'Minimal output')
24
- .option('-v, --verbose', 'Verbose logging')
25
26
  .option('--inspect', 'Enable Node.js inspector')
26
- .option('--inspect-brk', 'Enable Node.js inspector with breakpoint')
27
- .option('--env <file>', 'Environment file to load', '.env')
28
- .option('--exec <command>', 'Custom command to execute')
29
- .option('--tsconfig <path>', 'TypeScript config file path')
30
- .option('--no-source-maps', 'Disable source map generation')
31
- .option('--transpile-only', 'Skip type checking (faster)')
32
- .option('--node-args <args>', 'Node.js arguments (comma-separated)', '')
27
+ .option('--inspect-brk', 'Enable Node.js inspector with break')
28
+ .option('--env <file>', 'Load environment variables from file', '.env')
29
+ .option('--exec <command>', 'Command to execute instead of built-in TypeScript compilation')
30
+ .option('--tsconfig <path>', 'Path to TypeScript configuration file')
31
+ .option('--no-source-maps', 'Disable source maps')
32
+ .option('--transpile-only', 'Skip type checking for faster compilation')
33
+ .option('--node-args <args>', 'Additional Node.js arguments (comma-separated)', '')
33
34
  .action(async (file, options) => {
34
35
  try {
35
36
  const targetFile = file || 'src/index.ts';
36
- const delay = options.fast ? 50 : options.delay;
37
+ // تنظیمات fast mode
38
+ const delay = options.fast ? 200 : options.delay;
37
39
  if (!options.quiet) {
38
- console.log(''); // Empty line for better visual separation
39
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} ${chalk_1.default.bold('neex dev')} ${chalk_1.default.dim('v1.0.0')} - ${chalk_1.default.cyan(targetFile)}`, 'info');
40
+ 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');
41
+ if (options.verbose) {
42
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
43
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Built-in TypeScript compilation`, 'info');
44
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reloading with intelligent caching`, 'info');
45
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
46
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Fast transpilation mode`, 'info');
47
+ logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Dependency tracking`, 'info');
48
+ }
40
49
  }
41
50
  devManager = new dev_manager_js_1.DevManager({
42
51
  file: targetFile,
@@ -61,119 +70,58 @@ function addDevCommands(program) {
61
70
  }
62
71
  catch (error) {
63
72
  if (error instanceof Error) {
64
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} ${error.message}`, 'error');
73
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Development server error: ${error.message}`, 'error');
65
74
  }
66
75
  else {
67
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Unknown error occurred`, 'error');
76
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} An unknown development server error occurred`, 'error');
68
77
  }
69
78
  process.exit(1);
70
79
  }
71
80
  });
72
- // Clean cache command
81
+ // Additional helper commands
73
82
  program
74
83
  .command('dev:clean')
75
- .description('Clean development cache and temp files')
84
+ .description('Clean development server cache and temporary files')
76
85
  .action(() => {
77
86
  const path = require('path');
78
87
  const fs = require('fs');
79
88
  const tempDir = path.join(process.cwd(), '.neex-temp');
80
- const nodeModulesCache = path.join(process.cwd(), 'node_modules/.cache');
81
- let cleaned = false;
82
89
  if (fs.existsSync(tempDir)) {
83
90
  fs.rmSync(tempDir, { recursive: true, force: true });
84
- cleaned = true;
85
- }
86
- if (fs.existsSync(nodeModulesCache)) {
87
- try {
88
- fs.rmSync(nodeModulesCache, { recursive: true, force: true });
89
- cleaned = true;
90
- }
91
- catch (error) {
92
- // Ignore cache cleanup errors
93
- }
94
- }
95
- if (cleaned) {
96
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Cache cleaned successfully`, 'info');
91
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} Cleaned development cache`, 'info');
97
92
  }
98
93
  else {
99
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('ℹ')} No cache to clean`, 'info');
94
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.info)} No cache to clean`, 'info');
100
95
  }
101
96
  });
102
- // TypeScript config check
103
97
  program
104
98
  .command('dev:check')
105
- .description('Check TypeScript configuration')
106
- .option('--tsconfig <path>', 'TypeScript config file path')
99
+ .description('Check TypeScript configuration and dependencies')
100
+ .option('--tsconfig <path>', 'Path to TypeScript configuration file')
107
101
  .action((options) => {
108
102
  const path = require('path');
109
103
  const fs = require('fs');
110
104
  const configPath = options.tsconfig || 'tsconfig.json';
111
105
  if (!fs.existsSync(configPath)) {
112
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} TypeScript config not found: ${configPath}`, 'error');
106
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} TypeScript config not found: ${configPath}`, 'error');
113
107
  process.exit(1);
114
108
  }
115
109
  try {
116
110
  const config = JSON.parse(fs.readFileSync(configPath, 'utf8'));
117
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} TypeScript config is valid`, 'info');
118
- if (config.compilerOptions && !options.quiet) {
119
- const opts = config.compilerOptions;
120
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Configuration:')}`, 'info');
121
- logger_manager_js_1.loggerManager.printLine(` Target: ${opts.target || 'ES5'}`, 'info');
122
- logger_manager_js_1.loggerManager.printLine(` Module: ${opts.module || 'CommonJS'}`, 'info');
123
- logger_manager_js_1.loggerManager.printLine(` Strict: ${opts.strict || false}`, 'info');
124
- logger_manager_js_1.loggerManager.printLine(` Source Maps: ${opts.sourceMap || false}`, 'info');
125
- logger_manager_js_1.loggerManager.printLine(` Skip Lib Check: ${opts.skipLibCheck || false}`, 'info');
111
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript config is valid`, 'info');
112
+ if (config.compilerOptions) {
113
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Compiler Options:')}`, 'info');
114
+ logger_manager_js_1.loggerManager.printLine(` Target: ${config.compilerOptions.target || 'default'}`, 'info');
115
+ logger_manager_js_1.loggerManager.printLine(` Module: ${config.compilerOptions.module || 'default'}`, 'info');
116
+ logger_manager_js_1.loggerManager.printLine(` Strict: ${config.compilerOptions.strict || 'false'}`, 'info');
117
+ logger_manager_js_1.loggerManager.printLine(` Source Maps: ${config.compilerOptions.sourceMap || 'false'}`, 'info');
126
118
  }
127
119
  }
128
120
  catch (error) {
129
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Invalid TypeScript config: ${error.message}`, 'error');
121
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Invalid TypeScript config: ${error.message}`, 'error');
130
122
  process.exit(1);
131
123
  }
132
124
  });
133
- // Performance info command
134
- program
135
- .command('dev:info')
136
- .description('Show development server information')
137
- .action(() => {
138
- const path = require('path');
139
- const fs = require('fs');
140
- const os = require('os');
141
- console.log('');
142
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('⚡')} ${chalk_1.default.bold('neex dev')} - Development Server Info`, 'info');
143
- console.log('');
144
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('System:')}`, 'info');
145
- logger_manager_js_1.loggerManager.printLine(` Platform: ${os.platform()} ${os.arch()}`, 'info');
146
- logger_manager_js_1.loggerManager.printLine(` Node.js: ${process.version}`, 'info');
147
- logger_manager_js_1.loggerManager.printLine(` Memory: ${Math.round(process.memoryUsage().heapUsed / 1024 / 1024)}MB used`, 'info');
148
- console.log('');
149
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Features:')}`, 'info');
150
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Ultra-fast TypeScript compilation`, 'info');
151
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Intelligent module caching`, 'info');
152
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Hot reload with dependency tracking`, 'info');
153
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Source map support`, 'info');
154
- logger_manager_js_1.loggerManager.printLine(` ${chalk_1.default.green('✓')} Memory-optimized processing`, 'info');
155
- const tsConfigExists = fs.existsSync('tsconfig.json');
156
- const packageJsonExists = fs.existsSync('package.json');
157
- console.log('');
158
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim('Project:')}`, 'info');
159
- logger_manager_js_1.loggerManager.printLine(` TypeScript Config: ${tsConfigExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
160
- logger_manager_js_1.loggerManager.printLine(` Package.json: ${packageJsonExists ? chalk_1.default.green('✓') : chalk_1.default.red('✖')}`, 'info');
161
- if (packageJsonExists) {
162
- try {
163
- const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
164
- if (pkg.name) {
165
- logger_manager_js_1.loggerManager.printLine(` Name: ${pkg.name}`, 'info');
166
- }
167
- if (pkg.version) {
168
- logger_manager_js_1.loggerManager.printLine(` Version: ${pkg.version}`, 'info');
169
- }
170
- }
171
- catch (error) {
172
- // Ignore package.json parsing errors
173
- }
174
- }
175
- console.log('');
176
- });
177
125
  // Cleanup function
178
126
  const cleanupDev = () => {
179
127
  if (devManager) {
@@ -181,27 +129,20 @@ function addDevCommands(program) {
181
129
  devManager = null;
182
130
  }
183
131
  };
184
- // Enhanced signal handling
185
- const handleSignal = (signal) => {
132
+ // Handle process termination
133
+ process.on('SIGINT', () => {
186
134
  if (devManager) {
187
- console.log(''); // New line for better formatting
188
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Received ${signal}, shutting down...`, 'info');
135
+ logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGINT, shutting down gracefully...`, 'info');
189
136
  cleanupDev();
190
137
  process.exit(0);
191
138
  }
192
- };
193
- process.on('SIGINT', () => handleSignal('SIGINT'));
194
- process.on('SIGTERM', () => handleSignal('SIGTERM'));
195
- // Handle uncaught exceptions
196
- process.on('uncaughtException', (error) => {
197
- console.error(chalk_1.default.red('Uncaught Exception:'), error);
198
- cleanupDev();
199
- process.exit(1);
200
139
  });
201
- process.on('unhandledRejection', (reason, promise) => {
202
- console.error(chalk_1.default.red('Unhandled Rejection at:'), promise, 'reason:', reason);
203
- cleanupDev();
204
- process.exit(1);
140
+ process.on('SIGTERM', () => {
141
+ if (devManager) {
142
+ logger_manager_js_1.loggerManager.printLine(`\n${chalk_1.default.yellow(figures_1.default.warning)} Received SIGTERM, shutting down gracefully...`, 'info');
143
+ cleanupDev();
144
+ process.exit(0);
145
+ }
205
146
  });
206
147
  return { cleanupDev };
207
148
  }
@@ -27,16 +27,16 @@ 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 - Ultra-fast TypeScript development server like tsx
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");
34
34
  const chalk_1 = __importDefault(require("chalk"));
35
+ const figures_1 = __importDefault(require("figures"));
35
36
  const path_1 = __importDefault(require("path"));
36
37
  const fs_1 = __importDefault(require("fs"));
37
38
  const lodash_1 = require("lodash");
38
39
  const ts = __importStar(require("typescript"));
39
- const crypto_1 = __importDefault(require("crypto"));
40
40
  class DevManager {
41
41
  constructor(options) {
42
42
  this.process = null;
@@ -45,23 +45,10 @@ class DevManager {
45
45
  this.restartCount = 0;
46
46
  this.startTime = null;
47
47
  this.moduleCache = new Map();
48
- this.currentTempFile = null;
48
+ this.fileWatcher = new Map();
49
49
  this.options = options;
50
- this.tempDir = path_1.default.join(process.cwd(), '.neex-temp');
51
- this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), Math.max(options.delay, 100));
50
+ this.debouncedRestart = (0, lodash_1.debounce)(this.restart.bind(this), options.delay);
52
51
  this.tsCompilerOptions = this.loadTsConfig();
53
- this.setupTempDir();
54
- }
55
- setupTempDir() {
56
- if (fs_1.default.existsSync(this.tempDir)) {
57
- try {
58
- fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
59
- }
60
- catch (error) {
61
- // Ignore cleanup errors
62
- }
63
- }
64
- fs_1.default.mkdirSync(this.tempDir, { recursive: true });
65
52
  }
66
53
  loadTsConfig() {
67
54
  const configPath = this.options.tsConfig || 'tsconfig.json';
@@ -70,6 +57,8 @@ class DevManager {
70
57
  module: ts.ModuleKind.CommonJS,
71
58
  moduleResolution: ts.ModuleResolutionKind.NodeJs,
72
59
  allowJs: true,
60
+ outDir: undefined,
61
+ rootDir: undefined,
73
62
  strict: false,
74
63
  esModuleInterop: true,
75
64
  skipLibCheck: true,
@@ -79,22 +68,28 @@ class DevManager {
79
68
  sourceMap: this.options.sourceMaps,
80
69
  inlineSourceMap: false,
81
70
  inlineSources: false,
82
- removeComments: false,
83
- preserveConstEnums: false,
84
- isolatedModules: true, // For faster compilation
85
71
  };
86
72
  if (fs_1.default.existsSync(configPath)) {
87
73
  try {
88
74
  const configFile = ts.readConfigFile(configPath, ts.sys.readFile);
89
- if (!configFile.error) {
90
- const parsedConfig = ts.parseJsonConfigFileContent(configFile.config, ts.sys, path_1.default.dirname(configPath));
91
- if (parsedConfig.errors.length === 0) {
92
- return { ...defaultOptions, ...parsedConfig.options };
93
- }
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');
94
88
  }
89
+ return options;
95
90
  }
96
91
  catch (error) {
97
- // Fall back to defaults
92
+ logger_manager_js_1.loggerManager.printLine(`Failed to load tsconfig.json: ${error.message}`, 'warn');
98
93
  }
99
94
  }
100
95
  return defaultOptions;
@@ -104,196 +99,190 @@ class DevManager {
104
99
  try {
105
100
  const envContent = fs_1.default.readFileSync(this.options.envFile, 'utf8');
106
101
  const lines = envContent.split('\n');
102
+ let loadedCount = 0;
107
103
  for (const line of lines) {
108
104
  const trimmed = line.trim();
109
105
  if (trimmed && !trimmed.startsWith('#')) {
110
106
  const [key, ...values] = trimmed.split('=');
111
107
  if (key && values.length > 0) {
112
108
  process.env[key.trim()] = values.join('=').trim().replace(/^["']|["']$/g, '');
109
+ loadedCount++;
113
110
  }
114
111
  }
115
112
  }
113
+ if (!this.options.quiet && loadedCount > 0) {
114
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} Loaded ${loadedCount} env variable${loadedCount > 1 ? 's' : ''} from ${path_1.default.basename(this.options.envFile)}`, 'info');
115
+ }
116
+ else if (this.options.verbose) {
117
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.dim(figures_1.default.info)} No env variables found in ${this.options.envFile}`, 'info');
118
+ }
116
119
  }
117
120
  catch (error) {
118
- if (this.options.verbose) {
119
- logger_manager_js_1.loggerManager.printLine(`Failed to load ${this.options.envFile}: ${error.message}`, 'warn');
120
- }
121
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Failed to load ${this.options.envFile}: ${error.message}`, 'warn');
121
122
  }
122
123
  }
123
124
  }
124
- createHash(content) {
125
- return crypto_1.default.createHash('md5').update(content).digest('hex');
126
- }
127
- extractDependencies(sourceCode, filePath) {
128
- const dependencies = [];
129
- const importRegex = /(?:import|require)\s*(?:\([^)]*\)|[^;]+?from\s+)?['"`]([^'"`]+)['"`]/g;
130
- let match;
131
- while ((match = importRegex.exec(sourceCode)) !== null) {
132
- const importPath = match[1];
133
- if (importPath.startsWith('.')) {
134
- let resolvedPath = path_1.default.resolve(path_1.default.dirname(filePath), importPath);
135
- // Try to resolve with extensions
136
- if (!fs_1.default.existsSync(resolvedPath)) {
137
- for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
138
- const withExt = resolvedPath + ext;
139
- if (fs_1.default.existsSync(withExt)) {
140
- resolvedPath = withExt;
141
- break;
142
- }
143
- }
125
+ compileTypeScript(filePath) {
126
+ const absolutePath = path_1.default.resolve(filePath);
127
+ // Check cache first
128
+ const cached = this.moduleCache.get(absolutePath);
129
+ if (cached && !this.options.transpileOnly) {
130
+ return cached;
131
+ }
132
+ try {
133
+ const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
134
+ const dependencies = new Set();
135
+ // Extract import/require dependencies
136
+ const importRegex = /(?:import|require)\s*(?:\(.*?\)|.*?from\s+)['"`]([^'"`]+)['"`]/g;
137
+ let match;
138
+ while ((match = importRegex.exec(sourceCode)) !== null) {
139
+ if (!match[1].startsWith('.'))
140
+ continue;
141
+ const depPath = path_1.default.resolve(path_1.default.dirname(absolutePath), match[1]);
142
+ dependencies.add(depPath);
143
+ }
144
+ let result;
145
+ if (this.options.transpileOnly) {
146
+ // Fast transpile without type checking
147
+ result = ts.transpileModule(sourceCode, {
148
+ compilerOptions: this.tsCompilerOptions,
149
+ fileName: absolutePath,
150
+ reportDiagnostics: false
151
+ });
152
+ }
153
+ else {
154
+ // Full compilation with type checking
155
+ const program = ts.createProgram([absolutePath], this.tsCompilerOptions);
156
+ const sourceFile = program.getSourceFile(absolutePath);
157
+ if (!sourceFile) {
158
+ throw new Error(`Could not load source file: ${absolutePath}`);
144
159
  }
145
- // Try index files
146
- if (!fs_1.default.existsSync(resolvedPath)) {
147
- for (const ext of ['.ts', '.tsx', '.js', '.jsx']) {
148
- const indexPath = path_1.default.join(resolvedPath, 'index' + ext);
149
- if (fs_1.default.existsSync(indexPath)) {
150
- resolvedPath = indexPath;
151
- break;
160
+ // Check for errors
161
+ const diagnostics = ts.getPreEmitDiagnostics(program, sourceFile);
162
+ if (diagnostics.length > 0) {
163
+ const errors = diagnostics.map(diagnostic => {
164
+ const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
165
+ if (diagnostic.file && diagnostic.start !== undefined) {
166
+ const { line, character } = diagnostic.file.getLineAndCharacterOfPosition(diagnostic.start);
167
+ return `${path_1.default.relative(process.cwd(), diagnostic.file.fileName)}:${line + 1}:${character + 1} - ${message}`;
152
168
  }
169
+ return message;
170
+ });
171
+ logger_manager_js_1.loggerManager.printLine(`TypeScript compilation errors:\n${errors.join('\n')}`, 'error');
172
+ if (!this.options.quiet) {
173
+ process.exit(1);
153
174
  }
154
175
  }
155
- if (fs_1.default.existsSync(resolvedPath)) {
156
- dependencies.push(resolvedPath);
157
- }
158
- }
159
- }
160
- return dependencies;
161
- }
162
- compileModule(filePath, forceRecompile = false) {
163
- const absolutePath = path_1.default.resolve(filePath);
164
- try {
165
- const sourceCode = fs_1.default.readFileSync(absolutePath, 'utf8');
166
- const hash = this.createHash(sourceCode);
167
- const cached = this.moduleCache.get(absolutePath);
168
- // Check if we can use cached version
169
- if (!forceRecompile && cached && cached.hash === hash) {
170
- return cached;
176
+ result = ts.transpileModule(sourceCode, {
177
+ compilerOptions: this.tsCompilerOptions,
178
+ fileName: absolutePath,
179
+ reportDiagnostics: true
180
+ });
171
181
  }
172
- const dependencies = this.extractDependencies(sourceCode, absolutePath);
173
- // Fast transpile without type checking for development
174
- const result = ts.transpileModule(sourceCode, {
175
- compilerOptions: this.tsCompilerOptions,
176
- fileName: absolutePath,
177
- reportDiagnostics: false // Skip diagnostics for speed
178
- });
179
- const moduleInfo = {
182
+ const compiled = {
180
183
  code: result.outputText,
181
184
  map: result.sourceMapText,
182
- hash,
183
- timestamp: Date.now(),
184
185
  dependencies
185
186
  };
186
- this.moduleCache.set(absolutePath, moduleInfo);
187
- if (this.options.verbose) {
188
- logger_manager_js_1.loggerManager.printLine(`Compiled ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
189
- }
190
- return moduleInfo;
187
+ this.moduleCache.set(absolutePath, compiled);
188
+ return compiled;
191
189
  }
192
190
  catch (error) {
193
- logger_manager_js_1.loggerManager.printLine(`Compilation error: ${error.message}`, 'error');
191
+ logger_manager_js_1.loggerManager.printLine(`Compilation error in ${filePath}: ${error.message}`, 'error');
194
192
  throw error;
195
193
  }
196
194
  }
197
- invalidateModuleCache(filePath) {
198
- const absolutePath = path_1.default.resolve(filePath);
199
- // Remove the file itself
200
- this.moduleCache.delete(absolutePath);
201
- // Remove any modules that depend on this file
202
- const toRemove = [];
203
- for (const [cachedPath, info] of this.moduleCache.entries()) {
204
- if (info.dependencies.includes(absolutePath)) {
205
- toRemove.push(cachedPath);
206
- }
207
- }
208
- for (const pathToRemove of toRemove) {
209
- this.moduleCache.delete(pathToRemove);
210
- }
211
- if (this.options.verbose && toRemove.length > 0) {
212
- logger_manager_js_1.loggerManager.printLine(`Invalidated ${toRemove.length + 1} modules`, 'info');
195
+ createTempFile(compiled, originalPath) {
196
+ const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
197
+ if (!fs_1.default.existsSync(tempDir)) {
198
+ fs_1.default.mkdirSync(tempDir, { recursive: true });
213
199
  }
214
- }
215
- createExecutableFile() {
216
- // Always force recompile the main file
217
- const mainModule = this.compileModule(this.options.file, true);
218
- // Create a unique temp file
219
- const timestamp = Date.now();
220
- const random = Math.random().toString(36).substr(2, 9);
221
- const tempFile = path_1.default.join(this.tempDir, `main-${timestamp}-${random}.js`);
222
- let code = mainModule.code;
223
- // Add source map support
224
- if (mainModule.map && this.options.sourceMaps) {
200
+ const tempFile = path_1.default.join(tempDir, `${path_1.default.basename(originalPath, path_1.default.extname(originalPath))}-${Date.now()}.js`);
201
+ let code = compiled.code;
202
+ // Handle source maps
203
+ if (compiled.map && this.options.sourceMaps) {
225
204
  const mapFile = tempFile + '.map';
226
- fs_1.default.writeFileSync(mapFile, mainModule.map);
205
+ fs_1.default.writeFileSync(mapFile, compiled.map);
227
206
  code += `\n//# sourceMappingURL=${path_1.default.basename(mapFile)}`;
228
207
  }
229
208
  fs_1.default.writeFileSync(tempFile, code);
230
- // Clean up old temp file
231
- if (this.currentTempFile && fs_1.default.existsSync(this.currentTempFile)) {
209
+ return tempFile;
210
+ }
211
+ cleanupTempFiles() {
212
+ const tempDir = path_1.default.join(process.cwd(), '.neex-temp');
213
+ if (fs_1.default.existsSync(tempDir)) {
232
214
  try {
233
- fs_1.default.unlinkSync(this.currentTempFile);
234
- const mapFile = this.currentTempFile + '.map';
235
- if (fs_1.default.existsSync(mapFile)) {
236
- fs_1.default.unlinkSync(mapFile);
237
- }
215
+ fs_1.default.rmSync(tempDir, { recursive: true, force: true });
238
216
  }
239
217
  catch (error) {
240
218
  // Ignore cleanup errors
241
219
  }
242
220
  }
243
- this.currentTempFile = tempFile;
244
- return tempFile;
245
221
  }
246
222
  async getExecuteCommand() {
247
223
  if (this.options.execCommand) {
248
224
  const parts = this.options.execCommand.split(' ');
249
- return { command: parts[0], args: parts.slice(1) };
225
+ return { command: parts[0], args: [...parts.slice(1)] };
250
226
  }
251
- const executableFile = this.createExecutableFile();
252
- const args = [...this.options.nodeArgs, executableFile];
253
- // Add Node.js flags
254
- if (this.options.inspect)
227
+ // Compile TypeScript file
228
+ const compiled = this.compileTypeScript(this.options.file);
229
+ const tempFile = this.createTempFile(compiled, this.options.file);
230
+ const args = [...this.options.nodeArgs, tempFile];
231
+ if (this.options.inspect) {
255
232
  args.unshift('--inspect');
256
- if (this.options.inspectBrk)
233
+ }
234
+ if (this.options.inspectBrk) {
257
235
  args.unshift('--inspect-brk');
258
- if (this.options.sourceMaps)
236
+ }
237
+ // Enable source map support
238
+ if (this.options.sourceMaps) {
259
239
  args.unshift('--enable-source-maps');
240
+ }
260
241
  return { command: 'node', args };
261
242
  }
262
243
  clearConsole() {
263
244
  if (this.options.clearConsole && process.stdout.isTTY) {
264
- process.stdout.write('\x1Bc'); // Clear screen and scrollback
245
+ process.stdout.write('\x1b[2J\x1b[0f');
265
246
  }
266
247
  }
267
248
  async startProcess() {
268
249
  var _a, _b;
269
- if (this.process)
250
+ if (this.process) {
270
251
  return;
252
+ }
271
253
  this.loadEnvFile();
272
254
  try {
273
255
  const { command, args } = await this.getExecuteCommand();
256
+ if (this.options.verbose) {
257
+ logger_manager_js_1.loggerManager.printLine(`Executing: ${command} ${args.join(' ')}`, 'info');
258
+ }
274
259
  this.process = (0, child_process_1.spawn)(command, args, {
275
260
  stdio: ['ignore', 'pipe', 'pipe'],
261
+ shell: false,
276
262
  env: {
277
263
  ...process.env,
278
264
  NODE_ENV: process.env.NODE_ENV || 'development',
279
265
  FORCE_COLOR: this.options.color ? '1' : '0',
280
- NODE_OPTIONS: '--max-old-space-size=4096', // Prevent memory issues
266
+ TS_NODE_DEV: '1',
267
+ NEEX_DEV: '1'
281
268
  },
282
- detached: false // Keep attached for better cleanup
269
+ detached: true
283
270
  });
284
271
  this.startTime = new Date();
285
272
  this.restartCount++;
286
273
  if (!this.options.quiet) {
287
274
  const timestamp = new Date().toLocaleTimeString();
288
- const fileRelative = path_1.default.relative(process.cwd(), this.options.file);
289
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('▶')} ${chalk_1.default.cyan(fileRelative)} ${chalk_1.default.dim(`#${this.restartCount} ${timestamp}`)}`, 'info');
275
+ 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');
290
276
  }
291
- // Handle stdout/stderr
292
277
  (_a = this.process.stdout) === null || _a === void 0 ? void 0 : _a.on('data', (data) => {
293
- process.stdout.write(data);
278
+ if (!this.options.quiet) {
279
+ process.stdout.write(data);
280
+ }
294
281
  });
295
282
  (_b = this.process.stderr) === null || _b === void 0 ? void 0 : _b.on('data', (data) => {
296
- process.stderr.write(data);
283
+ if (!this.options.quiet) {
284
+ process.stderr.write(data);
285
+ }
297
286
  });
298
287
  this.process.on('error', (error) => {
299
288
  logger_manager_js_1.loggerManager.printLine(`Process error: ${error.message}`, 'error');
@@ -301,147 +290,177 @@ class DevManager {
301
290
  this.process.on('exit', (code, signal) => {
302
291
  if (this.process) {
303
292
  this.process = null;
304
- if (!this.isRestarting && code !== 0) {
305
- const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
306
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('✖')} Process exited with code ${code} (${duration}ms)`, 'error');
293
+ if (!this.isRestarting) {
294
+ if (code !== 0) {
295
+ const duration = this.startTime ? Date.now() - this.startTime.getTime() : 0;
296
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red(figures_1.default.cross)} Process exited with code ${code} after ${duration}ms`, 'error');
297
+ }
307
298
  }
308
299
  }
309
300
  });
310
301
  }
311
302
  catch (error) {
312
- logger_manager_js_1.loggerManager.printLine(`Failed to start: ${error.message}`, 'error');
303
+ logger_manager_js_1.loggerManager.printLine(`Failed to start process: ${error.message}`, 'error');
313
304
  throw error;
314
305
  }
315
306
  }
316
307
  async stopProcess() {
317
- if (!this.process)
308
+ if (!this.process) {
318
309
  return;
310
+ }
319
311
  return new Promise((resolve) => {
312
+ if (!this.process) {
313
+ resolve();
314
+ return;
315
+ }
320
316
  const proc = this.process;
321
317
  this.process = null;
322
318
  const cleanup = () => {
319
+ if (!this.options.quiet) {
320
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.square)} Stopped process`, 'info');
321
+ }
322
+ this.cleanupTempFiles();
323
323
  resolve();
324
324
  };
325
325
  proc.on('exit', cleanup);
326
326
  proc.on('error', cleanup);
327
327
  try {
328
- proc.kill('SIGTERM');
329
- // Force kill after timeout
330
- setTimeout(() => {
331
- if (!proc.killed) {
332
- proc.kill('SIGKILL');
333
- }
334
- }, 1000);
328
+ if (proc.pid) {
329
+ // Kill process group
330
+ process.kill(-proc.pid, 'SIGTERM');
331
+ // Fallback after timeout
332
+ setTimeout(() => {
333
+ if (proc.pid && !proc.killed) {
334
+ try {
335
+ process.kill(-proc.pid, 'SIGKILL');
336
+ }
337
+ catch (e) {
338
+ // Ignore
339
+ }
340
+ }
341
+ }, 3000);
342
+ }
335
343
  }
336
344
  catch (error) {
345
+ // Process might already be dead
337
346
  cleanup();
338
347
  }
339
348
  });
340
349
  }
350
+ invalidateCache(filePath) {
351
+ const absolutePath = path_1.default.resolve(filePath);
352
+ // Remove from cache
353
+ this.moduleCache.delete(absolutePath);
354
+ // Remove dependent modules from cache
355
+ for (const [cachedPath, module] of this.moduleCache.entries()) {
356
+ if (module.dependencies.has(absolutePath)) {
357
+ this.moduleCache.delete(cachedPath);
358
+ }
359
+ }
360
+ }
341
361
  async restart() {
342
- if (this.isRestarting)
362
+ if (this.isRestarting) {
343
363
  return;
364
+ }
344
365
  this.isRestarting = true;
345
- // Clear console immediately for better UX
346
- this.clearConsole();
366
+ if (this.options.clearConsole) {
367
+ this.clearConsole();
368
+ }
347
369
  if (!this.options.quiet) {
348
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⟳')} Restarting...`, 'info');
370
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.arrowRight)} Restarting due to changes...`, 'info');
349
371
  }
350
- // Stop current process
372
+ // Clear module cache
373
+ this.moduleCache.clear();
351
374
  await this.stopProcess();
352
- // Start new process
375
+ // Small delay to ensure cleanup
376
+ await new Promise(resolve => setTimeout(resolve, 100));
353
377
  await this.startProcess();
354
378
  this.isRestarting = false;
355
379
  }
356
380
  setupWatcher() {
357
381
  const watchPatterns = this.options.watch;
358
- // Optimized ignore patterns
359
382
  const ignored = [
360
- 'node_modules/**',
361
- '.git/**',
362
- 'dist/**',
363
- 'build/**',
364
- '.neex-temp/**',
383
+ '**/node_modules/**',
384
+ '**/.git/**',
385
+ '**/dist/**',
386
+ '**/build/**',
387
+ '**/.neex-temp/**',
365
388
  '**/*.log',
366
389
  '**/*.d.ts',
367
- '**/*.map',
368
- '**/*.tsbuildinfo',
369
- ...this.options.ignore
390
+ ...this.options.ignore.map(pattern => `**/${pattern}/**`)
370
391
  ];
371
392
  this.watcher = (0, chokidar_1.watch)(watchPatterns, {
372
393
  ignored,
373
394
  ignoreInitial: true,
374
395
  followSymlinks: false,
375
396
  usePolling: false,
376
- atomic: 50,
397
+ atomic: 200,
377
398
  awaitWriteFinish: {
378
399
  stabilityThreshold: 100,
379
400
  pollInterval: 50
380
401
  }
381
402
  });
382
403
  this.watcher.on('change', (filePath) => {
383
- this.invalidateModuleCache(filePath);
404
+ this.invalidateCache(filePath);
384
405
  if (this.options.verbose) {
385
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('●')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
406
+ logger_manager_js_1.loggerManager.printLine(`File changed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
386
407
  }
387
408
  this.debouncedRestart();
388
409
  });
389
410
  this.watcher.on('add', (filePath) => {
390
411
  if (this.options.verbose) {
391
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('+')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
412
+ logger_manager_js_1.loggerManager.printLine(`File added: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
392
413
  }
393
414
  this.debouncedRestart();
394
415
  });
395
416
  this.watcher.on('unlink', (filePath) => {
396
- this.invalidateModuleCache(filePath);
417
+ this.invalidateCache(filePath);
397
418
  if (this.options.verbose) {
398
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.red('-')} ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
419
+ logger_manager_js_1.loggerManager.printLine(`File removed: ${path_1.default.relative(process.cwd(), filePath)}`, 'info');
399
420
  }
400
421
  this.debouncedRestart();
401
422
  });
402
423
  this.watcher.on('error', (error) => {
403
424
  logger_manager_js_1.loggerManager.printLine(`Watcher error: ${error.message}`, 'error');
404
425
  });
426
+ if (this.options.verbose) {
427
+ logger_manager_js_1.loggerManager.printLine(`Watching: ${watchPatterns.join(', ')}`, 'info');
428
+ logger_manager_js_1.loggerManager.printLine(`Ignoring: ${ignored.join(', ')}`, 'info');
429
+ }
405
430
  }
406
431
  async start() {
432
+ // Check if target file exists
407
433
  if (!fs_1.default.existsSync(this.options.file)) {
408
434
  throw new Error(`Target file not found: ${this.options.file}`);
409
435
  }
436
+ // Validate TypeScript file
410
437
  const ext = path_1.default.extname(this.options.file);
411
438
  if (!['.ts', '.tsx', '.js', '.jsx'].includes(ext)) {
412
439
  throw new Error(`Unsupported file extension: ${ext}`);
413
440
  }
414
- // Clear any existing cache
415
- this.moduleCache.clear();
416
- this.setupTempDir();
417
- if (!this.options.quiet) {
418
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue('')} Starting dev server...`, 'info');
441
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Starting TypeScript development server...`, 'info');
442
+ // Show configuration in verbose mode
443
+ if (this.options.verbose) {
444
+ logger_manager_js_1.loggerManager.printLine(`Target file: ${this.options.file}`, 'info');
445
+ logger_manager_js_1.loggerManager.printLine(`Watch patterns: ${this.options.watch.join(', ')}`, 'info');
446
+ logger_manager_js_1.loggerManager.printLine(`Restart delay: ${this.options.delay}ms`, 'info');
447
+ logger_manager_js_1.loggerManager.printLine(`Transpile only: ${this.options.transpileOnly}`, 'info');
448
+ logger_manager_js_1.loggerManager.printLine(`Source maps: ${this.options.sourceMaps}`, 'info');
419
449
  }
420
450
  this.setupWatcher();
421
451
  await this.startProcess();
422
- if (!this.options.quiet) {
423
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green('✓')} Watching for changes...`, 'info');
424
- }
452
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.green(figures_1.default.tick)} TypeScript development server started. Watching for changes...`, 'info');
425
453
  }
426
454
  async stop() {
427
- if (!this.options.quiet) {
428
- logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow('⏹')} Stopping dev server...`, 'info');
429
- }
455
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.yellow(figures_1.default.warning)} Stopping development server...`, 'info');
430
456
  if (this.watcher) {
431
457
  await this.watcher.close();
432
458
  this.watcher = null;
433
459
  }
434
460
  await this.stopProcess();
435
- // Cleanup temp files
436
- if (fs_1.default.existsSync(this.tempDir)) {
437
- try {
438
- fs_1.default.rmSync(this.tempDir, { recursive: true, force: true });
439
- }
440
- catch (error) {
441
- // Ignore cleanup errors
442
- }
461
+ if (this.restartCount > 0) {
462
+ logger_manager_js_1.loggerManager.printLine(`${chalk_1.default.blue(figures_1.default.info)} Development server stopped after ${this.restartCount} restart(s)`, 'info');
443
463
  }
444
- this.moduleCache.clear();
445
464
  }
446
465
  }
447
466
  exports.DevManager = DevManager;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "neex",
3
- "version": "0.6.89",
3
+ "version": "0.6.90",
4
4
  "description": "The Modern Build System for Polyrepo-in-Monorepo Architecture",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",