import { promises as fs } from "node:fs" import path from "node:path" import ts from "typescript" const baseConfigFileName = "./tsconfig.json" const mappings = [ { type: "module", outDir: "mjs", tsExt: "mts" }, { type: "commonjs", outDir: "cjs", tsExt: "cts" }, ] const configFile = ts.readConfigFile(baseConfigFileName, ts.sys.readFile) if (configFile.error) { printDiagnostics(configFile.error) process.exit(1) } const configResult = ts.parseJsonConfigFileContent(configFile.config, ts.sys, "./") if (configResult.errors.length > 0) { printDiagnostics(...configResult.errors) process.exit(1) } for (const mapping of mappings) { try { await fs.rm(mapping.outDir, { recursive: true }) } catch (err) { } const newFileNames = new Array<string>() for (const fileName of configResult.fileNames) { let content = await fs.readFile(fileName, { encoding: "utf-8" }) content = content.replace(/(["'])([^"]+)\.ts\1/g, `$1$2.${mapping.tsExt.replace("ts", "js")}$1`) const newFileName = path.join(mapping.outDir, fileName.replace(/\.ts$/, `.${mapping.tsExt}`)) await fs.mkdir(path.dirname(newFileName), { recursive: true }) await fs.writeFile(newFileName, content, { encoding: "utf-8" }) newFileNames.push(newFileName) } const options: ts.CompilerOptions = { ...configResult.options, noEmit: false, emitDeclarationOnly: false, allowImportingTsExtensions: false, declaration: true, declarationMap: true, declarationDir: undefined, module: mapping.type === "module" ? ts.ModuleKind.ES2022 : ts.ModuleKind.CommonJS, moduleResolution: mapping.type === "module" ? ts.ModuleResolutionKind.Node16 : ts.ModuleResolutionKind.Node10, outDir: path.join(mapping.outDir, "lib") } const host = ts.createCompilerHost(options) const program = ts.createProgram(newFileNames, options, host) const emitResult = program.emit() if (emitResult.diagnostics.length > 0) { printDiagnostics(...emitResult.diagnostics) if (emitResult.emitSkipped) { process.exit(1) } } } function printDiagnostics(...diagnostics: ts.Diagnostic[]) { for (const diagnostic of diagnostics) { if (diagnostic.file) { const { line, character } = ts.getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start!); const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n"); console.error(`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`); } else { console.error(ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")); } } }