UNPKG

rsbuild-plugin-dts

Version:

Rsbuild plugin that supports emitting declaration files for TypeScript.

282 lines (281 loc) 16.2 kB
import * as __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__ from "node:fs"; import * as __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__ from "node:fs/promises"; import * as __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__ from "node:os"; import * as __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__ from "node:path"; import * as __WEBPACK_EXTERNAL_MODULE__ast_grep_napi_5dd5d9b1__ from "@ast-grep/napi"; import * as __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__ from "@rsbuild/core"; import * as __WEBPACK_EXTERNAL_MODULE_magic_string_758c1a52__ from "magic-string"; import * as __WEBPACK_EXTERNAL_MODULE_picocolors__ from "picocolors"; import * as __WEBPACK_EXTERNAL_MODULE_tinyglobby__ from "tinyglobby"; import * as __WEBPACK_EXTERNAL_MODULE_tsconfig_paths_df62e9eb__ from "tsconfig-paths"; import * as __WEBPACK_EXTERNAL_MODULE_typescript__ from "typescript"; const JS_EXTENSIONS = [ 'js', 'mjs', 'jsx', '(?<!\\.d\\.)ts', '(?<!\\.d\\.)mts', '(?<!\\.d\\.)cts', 'tsx', 'cjs', 'cjsx', 'mjsx', 'mtsx', 'ctsx' ]; const JS_EXTENSIONS_PATTERN = new RegExp(`\\.(${JS_EXTENSIONS.join('|')})$`); function loadTsconfig(tsconfigPath) { const configFile = __WEBPACK_EXTERNAL_MODULE_typescript__["default"].readConfigFile(tsconfigPath, __WEBPACK_EXTERNAL_MODULE_typescript__["default"].sys.readFile); const configFileContent = __WEBPACK_EXTERNAL_MODULE_typescript__["default"].parseJsonConfigFileContent(configFile.config, __WEBPACK_EXTERNAL_MODULE_typescript__["default"].sys, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].dirname(tsconfigPath)); return configFileContent; } const TEMP_FOLDER = '.rslib'; const TEMP_DTS_DIR = `${TEMP_FOLDER}/declarations`; function ensureTempDeclarationDir(cwd, name) { const dirPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, TEMP_DTS_DIR, name); if (__WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].existsSync(dirPath)) return dirPath; __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].mkdirSync(dirPath, { recursive: true }); const gitIgnorePath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, TEMP_FOLDER, '.gitignore'); __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].writeFileSync(gitIgnorePath, '**/*\n'); return dirPath; } async function pathExists(path) { return __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].promises.access(path).then(()=>true).catch(()=>false); } async function isDirectory(filePath) { try { const stat = await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].stat(filePath); return stat.isDirectory(); } catch { return false; } } async function emptyDir(dir) { if (!await pathExists(dir)) return; try { for (const file of (await __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].promises.readdir(dir)))await __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].promises.rm(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].resolve(dir, file), { recursive: true, force: true }); } catch (err) { __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.debug(`Failed to empty dir: ${dir}`); __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.debug(err); } } async function clearTempDeclarationDir(cwd) { const dirPath = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].join(cwd, TEMP_DTS_DIR); await emptyDir(dirPath); } function getFileLoc(diagnostic, configPath) { if (diagnostic.file) { const { line, character } = __WEBPACK_EXTERNAL_MODULE_typescript__["default"].getLineAndCharacterOfPosition(diagnostic.file, diagnostic.start); return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(diagnostic.file.fileName)}:${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow(line + 1)}:${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].yellow(character + 1)}`; } return `${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(configPath)}`; } const prettyTime = (seconds)=>{ const format = (time)=>__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].bold(time); if (seconds < 10) { const digits = seconds >= 0.01 ? 2 : 3; return `${format(seconds.toFixed(digits))} s`; } if (seconds < 60) return `${format(seconds.toFixed(1))} s`; const minutes = seconds / 60; return `${format(minutes.toFixed(2))} m`; }; const convertPath = (path)=>{ if ('win32' === (0, __WEBPACK_EXTERNAL_MODULE_node_os_74b4b876__.platform)()) return (0, __WEBPACK_EXTERNAL_MODULE_tinyglobby__.convertPathToPattern)(path); return path; }; function getTimeCost(start) { const second = (Date.now() - start) / 1000; return prettyTime(second); } async function addBannerAndFooter(dtsFile, banner, footer) { const content = await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].readFile(dtsFile, 'utf-8'); const code = new __WEBPACK_EXTERNAL_MODULE_magic_string_758c1a52__["default"](content); if (banner && !content.trimStart().startsWith(banner.trim())) code.prepend(`${banner}\n`); if (footer && !content.trimEnd().endsWith(footer.trim())) code.append(`\n${footer}\n`); if (code.hasChanged()) await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(dtsFile, code.toString()); } async function addExtension(redirect, dtsFile, path, extension) { if (!redirect.extension) return path; let redirectPath = path; if (await isDirectory((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.join)((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.dirname)(dtsFile), redirectPath))) redirectPath = `${redirectPath}/index`; return `${redirectPath}${extension}`; } async function redirectDtsImports(dtsFile, dtsExtension, redirect, matchPath, outDir, rootDir) { const content = await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].readFile(dtsFile, 'utf-8'); const code = new __WEBPACK_EXTERNAL_MODULE_magic_string_758c1a52__["default"](content); const sgNode = (await (0, __WEBPACK_EXTERNAL_MODULE__ast_grep_napi_5dd5d9b1__.parseAsync)("typescript", content)).root(); const matcher = { rule: { kind: 'string_fragment', any: [ { inside: { stopBy: 'end', kind: 'import_statement', field: 'source' } }, { inside: { stopBy: 'end', kind: 'export_statement', field: 'source' } }, { inside: { kind: 'string', inside: { kind: 'arguments', inside: { kind: 'call_expression', has: { field: 'function', regex: '^(import|require)$' } } } } } ] } }; const matchModule = sgNode.findAll(matcher).map((matchNode)=>({ n: matchNode.text(), s: matchNode.range().start.index, e: matchNode.range().end.index })); const extension = dtsExtension.replace(/\.d\.ts$/, '.js').replace(/\.d\.cts$/, '.cjs').replace(/\.d\.mts$/, '.mjs'); for (const imp of matchModule){ const { n: importPath, s: start, e: end } = imp; if (!!importPath) try { const absoluteImportPath = matchPath(importPath, void 0, void 0, [ '.jsx', '.tsx', '.js', '.ts', '.mjs', '.mts', '.cjs', '.cts' ]); let redirectImportPath = importPath; if (absoluteImportPath && redirect.path) { const isOutsideRootdir = !(0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(absoluteImportPath).startsWith((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(rootDir) + __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].sep); if (isOutsideRootdir) { const relativePath = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.relative)((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.dirname)(dtsFile), absoluteImportPath); redirectImportPath = relativePath.startsWith('..') ? relativePath : `./${relativePath}`; } else { const originalFilePath = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.resolve)(rootDir, (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.relative)(outDir, dtsFile)); const originalSourceDir = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.dirname)(originalFilePath); const relativePath = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.relative)(originalSourceDir, absoluteImportPath); redirectImportPath = relativePath.startsWith('..') ? relativePath : `./${relativePath}`; } } const ext = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.extname)(redirectImportPath); if (ext) { if (JS_EXTENSIONS_PATTERN.test(redirectImportPath)) { if (redirect.extension) redirectImportPath = redirectImportPath.replace(/\.[^.]+$/, extension); } } else { if (absoluteImportPath && (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(absoluteImportPath).startsWith((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(rootDir))) redirectImportPath = await addExtension(redirect, dtsFile, redirectImportPath, extension); if (!absoluteImportPath && importPath.startsWith('.')) redirectImportPath = await addExtension(redirect, dtsFile, redirectImportPath, extension); } const normalizedRedirectImportPath = redirectImportPath.split(__WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].sep).join('/'); code.overwrite(start, end, normalizedRedirectImportPath); } catch (err) { __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.debug(err); } } if (code.hasChanged()) await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].writeFile(dtsFile, code.toString()); } async function processDtsFiles(bundle, dir, dtsExtension, redirect, tsconfigPath, rootDir, banner, footer) { if (bundle) return; let matchPath; if (redirect.path || redirect.extension) { const result = (0, __WEBPACK_EXTERNAL_MODULE_tsconfig_paths_df62e9eb__.loadConfig)(tsconfigPath); if ('failed' === result.resultType) { __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.error(result.message); return; } const { absoluteBaseUrl, paths, mainFields, addMatchAll } = result; matchPath = (0, __WEBPACK_EXTERNAL_MODULE_tsconfig_paths_df62e9eb__.createMatchPath)(absoluteBaseUrl, paths, mainFields, addMatchAll); } const dtsFiles = await (0, __WEBPACK_EXTERNAL_MODULE_tinyglobby__.glob)(convertPath((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.join)(dir, '/**/*.d.ts')), { absolute: true }); for (const file of dtsFiles)try { if (banner || footer) await addBannerAndFooter(file, banner, footer); if ((redirect.path || redirect.extension) && matchPath) await redirectDtsImports(file, dtsExtension, redirect, matchPath, dir, rootDir); const newFile = file.replace('.d.ts', dtsExtension); __WEBPACK_EXTERNAL_MODULE_node_fs_5ea92f0c__["default"].renameSync(file, newFile); } catch (error) { __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.error(`Error renaming DTS file ${file}: ${error}`); } } function processSourceEntry(bundle, entryConfig) { if (!bundle) return []; if (entryConfig && Object.values(entryConfig).every((val)=>'string' == typeof val)) return Object.entries(entryConfig).map(([name, path])=>({ name, path })); throw new Error('@microsoft/api-extractor only support entry of Record<string, string> type to bundle DTS, please check your entry config.'); } async function calcLongestCommonPath(absPaths) { if (0 === absPaths.length) return null; const sep = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].posix.sep; const splitPaths = absPaths.map((p)=>p.split(sep)); let lcaFragments = splitPaths[0]; for(let i = 1; i < splitPaths.length; i++){ const currentPath = splitPaths[i]; const minLength = Math.min(lcaFragments.length, currentPath.length); let j = 0; while(j < minLength && lcaFragments[j] === currentPath[j])j++; lcaFragments = lcaFragments.slice(0, j); } let lca = lcaFragments.length > 0 ? lcaFragments.join(sep) : sep; const stats = await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].stat(lca); if (stats?.isFile()) lca = __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__["default"].dirname(lca); return lca; } async function cleanDtsFiles(dir) { const patterns = [ '/**/*.d.ts', '/**/*.d.cts', '/**/*.d.mts' ]; const files = await Promise.all(patterns.map((pattern)=>(0, __WEBPACK_EXTERNAL_MODULE_tinyglobby__.glob)(convertPath((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.join)(dir, pattern)), { absolute: true }))); const allFiles = files.flat(); await Promise.all(allFiles.map((file)=>__WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].rm(file, { force: true }))); } async function cleanTsBuildInfoFile(tsconfigPath, compilerOptions) { const tsconfigDir = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.dirname)(tsconfigPath); const { outDir, rootDir, tsBuildInfoFile } = compilerOptions; let tsbuildInfoFilePath = `${(0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.basename)(tsconfigPath, '.json')}${tsBuildInfoFile ?? '.tsbuildinfo'}`; if (outDir) tsbuildInfoFilePath = rootDir ? (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.join)(outDir, (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.relative)((0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.resolve)(tsconfigDir, rootDir), tsconfigDir), tsbuildInfoFilePath) : (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.join)(outDir, tsbuildInfoFilePath); if (await pathExists(tsbuildInfoFilePath)) await __WEBPACK_EXTERNAL_MODULE_node_fs_promises_153e37e0__["default"].rm(tsbuildInfoFilePath, { force: true }); } function getDtsEmitPath(pathFromPlugin, declarationDir, distPath) { return pathFromPlugin ?? declarationDir ?? distPath; } function warnIfOutside(cwd, dir, label) { if (dir) { const normalizedCwd = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(cwd); const normalizedDir = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.normalize)(dir); const relDir = (0, __WEBPACK_EXTERNAL_MODULE_node_path_c5b9b54f__.relative)(normalizedCwd, normalizedDir); if (relDir.startsWith('..')) __WEBPACK_EXTERNAL_MODULE__rsbuild_core_1b356efc__.logger.warn(`The resolved ${label} ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(normalizedDir)} is outside the project root ${__WEBPACK_EXTERNAL_MODULE_picocolors__["default"].cyan(normalizedCwd)}, please check your tsconfig file.`); } } export { JS_EXTENSIONS_PATTERN, TEMP_DTS_DIR, TEMP_FOLDER, addBannerAndFooter, calcLongestCommonPath, cleanDtsFiles, cleanTsBuildInfoFile, clearTempDeclarationDir, emptyDir, ensureTempDeclarationDir, getDtsEmitPath, getFileLoc, getTimeCost, isDirectory, loadTsconfig, pathExists, prettyTime, processDtsFiles, processSourceEntry, redirectDtsImports, warnIfOutside };