UNPKG

jsrunner-bundler

Version:

NPM Bundler (sources & types) for the JavaScript Runner

116 lines (101 loc) 4.13 kB
#!/usr/bin/env node // jsrunner-bundler.cjs // Empaqueta el bundle JS y genera typings como módulos ambient (“declare module 'x' { … }”) const fs = require('fs'); const path = require('path'); const webpack = require('webpack'); const { execSync } = require('child_process'); // Directorios: 'src' en raíz para el entry, y 'dist' en raíz para salida const SRC_DIR = path.resolve(__dirname, 'src'); const DIST_DIR = path.resolve(__dirname, 'dist'); const ENTRY_JS = path.join(SRC_DIR, 'index.js'); const OUT_JS = path.join(DIST_DIR, 'jsrunner.js'); const OUT_DTS = path.join(DIST_DIR, 'jsrunner.d.ts'); // Módulos a empaquetar pasados como argumentos const modules = process.argv.slice(2); if (!modules.length) { console.error('❌ Uso: node jsrunner-bundler.cjs <módulo1> [módulo2 …]'); process.exit(1); } /** * Recoge recursivamente todos los archivos .d.ts en un directorio */ function collectDtsFiles(dir, out = []) { for (const name of fs.readdirSync(dir)) { const full = path.join(dir, name); const stat = fs.statSync(full); if (stat.isDirectory()) collectDtsFiles(full, out); else if (name.endsWith('.d.ts')) out.push(full); } return out; } /** * Elimina líneas de import/export from 'x' y export {} */ function removeImportsAndExports(src) { return src .split('\n') .filter(line => { const t = line.trim(); if (/^(import|export)\s.*from\s+['"].+['"];?$/.test(t)) return false; if (/^export\s+\{\s*\};?$/.test(t)) return false; return true; }) .map(line => line.replace(/^export\s+/, '')) .join('\n'); } // 1) Instala dependencias locales console.log('📦 npm install %s', modules.join(' ')); execSync(`npm install ${modules.join(' ')}`, { stdio: 'inherit' }); // 2) Genera entry JS para Webpack en 'src/index.js' fs.mkdirSync(SRC_DIR, { recursive: true }); const entryContent = modules.map(m => `export * from "${m}";`).join('\n'); fs.writeFileSync(ENTRY_JS, entryContent, 'utf8'); // 3) Ejecuta Webpack console.log('🧩 Ejecutando Webpack…'); const webpackConfigPath = path.resolve(__dirname, 'webpack.config.js'); if (!fs.existsSync(webpackConfigPath)) { console.error('❌ No se encontró webpack.config.js'); process.exit(1); } const webpackConfig = require(webpackConfigPath); webpack(webpackConfig, (err, stats) => { if (err || stats.hasErrors()) { console.error('❌ Webpack falló:', err || stats.toJson().errors); process.exit(1); } console.log('✅ Bundle generado:', OUT_JS); // 4) Genera typings .d.ts como un único módulo ambient por paquete console.log('📄 Generando typings embebidos en un único module...'); let output = `// AUTO-GENERATED: combinadas para [${modules.join(', ')}]\n\n`; modules.forEach(modName => { // Resuelve ruta de package.json y root de tipos const pkgJsonPath = require.resolve(path.join(modName, 'package.json')); const pkgRoot = path.dirname(pkgJsonPath); const pkg = require(pkgJsonPath); let typesRoot = pkg.types || pkg.typings ? path.resolve(pkgRoot, pkg.types || pkg.typings) : pkgRoot; if (!fs.statSync(typesRoot).isDirectory()) typesRoot = path.dirname(typesRoot); // Recopila y concatena todos los .d.ts const files = collectDtsFiles(typesRoot).sort(); let combined = ''; files.forEach(file => { const rel = path.relative(typesRoot, file).replace(/\\/g, '/'); let src = fs.readFileSync(file, 'utf8'); src = removeImportsAndExports(src).trim(); combined += `// ----- ${rel} -----\n`; combined += src + '\n\n'; }); // Envuelve todo en un único declare module output += `declare module "${modName}" {\n`; combined.split('\n').forEach(line => { output += ' ' + line + '\n'; }); output += '}\n\n'; }); // Escribe el archivo resultante fs.mkdirSync(path.dirname(OUT_DTS), { recursive: true }); fs.writeFileSync(OUT_DTS, output, 'utf8'); console.log('✅ Typings generadas en:', OUT_DTS); });