From ef4e8d065afdd9afcab2cb915b2fa94cd2920739 Mon Sep 17 00:00:00 2001 From: Ezio Lin Date: Sun, 25 Feb 2024 01:58:33 +0800 Subject: [PATCH] fix: declaration generation error (#733) --- src/builder/bundless/dts/index.ts | 35 ++++++++-------- src/builder/bundless/index.ts | 68 ++++++++++++++++++++++++------- 2 files changed, 72 insertions(+), 31 deletions(-) diff --git a/src/builder/bundless/dts/index.ts b/src/builder/bundless/dts/index.ts index 5c4f30b8..976afc39 100644 --- a/src/builder/bundless/dts/index.ts +++ b/src/builder/bundless/dts/index.ts @@ -143,17 +143,13 @@ export default async function getDeclarations( sourceFile, }; - // only collect dts for input files, to avoid output error in watch mode - // ref: https://github.com/umijs/father-next/issues/43 - if (inputFiles.includes(sourceFile)) { - const index = output.findIndex( - (out) => out.file === ret.file && out.sourceFile === ret.sourceFile, - ); - if (index > -1) { - output.splice(index, 1, ret); - } else { - output.push(ret); - } + const index = output.findIndex( + (out) => out.file === ret.file && out.sourceFile === ret.sourceFile, + ); + if (index > -1) { + output.splice(index, 1, ret); + } else { + output.push(ret); } // group cache by file (d.ts & d.ts.map) @@ -221,11 +217,14 @@ export default async function getDeclarations( // check compile error // ref: https://github.com/microsoft/TypeScript/wiki/Using-the-Compiler-API#a-minimal-compiler - const diagnostics = ts + const allDiagnostics = ts .getPreEmitDiagnostics(incrProgram.getProgram()) - .concat(result.diagnostics) - // omit error for files which not included by build - .filter((d) => !d.file || inputFiles.includes(d.file.fileName)); + .concat(result.diagnostics); + + // omit error for files which not included by build + const diagnostics = allDiagnostics.filter( + (d) => !d.file || inputFiles.includes(d.file.fileName), + ); /* istanbul ignore if -- @preserve */ if (diagnostics.length) { @@ -256,7 +255,11 @@ export default async function getDeclarations( }); throw new Error('Declaration generation failed.'); } + + return output.filter( + (it) => !allDiagnostics.some((d) => d.file?.fileName === it.sourceFile), + ); } - return output; + return []; } diff --git a/src/builder/bundless/index.ts b/src/builder/bundless/index.ts index 9f781990..f17cff45 100644 --- a/src/builder/bundless/index.ts +++ b/src/builder/bundless/index.ts @@ -30,6 +30,13 @@ function replacePathExt(filePath: string, ext: string) { return path.join(parsed.dir, `${parsed.name}${ext}`); } +/** + * checks if a file path is located within a specific directory. + */ +const isFileInDir = (filePath: string, dirPath: string) => { + return filePath.startsWith(winPath(dirPath).replace(/\/+$/, '')); +}; + /** * transform specific files */ @@ -41,22 +48,36 @@ async function transformFiles( watch?: true; }, ) { + // get config and dist path info for specific item + const itemPathInfo = (item: string) => { + const config = opts.configProvider.getConfigForFile(item); + + if (config) { + const itemDistPath = path.join( + config.output!, + path.relative(config.input, item), + ); + const itemDistAbsPath = path.join(opts.cwd, itemDistPath); + const itemDistDir = path.dirname(itemDistAbsPath); + + return { config, itemDistPath, itemDistAbsPath, itemDistDir }; + } else { + return null; + } + }; + try { let count = 0; const declarationFileMap = new Map(); // process all matched items for (let item of files) { - const config = opts.configProvider.getConfigForFile(item); + const pathInfo = itemPathInfo(item); const itemAbsPath = path.join(opts.cwd, item); - if (config) { - let itemDistPath = path.join( - config.output!, - path.relative(config.input, item), - ); - let itemDistAbsPath = path.join(opts.cwd, itemDistPath); - const parentPath = path.dirname(itemDistAbsPath); + if (pathInfo) { + const { config, itemDistDir: parentPath, ...itemDisInfo } = pathInfo; + let { itemDistPath, itemDistAbsPath } = itemDisInfo; // create parent directory if not exists if (!fs.existsSync(parentPath)) { @@ -124,13 +145,30 @@ async function transformFiles( }, ); - declarations.forEach((item) => { - fs.writeFileSync( - path.join(declarationFileMap.get(item.sourceFile)!, item.file), - item.content, - 'utf-8', - ); - }); + declarations + // filterMap: filter out declarations with unrecognized distDir and mapping it + .flatMap(({ sourceFile, ...declaration }) => { + // Prioritize using declarationFileMap + // If not available, try to recalculate itemDistDir + const distDir = + declarationFileMap.get(sourceFile) ?? + (() => { + const watchRoot = path.join(opts.cwd, opts.configProvider.input); + const isInWatchDir = isFileInDir(sourceFile, watchRoot); + return isInWatchDir + ? itemPathInfo(path.relative(opts.cwd, sourceFile))?.itemDistDir + : undefined; + })(); + + return distDir ? [{ distDir, declaration }] : []; + }) + .forEach(({ distDir, declaration }) => { + fs.writeFileSync( + path.join(distDir, declaration.file), + declaration.content, + 'utf-8', + ); + }); } return count;