UNPKG

techor

Version:

Author technology like a top leader

104 lines (99 loc) 5.34 kB
/* Techor ESM Shim */ import __url_for_shim from 'url'; import __path_for_shim from 'path'; import __mod_for_shim from 'module'; const __filename = __url_for_shim.fileURLToPath(import.meta.url); const __dirname = __path_for_shim.dirname(__filename); const require = __mod_for_shim.createRequire(import.meta.url); import { parse } from 'acorn'; import escodegen from 'escodegen'; const parseOptions = { ecmaVersion: 'latest', sourceType: 'module' }; const urlImportDeclaration = parse('import __url_for_shim from "url";', parseOptions).body[0]; const pathImportDeclaration = parse('import __path_for_shim from "path";', parseOptions).body[0]; const moduleImportDeclaration = parse('import __mod_for_shim from "module";', parseOptions).body[0]; const filenameDeclaration = parse('const __filename = __url_for_shim.fileURLToPath(import.meta.url);', parseOptions).body[0]; const dirnameDeclaration = parse('const __dirname = __path_for_shim.dirname(__filename);', parseOptions).body[0]; const requireDeclaration = parse('const require = __mod_for_shim.createRequire(import.meta.url);', parseOptions).body[0]; function esmShim() { return { name: 'techor-esm-shim', renderChunk: { order: 'pre', async handler (code, chunk, options) { if (options.format === 'es') { const ast = this.parse(code); if (ast.type === 'Program' && ast.body) { const newDeclarations = new Set(); const filteredBody = ast.body.filter(Boolean); let dirnameDeclared = false; let filenameDeclared = false; let requireDeclared = false; // top-level declarations for (const node of filteredBody){ if (node.type === 'VariableDeclaration') { const varName = node.declarations[0].id?.['name']; switch(varName){ case '__dirname': dirnameDeclared = true; break; case '__filename': filenameDeclared = true; break; case 'require': requireDeclared = true; break; } } } let dirnameUsed = false; let filenameUsed = false; let requireUsed = false; // walk the ESTree to find whether the variables `__dirname` `__filename` `require` are used const walk = (node)=>{ if (node.type === 'Identifier') { const name = node.name; if (name === '__dirname') dirnameUsed = true; if (name === '__filename') filenameUsed = true; if (name === 'require') requireUsed = true; } for(const key in node){ if (node[key] && typeof node[key] === 'object') { walk(node[key]); } } }; for (const node of filteredBody){ walk(node); } // import if (!filenameDeclared && filenameUsed || !dirnameDeclared && dirnameUsed) newDeclarations.add(urlImportDeclaration); if (!dirnameDeclared && dirnameUsed) newDeclarations.add(pathImportDeclaration); if (!requireDeclared && requireUsed) newDeclarations.add(moduleImportDeclaration); // variable if (!filenameDeclared && filenameUsed || !dirnameDeclared && dirnameUsed) newDeclarations.add(filenameDeclaration); if (!dirnameDeclared && dirnameUsed) newDeclarations.add(dirnameDeclaration); if (!requireDeclared && requireUsed) newDeclarations.add(requireDeclaration); if (newDeclarations.size > 0) { // extract shebang if exists const shebang = code.match(/^#!(.*)/)?.[0] || ''; ast.body.unshift(...Array.from(newDeclarations)); const generated = escodegen.generate(ast, { sourceMapWithCode: true, directive: true }); return { code: (shebang ? shebang + '\n' : '') + generated.code, map: generated.map }; } } } return null; } } }; } export { esmShim as default };