tsc-path-fix
Version:
Zero-runtime TypeScript path resolver - converts aliases to relative paths at compile time. Fast, lightweight, with native watch mode.
231 lines • 11.1 kB
JavaScript
var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
return new (P || (P = Promise))(function (resolve, reject) {
function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
step((generator = generator.apply(thisArg, _arguments || [])).next());
});
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.loadConfig = void 0;
exports.validateTscPathfixConfig = validateTscPathfixConfig;
exports.prepareConfig = prepareConfig;
exports.normalizeTsConfigExtendsOption = normalizeTsConfigExtendsOption;
exports.resolveTsConfigExtendsPath = resolveTsConfigExtendsPath;
const fs_1 = require("fs");
const mylas_1 = require("mylas");
const path_1 = require("path");
const utils_1 = require("../utils");
const replacers_1 = require("./replacers");
const normalizePath = require("normalize-path");
function validateTscPathfixConfig(config) {
const errors = [];
const tscPathfixConfig = config['tsc-path-fix'];
if (!tscPathfixConfig) {
return errors;
}
if (tscPathfixConfig.replacers) {
const replacers = tscPathfixConfig.replacers;
for (const [name, options] of Object.entries(replacers)) {
if (options.enabled === undefined) {
errors.push(`Replacer "${name}" is missing the "enabled" property`);
}
if (options.enabled && options.file === undefined) {
errors.push(`Enabled replacer "${name}" is missing the "file" property`);
}
}
}
if (tscPathfixConfig.fileExtensions) {
const { inputGlob, outputCheck } = tscPathfixConfig.fileExtensions;
if (inputGlob && typeof inputGlob !== 'string') {
errors.push('fileExtensions.inputGlob must be a string');
}
if (outputCheck && !Array.isArray(outputCheck)) {
errors.push('fileExtensions.outputCheck must be an array');
}
else if (outputCheck && !outputCheck.every(item => typeof item === 'string')) {
errors.push('fileExtensions.outputCheck must be an array of strings');
}
}
if (tscPathfixConfig.resolveFullPaths !== undefined &&
typeof tscPathfixConfig.resolveFullPaths !== 'boolean') {
errors.push('resolveFullPaths must be a boolean value');
}
if (tscPathfixConfig.verbose !== undefined &&
typeof tscPathfixConfig.verbose !== 'boolean') {
errors.push('verbose must be a boolean value');
}
if (tscPathfixConfig.showProgress !== undefined &&
typeof tscPathfixConfig.showProgress !== 'boolean') {
errors.push('showProgress must be a boolean value');
}
return errors;
}
function prepareConfig(options) {
return __awaiter(this, void 0, void 0, function* () {
var _a, _b, _c, _d, _e, _f;
const output = (_a = options.output) !== null && _a !== void 0 ? _a : new utils_1.Output(options.verbose, options.debug);
const configFile = !options.configFile
? (0, path_1.resolve)(process.cwd(), 'tsconfig.json')
: !(0, path_1.isAbsolute)(options.configFile)
? (0, path_1.resolve)(process.cwd(), options.configFile)
: options.configFile;
output.assert((0, fs_1.existsSync)(configFile), `Invalid file path => ${configFile}`);
const { baseUrl = '', outDir, declarationDir, paths, replacers, resolveFullPaths, verbose, fileExtensions } = (0, exports.loadConfig)(configFile, output);
if ((_b = options === null || options === void 0 ? void 0 : options.fileExtensions) === null || _b === void 0 ? void 0 : _b.inputGlob) {
fileExtensions.inputGlob = options.fileExtensions.inputGlob;
}
if ((_c = options === null || options === void 0 ? void 0 : options.fileExtensions) === null || _c === void 0 ? void 0 : _c.outputCheck) {
fileExtensions.outputCheck = options.fileExtensions.outputCheck;
}
output.verbose = verbose;
if (options.resolveFullPaths || resolveFullPaths) {
output.debug('resolveFullPaths is active');
options.resolveFullPaths = true;
}
const _outDir = (_d = options.outDir) !== null && _d !== void 0 ? _d : outDir;
if (declarationDir && _outDir !== declarationDir) {
(_e = options.declarationDir) !== null && _e !== void 0 ? _e : (options.declarationDir = declarationDir);
}
output.assert(_outDir, 'compilerOptions.outDir is not set');
const configDir = normalizePath((0, path_1.dirname)(configFile));
const projectConfig = {
configFile: configFile,
baseUrl: baseUrl,
outDir: _outDir,
configDir: configDir,
outPath: _outDir,
confDirParentFolderName: (0, path_1.basename)(configDir),
hasExtraModule: false,
configDirInOutPath: null,
relConfDirPathInOutPath: null,
pathCache: new utils_1.PathCache(!options.watch, fileExtensions === null || fileExtensions === void 0 ? void 0 : fileExtensions.outputCheck),
inputGlob: (fileExtensions === null || fileExtensions === void 0 ? void 0 : fileExtensions.inputGlob) || '{mjs,cjs,js,jsx,d.{mts,cts,ts,tsx}}'
};
output.debug('loaded project config:', projectConfig);
const config = Object.assign(Object.assign({}, projectConfig), { output: output, aliasTrie: (_f = options.aliasTrie) !== null && _f !== void 0 ? _f : utils_1.TrieNode.buildAliasTrie(projectConfig, paths), replacers: [] });
output.debug('loaded full config:', config);
yield (0, replacers_1.importReplacers)(config, replacers, options.replacers);
return config;
});
}
function replaceConfigDirPlaceholder(path, configDir) {
return path.replace(/\$\{configDir\}/g, configDir);
}
const loadConfig = (file, output, baseConfigDir = null) => {
var _a, _b, _c;
if (!(0, fs_1.existsSync)(file)) {
output.error(`File ${file} not found`, true);
}
output.debug('Loading config file:', file);
const rawConfig = mylas_1.Json.loadS(file, true);
const validationErrors = validateTscPathfixConfig(rawConfig);
if (validationErrors.length > 0) {
const errorMessage = `Invalid tsc-path-fix configuration in ${file}:\n${validationErrors.join('\n')}`;
output.error(errorMessage, true);
}
const { extends: ext, compilerOptions: { baseUrl, outDir, declarationDir, paths } = {
baseUrl: undefined,
outDir: undefined,
declarationDir: undefined,
paths: undefined
}, 'tsc-path-fix': TSCAliasConfig } = rawConfig;
const configDir = (0, path_1.dirname)(file);
output.debug('configDir', configDir);
const config = {};
if (baseUrl) {
if (baseConfigDir !== null) {
config.baseUrl = replaceConfigDirPlaceholder(baseUrl, baseConfigDir);
}
else {
config.baseUrl = baseUrl;
}
}
if (outDir) {
let replacedOutDir = outDir;
if (baseConfigDir !== null) {
replacedOutDir = replaceConfigDirPlaceholder(outDir, baseConfigDir);
}
config.outDir = (0, path_1.isAbsolute)(replacedOutDir)
? replacedOutDir
: (0, path_1.join)(configDir, replacedOutDir);
}
if (paths) {
if (baseConfigDir !== null) {
for (const key in paths) {
paths[key] = paths[key].map((path) => replaceConfigDirPlaceholder(path, baseConfigDir));
}
}
config.paths = paths;
}
if (declarationDir) {
let replacedDeclarationDir = declarationDir;
if (baseConfigDir !== null) {
replacedDeclarationDir = replaceConfigDirPlaceholder(declarationDir, baseConfigDir);
}
config.declarationDir = (0, path_1.isAbsolute)(replacedDeclarationDir)
? replacedDeclarationDir
: (0, path_1.join)(configDir, replacedDeclarationDir);
}
if (TSCAliasConfig === null || TSCAliasConfig === void 0 ? void 0 : TSCAliasConfig.replacers) {
config.replacers = TSCAliasConfig.replacers;
}
if (TSCAliasConfig === null || TSCAliasConfig === void 0 ? void 0 : TSCAliasConfig.resolveFullPaths) {
config.resolveFullPaths = TSCAliasConfig.resolveFullPaths;
}
if (TSCAliasConfig === null || TSCAliasConfig === void 0 ? void 0 : TSCAliasConfig.verbose) {
config.verbose = TSCAliasConfig.verbose;
}
config.fileExtensions = (_a = TSCAliasConfig === null || TSCAliasConfig === void 0 ? void 0 : TSCAliasConfig.fileExtensions) !== null && _a !== void 0 ? _a : {};
const replacerFile = (_c = (_b = config.replacers) === null || _b === void 0 ? void 0 : _b.pathReplacer) === null || _c === void 0 ? void 0 : _c.file;
if (replacerFile) {
config.replacers.pathReplacer.file = (0, path_1.join)(configDir, replacerFile);
}
output.debug('loaded config (from file):', config);
if (ext) {
return Object.assign(Object.assign({}, normalizeTsConfigExtendsOption(ext, file).reduce((pre, ext) => (Object.assign(Object.assign({}, pre), (0, exports.loadConfig)(ext, output, baseConfigDir !== null && baseConfigDir !== void 0 ? baseConfigDir : configDir))), {})), config);
}
return config;
};
exports.loadConfig = loadConfig;
function normalizeTsConfigExtendsOption(ext, file) {
if (!ext)
return [];
const configDir = (0, path_1.dirname)(file);
const normExts = (Array.isArray(ext) ? ext : [ext]).map((e) => e.startsWith('.')
? (0, path_1.join)(configDir, e.endsWith('.json') ? e : `${e}.json`)
: resolveTsConfigExtendsPath(e, file));
return normExts;
}
function resolveTsConfigExtendsPath(ext, file) {
const tsConfigDir = (0, path_1.dirname)(file);
const node_modules = mylas_1.Dir.nodeModules({ cwd: tsConfigDir });
const targetPaths = node_modules.map((v) => (0, path_1.join)(tsConfigDir, v, ext));
for (const targetPath of targetPaths) {
if (ext.endsWith('.json')) {
if ((0, fs_1.existsSync)(targetPath)) {
return targetPath;
}
else {
continue;
}
}
let isDirectory = false;
try {
const stats = (0, fs_1.lstatSync)(targetPath);
isDirectory = stats.isDirectory() || stats.isSymbolicLink();
}
catch (err) { }
if (isDirectory) {
return (0, path_1.join)(targetPath, 'tsconfig.json');
}
else {
if ((0, fs_1.existsSync)(`${targetPath}.json`)) {
return `${targetPath}.json`;
}
}
}
}
//# sourceMappingURL=config.js.map
;