@bobfrankston/importgen 0.1.26 → 0.1.28

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.
Files changed (2) hide show
  1. package/index.js +20 -146
  2. package/package.json +2 -2
package/index.js CHANGED
@@ -5,9 +5,12 @@
5
5
  */
6
6
  import fs from 'node:fs';
7
7
  import path from 'node:path';
8
- import { execSync } from 'node:child_process';
9
8
  import chokidar from 'chokidar';
10
9
  import packageJson from './package.json' with { type: 'json' };
10
+ /** Timestamp prefix for log messages */
11
+ function ts() {
12
+ return `[${new Date().toLocaleTimeString()}]`;
13
+ }
11
14
  /**
12
15
  * Resolve dependency path based on version specifier
13
16
  */
@@ -91,7 +94,7 @@ function collectDependencies(packageJsonPath, visited, dependencies, htmlDir, no
91
94
  let depPath = resolveDependencyPath(packageDir, depName, versionToUse);
92
95
  if (!depPath) {
93
96
  const warning = `Could not follow path for ${depName} (${versionToUse})`;
94
- console.warn(`[generate-importmap] Warning: ${warning}`);
97
+ console.warn(`${ts()} [generate-importmap] Warning: ${warning}`);
95
98
  warnings.push(warning);
96
99
  continue;
97
100
  }
@@ -99,7 +102,7 @@ function collectDependencies(packageJsonPath, visited, dependencies, htmlDir, no
99
102
  const dependencyBackupPath = depPath + '.dependency';
100
103
  if (fs.existsSync(dependencyBackupPath)) {
101
104
  const warning = `Using backup path ${dependencyBackupPath}`;
102
- console.warn(`[generate-importmap] Warning: ${warning}`);
105
+ console.warn(`${ts()} [generate-importmap] Warning: ${warning}`);
103
106
  warnings.push(warning);
104
107
  depPath = dependencyBackupPath;
105
108
  }
@@ -110,7 +113,7 @@ function collectDependencies(packageJsonPath, visited, dependencies, htmlDir, no
110
113
  const depPackageJsonPath = path.join(depPath, 'package.json');
111
114
  if (!fs.existsSync(depPackageJsonPath)) {
112
115
  const warning = `Could not follow path for ${depName} - no package.json found at ${depPath}`;
113
- console.warn(`[generate-importmap] Warning: ${warning}`);
116
+ console.warn(`${ts()} [generate-importmap] Warning: ${warning}`);
114
117
  warnings.push(warning);
115
118
  continue;
116
119
  }
@@ -135,7 +138,7 @@ function collectDependencies(packageJsonPath, visited, dependencies, htmlDir, no
135
138
  }
136
139
  }
137
140
  catch (e) {
138
- console.error(`[generate-importmap] Error processing ${packageJsonPath}:`, e.message);
141
+ console.error(`${ts()} [generate-importmap] Error processing ${packageJsonPath}:`, e.message);
139
142
  throw e; // Propagate so callers can avoid overwriting HTML with empty map
140
143
  }
141
144
  }
@@ -184,158 +187,37 @@ function generateImportMap(packageJsonPath, htmlFilePath) {
184
187
  }
185
188
  // Write back to HTML file
186
189
  fs.writeFileSync(htmlFilePath, html, 'utf-8');
187
- console.log('[generate-importmap] Updated import map');
190
+ console.log(`${ts()} [generate-importmap] Updated import map`);
188
191
  console.log(` Scanned ${visited.size} dependencies, generated ${dependencies.size} entries`);
189
192
  if (dependencies.size > 0) {
190
193
  console.log(' Packages:', Array.from(dependencies.keys()).join(', '));
191
194
  }
192
195
  }
193
196
  catch (e) {
194
- console.error('[generate-importmap] Error:', e.message);
197
+ console.error(`${ts()} [generate-importmap] Error:`, e.message);
195
198
  process.exit(1);
196
199
  }
197
200
  return result;
198
201
  }
199
- /**
200
- * Freeze dependencies: replace junctions/symlinks in node_modules with real copies.
201
- * Also adds a preinstall guard to package.json to prevent npm install from undoing the freeze.
202
- */
203
- function freezeDependencies(packageJsonPath) {
204
- const nodeModulesDir = path.join(process.cwd(), 'node_modules');
205
- if (!fs.existsSync(nodeModulesDir)) {
206
- console.error('[importgen] Error: node_modules not found');
207
- process.exit(1);
208
- }
209
- /** Check if a directory entry is a junction or symlink by comparing realpath to its path */
210
- function isLinked(entryPath) {
211
- try {
212
- const stat = fs.lstatSync(entryPath);
213
- // Symlink check (works on Linux/Mac symlinks)
214
- if (stat.isSymbolicLink())
215
- return true;
216
- // Junction check (Windows): realpath differs from the entry path
217
- if (stat.isDirectory()) {
218
- const real = fs.realpathSync(entryPath);
219
- return path.resolve(real) !== path.resolve(entryPath);
220
- }
221
- }
222
- catch (e) {
223
- console.error(`[importgen] Error checking ${entryPath}: ${e.message}`);
224
- }
225
- return false;
226
- }
227
- /** Freeze a single entry if it's a junction/symlink */
228
- function freezeEntry(entryPath, displayName) {
229
- if (!isLinked(entryPath))
230
- return;
231
- const target = fs.realpathSync(entryPath);
232
- console.log(` Freezing ${displayName} (${target})`);
233
- fs.rmSync(entryPath, { recursive: true });
234
- fs.cpSync(target, entryPath, { recursive: true });
235
- }
236
- console.log('[importgen] Freezing dependencies...');
237
- let frozenCount = 0;
238
- const entries = fs.readdirSync(nodeModulesDir);
239
- for (const entry of entries) {
240
- const entryPath = path.join(nodeModulesDir, entry);
241
- if (entry.startsWith('@')) {
242
- // Scoped package — walk one level deeper
243
- if (!fs.statSync(entryPath).isDirectory())
244
- continue;
245
- const scopedEntries = fs.readdirSync(entryPath);
246
- for (const scoped of scopedEntries) {
247
- const scopedPath = path.join(entryPath, scoped);
248
- const before = isLinked(scopedPath);
249
- freezeEntry(scopedPath, `${entry}/${scoped}`);
250
- if (before)
251
- frozenCount++;
252
- }
253
- }
254
- else {
255
- const before = isLinked(entryPath);
256
- freezeEntry(entryPath, entry);
257
- if (before)
258
- frozenCount++;
259
- }
260
- }
261
- console.log(`[importgen] Frozen ${frozenCount} linked packages`);
262
- // Add preinstall guard to package.json
263
- try {
264
- const pkgRaw = fs.readFileSync(packageJsonPath, 'utf-8');
265
- const pkg = JSON.parse(pkgRaw);
266
- if (!pkg.scripts)
267
- pkg.scripts = {};
268
- if (pkg.scripts.preinstall) {
269
- // Rename existing preinstall so unfreeze can restore it
270
- pkg.scripts['frozen-preinstall'] = pkg.scripts.preinstall;
271
- console.log(`[importgen] Saved existing preinstall script as "frozen-preinstall"`);
272
- }
273
- pkg.scripts.preinstall = 'echo FROZEN: dependencies were frozen by importgen. Use importgen --unfreeze to restore. && exit 1';
274
- fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
275
- console.log('[importgen] Added preinstall guard to package.json');
276
- }
277
- catch (e) {
278
- console.error(`[importgen] Error updating package.json: ${e.message}`);
279
- }
280
- }
281
- /**
282
- * Unfreeze: remove preinstall guard, restore original preinstall if saved, then run npm install.
283
- */
284
- function unfreezeDependencies(packageJsonPath) {
285
- try {
286
- const pkgRaw = fs.readFileSync(packageJsonPath, 'utf-8');
287
- const pkg = JSON.parse(pkgRaw);
288
- if (!pkg.scripts?.preinstall) {
289
- console.log('[importgen] No preinstall guard found — nothing to unfreeze');
290
- return;
291
- }
292
- if (pkg.scripts['frozen-preinstall']) {
293
- pkg.scripts.preinstall = pkg.scripts['frozen-preinstall'];
294
- delete pkg.scripts['frozen-preinstall'];
295
- console.log('[importgen] Restored original preinstall script');
296
- }
297
- else {
298
- delete pkg.scripts.preinstall;
299
- console.log('[importgen] Removed preinstall guard');
300
- }
301
- fs.writeFileSync(packageJsonPath, JSON.stringify(pkg, null, 2) + '\n', 'utf-8');
302
- }
303
- catch (e) {
304
- console.error(`[importgen] Error updating package.json: ${e.message}`);
305
- process.exit(1);
306
- }
307
- // Run npm install to restore proper dependencies
308
- console.log('[importgen] Running npm install...');
309
- try {
310
- execSync('npm install', { stdio: 'inherit', cwd: process.cwd() });
311
- console.log('[importgen] Unfreeze complete');
312
- }
313
- catch (e) {
314
- console.error(`[importgen] npm install failed: ${e.message}`);
315
- process.exit(1);
316
- }
317
- }
318
202
  // Parse CLI arguments
319
203
  const args = process.argv.slice(2);
320
204
  if (args.includes('-v') || args.includes('--version')) {
321
205
  console.log(`importgen ${packageJson.version}`);
322
206
  process.exit(0);
323
207
  }
324
- const knownFlags = new Set(['-w', '--watch', '--freeze', '-freeze', '--unfreeze', '-unfreeze', '-v', '--version']);
208
+ const knownFlags = new Set(['-w', '--watch', '-v', '--version']);
325
209
  // Report unrecognized flags as errors
326
210
  const unknownArgs = args.filter(a => a.startsWith('-') && !knownFlags.has(a));
327
211
  if (unknownArgs.length > 0) {
328
- console.error(`[importgen] Error: unrecognized argument(s): ${unknownArgs.join(', ')}`);
329
- console.error(` Usage: importgen [htmlfile] [-w|--watch] [--freeze] [--unfreeze] [-v|--version]`);
212
+ console.error(`${ts()} [importgen] Error: unrecognized argument(s): ${unknownArgs.join(', ')}`);
213
+ console.error(` Usage: importgen [htmlfile] [-w|--watch] [-v|--version]`);
330
214
  process.exit(1);
331
215
  }
332
216
  const watchMode = args.includes('-w') || args.includes('--watch');
333
- const freezeMode = args.includes('--freeze') || args.includes('-freeze');
334
- const unfreezeMode = args.includes('--unfreeze') || args.includes('-unfreeze');
335
217
  const positionalArgs = args.filter(a => !a.startsWith('-'));
336
218
  if (positionalArgs.length > 1) {
337
- console.error(`[importgen] Error: too many arguments: ${positionalArgs.join(', ')}`);
338
- console.error(` Usage: importgen [htmlfile] [-w|--watch] [--freeze] [--unfreeze] [-v|--version]`);
219
+ console.error(`${ts()} [importgen] Error: too many arguments: ${positionalArgs.join(', ')}`);
220
+ console.error(` Usage: importgen [htmlfile] [-w|--watch] [-v|--version]`);
339
221
  process.exit(1);
340
222
  }
341
223
  const htmlArg = positionalArgs[0];
@@ -346,23 +228,15 @@ const htmlFileName = htmlArg || possibleHtmlFiles.find(f => fs.existsSync(path.j
346
228
  const htmlFilePath = htmlFileName ? path.join(process.cwd(), htmlFileName) : null;
347
229
  // Check if files exist
348
230
  if (!fs.existsSync(packageJsonPath)) {
349
- console.error('[generate-importmap] Error: package.json not found in current directory');
231
+ console.error(`${ts()} [generate-importmap] Error: package.json not found in current directory`);
350
232
  process.exit(1);
351
233
  }
352
- if (freezeMode) {
353
- freezeDependencies(packageJsonPath);
354
- process.exit(0);
355
- }
356
- if (unfreezeMode) {
357
- unfreezeDependencies(packageJsonPath);
358
- process.exit(0);
359
- }
360
234
  if (!htmlFilePath || !fs.existsSync(htmlFilePath)) {
361
235
  if (htmlArg) {
362
- console.error(`[generate-importmap] Error: ${htmlArg} not found in current directory`);
236
+ console.error(`${ts()} [generate-importmap] Error: ${htmlArg} not found in current directory`);
363
237
  }
364
238
  else {
365
- console.error(`[generate-importmap] Error: No HTML file found. Looking for: ${possibleHtmlFiles.join(', ')}`);
239
+ console.error(`${ts()} [generate-importmap] Error: No HTML file found. Looking for: ${possibleHtmlFiles.join(', ')}`);
366
240
  }
367
241
  process.exit(1);
368
242
  }
@@ -405,7 +279,7 @@ if (watchMode) {
405
279
  watcher.on('unlink', onChange);
406
280
  watcher.on('ready', () => {
407
281
  const total = 1 + watchedDepDirs.size;
408
- console.log(`[generate-importmap] Watching ${total} directories for changes...`);
282
+ console.log(`${ts()} [generate-importmap] Watching ${total} directories for changes...`);
409
283
  if (watchedDepDirs.size > 0) {
410
284
  for (const dir of watchedDepDirs) {
411
285
  console.log(` ${dir}`);
@@ -413,7 +287,7 @@ if (watchMode) {
413
287
  }
414
288
  });
415
289
  watcher.on('error', (error) => {
416
- console.error('[generate-importmap] Watcher error:', error.message);
290
+ console.error(`${ts()} [generate-importmap] Watcher error:`, error.message);
417
291
  });
418
292
  }
419
293
  else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bobfrankston/importgen",
3
- "version": "0.1.26",
3
+ "version": "0.1.28",
4
4
  "description": "Generate ES Module import maps from package.json dependencies for native browser module loading",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -34,7 +34,7 @@
34
34
  "chokidar": "^4.0.3"
35
35
  },
36
36
  "devDependencies": {
37
- "@types/node": "^25.2.1"
37
+ "@types/node": "^25.3.0"
38
38
  },
39
39
  "publishConfig": {
40
40
  "access": "public"