dts-paths
Version:
Replace alias paths with relative paths after typescript compilation.
154 lines (150 loc) • 4.76 kB
JavaScript
/**
* @module dts-paths
* @package dts-paths
* @license MIT
* @version 1.1.8
* @author nuintun <nuintun@qq.com>
* @description Replace alias paths with relative paths after typescript compilation.
* @see https://github.com/nuintun/dts-paths#readme
*/
import { resolve } from 'node:path';
import { Project, ts } from 'ts-morph';
/**
* @module index
*/
const EXT_RE = /\.(?:(?:d\.)?([cm]?tsx?)|([cm]?jsx?))$/i;
function resolveModuleName(moduleName, containingFile, extensions, compilerOptions, moduleResolutionHost) {
for (const extension of extensions) {
for (const suffix of [extension, `/index${extension}`]) {
const { resolvedModule } = ts.resolveModuleName(
// Module name.
`${moduleName}${suffix}`,
// Containing file.
containingFile,
// Compiler options.
compilerOptions,
// Module resolution host.
moduleResolutionHost
);
if (resolvedModule) {
return resolvedModule;
}
}
}
const { resolvedModule } = ts.resolveModuleName(
// Module name.
moduleName,
// Containing file.
containingFile,
// Compiler options.
compilerOptions,
// Module resolution host.
moduleResolutionHost
);
return resolvedModule;
}
function getRelativeModulePath(resolvedFilePath, sourceFile) {
const relativePath = sourceFile.getRelativePathTo(resolvedFilePath);
const modulePath = relativePath.replace(EXT_RE, (match, tsExt, jsExt) => {
const fileExt = tsExt || jsExt;
if (fileExt) {
switch (fileExt.toLowerCase()) {
case 'js':
case 'ts':
case 'jsx':
case 'tsx':
return '.js';
case 'cjs':
case 'cts':
case 'cjsx':
case 'ctsx':
return '.cjs';
case 'mjs':
case 'mts':
case 'mjsx':
case 'mtsx':
return '.mjs';
default:
return match;
}
}
return match;
});
return modulePath.startsWith('.') ? modulePath : `./${modulePath}`;
}
/**
* @function resolvePaths
* @description Resolve dts import paths.
* @param root The root directory of dts.
* @param options The options of resolve.
* @return {Promise<Set<string>>}
*/
async function resolvePaths(
root,
{
compilerOptions,
exclude = ['node_modules'],
tsConfigFilePath = 'tsconfig.json',
extensions = ['.ts', '.cts', '.mts', '.d.ts', '.d.cts', '.d.mts']
} = {}
) {
const changed = new Set();
const moduleResolution = new Map();
const project = new Project({
compilerOptions,
skipAddingFilesFromTsConfig: true,
skipFileDependencyResolution: true,
tsConfigFilePath: resolve(tsConfigFilePath),
resolutionHost(moduleResolutionHost, getCompilerOptions) {
const compilerOptions = getCompilerOptions();
return {
resolveModuleNames(moduleNames, containingFile) {
const resolvedModules = [];
const resolvedImports = moduleResolution.get(containingFile) || new Map();
if (!moduleResolution.has(containingFile)) {
moduleResolution.set(containingFile, resolvedImports);
}
for (const moduleName of moduleNames) {
const resolvedModule = resolveModuleName(
moduleName,
containingFile,
extensions,
compilerOptions,
moduleResolutionHost
);
resolvedModules.push(resolvedModule);
if (resolvedModule && !resolvedModule.isExternalLibraryImport) {
resolvedImports.set(moduleName, resolvedModule.resolvedFileName);
}
}
return resolvedModules;
}
};
}
});
exclude = exclude.map(pattern => `!${pattern}`);
const include = resolve(root, '**/*.{ts,cts,mts,tsx,ctsx,mtsx}');
const sourceFiles = project.addSourceFilesAtPaths([include, ...exclude]);
project.resolveSourceFileDependencies();
for (const sourceFile of sourceFiles) {
const sourceFilePath = sourceFile.getFilePath();
const resolvedImports = moduleResolution.get(sourceFilePath);
if (resolvedImports) {
const importLiterals = sourceFile.getImportStringLiterals();
for (const importLiteral of importLiterals) {
const moduleName = importLiteral.getLiteralValue();
const resolvedFilePath = resolvedImports.get(moduleName);
if (resolvedFilePath) {
const relativeModulePath = getRelativeModulePath(resolvedFilePath, sourceFile);
if (relativeModulePath !== moduleName) {
changed.add(sourceFilePath);
importLiteral.setLiteralValue(relativeModulePath);
}
}
}
}
}
await project.save();
return changed;
}
export { resolvePaths };