tsconfig-replace-paths
Version:
Replace absolute paths to relative paths for package compilation
140 lines (139 loc) • 5.6 kB
JavaScript
import { existsSync } from 'fs';
import { dirname, join, relative, resolve } from 'path';
const LOOKUP_EXTS = ['.js', '.jsx', '.ts', '.tsx', '.d.ts', '.json'];
export function toRelative(from, target) {
const rel = relative(from, target);
return (rel.startsWith('.') ? rel : `./${rel}`).replace(/\\/g, '/');
}
function stripExtension(filePath) {
const ext = LOOKUP_EXTS.find(function (candidate) {
return filePath.endsWith(candidate);
});
if (ext) {
return {
base: filePath.substring(0, filePath.length - ext.length),
ext: ext,
};
}
return { base: filePath, ext: undefined };
}
function findExistingModule(basePath) {
const stripped = stripExtension(basePath);
if (stripped.ext && existsSync(basePath)) {
return { path: basePath, ext: stripped.ext };
}
if (stripped.ext === '.js' && existsSync(`${stripped.base}.ts`)) {
return { path: `${stripped.base}.ts`, ext: '.ts' };
}
if (stripped.ext === '.js' && existsSync(`${stripped.base}.tsx`)) {
return { path: `${stripped.base}.tsx`, ext: '.tsx' };
}
for (let i = 0; i < LOOKUP_EXTS.length; i += 1) {
const candidate = `${stripped.base}${LOOKUP_EXTS[i]}`;
if (existsSync(candidate)) {
return { path: candidate, ext: LOOKUP_EXTS[i] };
}
}
return null;
}
function sourcePathToOutputPath(sourceFile, usingSrcDir, outPath) {
const rel = relative(usingSrcDir, sourceFile);
if (rel.startsWith('..')) {
return join(outPath, rel);
}
return join(outPath, rel);
}
function mapSourceExtToOutput(sourceFile) {
if (sourceFile.endsWith('.tsx')) {
return `${sourceFile.substring(0, sourceFile.length - 4)}.jsx`;
}
if (sourceFile.endsWith('.ts')) {
return `${sourceFile.substring(0, sourceFile.length - 3)}.js`;
}
return sourceFile;
}
function findOutputModule(sourceModule, usingSrcDir, outPath) {
const mappedOutput = mapSourceExtToOutput(sourcePathToOutputPath(sourceModule.path, usingSrcDir, outPath));
if (existsSync(mappedOutput)) {
return mappedOutput;
}
const stripped = stripExtension(mappedOutput);
for (let i = 0; i < LOOKUP_EXTS.length; i += 1) {
const candidate = `${stripped.base}${LOOKUP_EXTS[i]}`;
if (existsSync(candidate)) {
return candidate;
}
}
if (sourceModule.ext === '.ts' || sourceModule.ext === '.tsx') {
return mappedOutput;
}
return sourceModule.path;
}
export function createAliasResolver(ctx) {
let replaceCount = 0;
function absToRel(modulePath, outFile) {
const alen = ctx.aliases.length;
for (let j = 0; j < alen; j += 1) {
const alias = ctx.aliases[j];
const prefix = alias.prefix;
const aliasPaths = alias.aliasPaths;
if (!modulePath.startsWith(prefix)) {
continue;
}
const modulePathRel = modulePath.substring(prefix.length);
const outFileDir = dirname(outFile);
const srcMirror = resolve(ctx.usingSrcDir, relative(ctx.outPath, outFile));
ctx.verboseLog(`${relative(ctx.basePath, outFile)} (source: ${relative(ctx.basePath, srcMirror)}):`);
ctx.verboseLog(`\timport '${modulePath}'`);
for (let i = 0; i < aliasPaths.length; i += 1) {
const apath = aliasPaths[i];
const lookupBase = resolve(apath, modulePathRel);
const sourceModule = findExistingModule(lookupBase);
if (!sourceModule) {
continue;
}
const outputModule = findOutputModule(sourceModule, ctx.usingSrcDir, ctx.outPath);
const modulePathEndsWithJs = modulePath.endsWith('.js') || modulePath.endsWith('.jsx');
const aliasUsesJs = apath.endsWith('.js') || apath.endsWith('.jsx');
let targetPath = outputModule || sourceModule.path;
if (targetPath.endsWith('.ts') || targetPath.endsWith('.tsx')) {
targetPath = mapSourceExtToOutput(targetPath);
}
if ((modulePathEndsWithJs || aliasUsesJs) && (targetPath.endsWith('.js') || targetPath.endsWith('.jsx'))) {
}
else if (!modulePathEndsWithJs && targetPath.endsWith('.js')) {
targetPath = targetPath.substring(0, targetPath.length - 3);
}
else if (!modulePathEndsWithJs && targetPath.endsWith('.jsx')) {
targetPath = targetPath.substring(0, targetPath.length - 4);
}
const rel = toRelative(outFileDir, targetPath);
replaceCount += 1;
ctx.verboseLog(`\treplacing '${modulePath}' -> '${rel}' referencing ${relative(ctx.basePath, sourceModule.path)}`);
return rel;
}
ctx.verboseLog(`\tcould not replace ${modulePath}`);
}
return modulePath;
}
return {
absToRel: absToRel,
getReplaceCount: function () {
return replaceCount;
},
};
}
export function buildAliases(paths, basePath) {
return Object.keys(paths)
.map(function (alias) {
return {
prefix: alias.replace(/\*$/, ''),
aliasPaths: paths[alias].map(function (p) {
return resolve(basePath, p.replace(/\*$/, ''));
}),
};
})
.filter(function (entry) {
return entry.prefix;
});
}