/** * Babel plugin for IOR import transformation * This plugin can transform IOR imports at build time for better optimization */ const fs = require('node:fs'); const path = require('node:path'); // Cache for IOR mappings let iorMappings = null; /** * Build IOR mappings from component package.json files */ function buildMappings(projectRoot) { if (iorMappings) return iorMappings; iorMappings = new Map(); const componentsDir = path.join(projectRoot, 'src', 'components'); try { const scanDirectory = (dir, depth = 0) => { if (depth > 3) return; // Limit recursion depth const entries = fs.readdirSync(dir, { withFileTypes: true }); for (const entry of entries) { const fullPath = path.join(dir, entry.name); if (entry.isDirectory()) { scanDirectory(fullPath, depth + 1); } else if (entry.name === 'package.json') { try { const content = fs.readFileSync(fullPath, 'utf-8'); const pkg = JSON.parse(content); if (pkg.metatrom?.ior) { const componentDir = path.dirname(fullPath); const mainFile = pkg.main || 'index.ts'; const componentPath = path.join(componentDir, mainFile); // Create relative path from project root const relativePath = path.relative(projectRoot, componentPath).replace(/\\/g, '/'); // Normalize path separators // Store both with and without esm: prefix iorMappings.set(`ior:esm:${pkg.metatrom.ior}`, `./${relativePath}`); iorMappings.set(`ior:${pkg.metatrom.ior}`, `./${relativePath}`); } } catch (_err) { // Ignore parse errors } } } }; scanDirectory(componentsDir); } catch (_err) { console.warn('[Babel IOR Plugin] Could not scan components:', _err); } return iorMappings; } /** * Babel plugin factory */ module.exports = (babel) => { const { types: t } = babel; return { name: 'babel-plugin-ior', visitor: { // Transform import declarations ImportDeclaration(path, state) { const source = path.node.source.value; if (source.startsWith('ior:')) { const projectRoot = state.opts.projectRoot || process.cwd(); const mappings = buildMappings(projectRoot); const resolvedPath = mappings.get(source); if (resolvedPath) { // Replace the IOR import with the resolved path path.node.source = t.stringLiteral(resolvedPath); console.log(`[Babel IOR] Transformed: ${source} -> ${resolvedPath}`); } else { console.warn(`[Babel IOR] No mapping found for: ${source}`); } } }, // Transform dynamic imports CallExpression(path, state) { if ( path.node.callee.type === 'Import' || (path.node.callee.type === 'Identifier' && path.node.callee.name === 'require') ) { const arg = path.node.arguments[0]; if (t.isStringLiteral(arg) && arg.value.startsWith('ior:')) { const projectRoot = state.opts.projectRoot || process.cwd(); const mappings = buildMappings(projectRoot); const resolvedPath = mappings.get(arg.value); if (resolvedPath) { // Replace the IOR path with the resolved path path.node.arguments[0] = t.stringLiteral(resolvedPath); console.log( `[Babel IOR] Transformed dynamic import: ${arg.value} -> ${resolvedPath}`, ); } } } }, // Transform require() calls for CommonJS compatibility MemberExpression(path, state) { if ( path.node.object.type === 'CallExpression' && path.node.object.callee.type === 'Identifier' && path.node.object.callee.name === 'require' ) { const arg = path.node.object.arguments[0]; if (t.isStringLiteral(arg) && arg.value.startsWith('ior:')) { const projectRoot = state.opts.projectRoot || process.cwd(); const mappings = buildMappings(projectRoot); const resolvedPath = mappings.get(arg.value); if (resolvedPath) { path.node.object.arguments[0] = t.stringLiteral(resolvedPath); console.log(`[Babel IOR] Transformed require: ${arg.value} -> ${resolvedPath}`); } } } }, }, }; }; // Export utility functions for testing module.exports.buildMappings = buildMappings; module.exports.clearCache = () => { iorMappings = null; };