rsbuild-plugin-dts
Version:
Rsbuild plugin that supports emitting declaration files for TypeScript.
282 lines (281 loc) • 16.2 kB
JavaScript
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 };