neex 0.6.90 → 0.6.91

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