UNPKG

rsbuild-plugin-dts

Version:

Rsbuild plugin that supports emitting declaration files for TypeScript.

151 lines (150 loc) 8.29 kB
import { logger } from "@rsbuild/core"; import { updateDeclarationMapContent, loadTypescript, processDtsFiles, color, renameDtsFile, getTimeCost } from "./188.js"; const logPrefixTsc = color.dim('[tsc]'); const createFormatHost = (ts)=>({ getCanonicalFileName: (path)=>path, getCurrentDirectory: ts.sys.getCurrentDirectory.bind(ts.sys), getNewLine: ()=>ts.sys.newLine }); async function handleDiagnosticsAndProcessFiles(ts, formatHost, diagnostics, configPath, bundle, cwd, declarationDir, dtsExtension, redirect, rootDir, paths, banner, footer, name) { const diagnosticMessages = []; for (const diagnostic of diagnostics){ const message = ts.formatDiagnosticsWithColorAndContext([ diagnostic ], formatHost); diagnosticMessages.push(message); } await processDtsFiles(bundle, cwd, declarationDir, dtsExtension, redirect, configPath, rootDir, paths, banner, footer); if (diagnosticMessages.length) { for (const message of diagnosticMessages)logger.error(logPrefixTsc, message); const error = new Error(`Failed to generate declaration files. ${color.dim(`(${name})`)}`); error.stack = ''; throw error; } } async function emitDtsTsc(options, onComplete, bundle = false, isWatch = false, build = false) { const start = Date.now(); const { configPath, tsConfigResult, declarationDir, name, dtsExtension, rootDir, cwd, banner, footer, paths, redirect } = options; const ts = loadTypescript(cwd); const formatHost = createFormatHost(ts); const { options: rawCompilerOptions, fileNames, projectReferences } = tsConfigResult; const compilerOptions = { ...rawCompilerOptions, configFilePath: configPath, noEmit: false, declaration: true, declarationDir, emitDeclarationOnly: true }; const createProgram = ts.createSemanticDiagnosticsBuilderProgram; const reportDiagnostic = (diagnostic)=>{ logger.error(logPrefixTsc, ts.formatDiagnosticsWithColorAndContext([ diagnostic ], formatHost)); }; const reportWatchStatusChanged = async (diagnostic, _newLine, _options, errorCount)=>{ const message = `${ts.flattenDiagnosticMessageText(diagnostic.messageText, formatHost.getNewLine())} ${color.dim(`(${name})`)}`; if (6031 === diagnostic.code || 6032 === diagnostic.code) logger.info(logPrefixTsc, message); if (6194 === diagnostic.code) { if (0 !== errorCount && errorCount) logger.error(logPrefixTsc, message); else { logger.info(logPrefixTsc, message); onComplete(true); } await processDtsFiles(bundle, cwd, declarationDir, dtsExtension, redirect, configPath, rootDir, paths, banner, footer); } if (6193 === diagnostic.code) { logger.error(logPrefixTsc, message); await processDtsFiles(bundle, cwd, declarationDir, dtsExtension, redirect, configPath, rootDir, paths, banner, footer); } }; const system = { ...ts.sys, writeFile: (fileName, contents, writeByteOrderMark)=>{ const newFileName = renameDtsFile(fileName, dtsExtension, bundle); const newContents = updateDeclarationMapContent(fileName, contents, dtsExtension, bundle, compilerOptions.declarationMap); ts.sys.writeFile(newFileName, newContents, writeByteOrderMark); } }; if (isWatch) if (build) { const host = ts.createSolutionBuilderWithWatchHost(system, createProgram, reportDiagnostic, void 0, reportWatchStatusChanged); const solutionBuilder = ts.createSolutionBuilderWithWatch(host, [ configPath ], compilerOptions, { watch: true }); solutionBuilder.build(); } else { const host = ts.createWatchCompilerHost(configPath, compilerOptions, system, createProgram, reportDiagnostic, reportWatchStatusChanged); ts.createWatchProgram(host); } else { if (build || compilerOptions.composite) if (!build && compilerOptions.composite) { const originHost = ts.createIncrementalCompilerHost(compilerOptions); const host = { ...originHost, writeFile: (fileName, contents, writeByteOrderMark, onError, sourceFiles)=>{ const newFileName = renameDtsFile(fileName, dtsExtension, bundle); const newContents = updateDeclarationMapContent(fileName, contents, dtsExtension, bundle, compilerOptions.declarationMap); originHost.writeFile(newFileName, newContents, writeByteOrderMark, onError, sourceFiles); } }; const program = ts.createIncrementalProgram({ rootNames: fileNames, options: compilerOptions, configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(tsConfigResult), projectReferences, host, createProgram }); const allDiagnostics = []; allDiagnostics.push(...program.getConfigFileParsingDiagnostics(), ...program.getSyntacticDiagnostics(), ...program.getOptionsDiagnostics(), ...program.getGlobalDiagnostics(), ...program.getSemanticDiagnostics(), ...program.getDeclarationDiagnostics()); const emitResult = program.emit(); allDiagnostics.push(...emitResult.diagnostics); const sortAndDeduplicateDiagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); await handleDiagnosticsAndProcessFiles(ts, formatHost, sortAndDeduplicateDiagnostics, configPath, bundle, cwd, declarationDir, dtsExtension, redirect, rootDir, paths, banner, footer, name); } else { let errorNumber = 0; const reportErrorSummary = (errorCount)=>{ errorNumber = errorCount; }; const host = ts.createSolutionBuilderHost(system, createProgram, reportDiagnostic, void 0, reportErrorSummary); const solutionBuilder = ts.createSolutionBuilder(host, [ configPath ], compilerOptions); solutionBuilder.build(); await processDtsFiles(bundle, cwd, declarationDir, dtsExtension, redirect, configPath, rootDir, paths, banner, footer); if (errorNumber > 0) { const error = new Error(`Failed to generate declaration files. ${color.dim(`(${name})`)}`); error.stack = ''; throw error; } } else { const originHost = ts.createCompilerHost(compilerOptions); const host = { ...originHost, writeFile: (fileName, contents, writeByteOrderMark, onError, sourceFiles)=>{ const newFileName = renameDtsFile(fileName, dtsExtension, bundle); const newContents = updateDeclarationMapContent(fileName, contents, dtsExtension, bundle, compilerOptions.declarationMap); originHost.writeFile(newFileName, newContents, writeByteOrderMark, onError, sourceFiles); } }; const program = ts.createProgram({ rootNames: fileNames, options: compilerOptions, projectReferences, host, configFileParsingDiagnostics: ts.getConfigFileParsingDiagnostics(tsConfigResult) }); const preEmitDiagnostics = ts.getPreEmitDiagnostics(program); const emitResult = program.emit(); const allDiagnostics = preEmitDiagnostics.concat(emitResult.diagnostics); const sortAndDeduplicateDiagnostics = ts.sortAndDeduplicateDiagnostics(allDiagnostics); await handleDiagnosticsAndProcessFiles(ts, formatHost, sortAndDeduplicateDiagnostics, configPath, bundle, cwd, declarationDir, dtsExtension, redirect, rootDir, paths, banner, footer, name); } if (bundle) logger.info(`declaration files prepared in ${getTimeCost(start)} ${color.dim(`(${name})`)}`); else logger.ready(`declaration files generated in ${getTimeCost(start)} ${color.dim(`(${name})`)}`); } } export { emitDtsTsc };