eslint-plugin-no-barrel-files
Version:
ESLint plugin for reducing barrel-file usage in two ways:
294 lines • 15.3 kB
JavaScript
;
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.createResolutionCaches = createResolutionCaches;
exports.createSharedResolutionCaches = createSharedResolutionCaches;
exports.setTypeScriptModuleLoaderForTests = setTypeScriptModuleLoaderForTests;
exports.getTypeScriptModule = getTypeScriptModule;
exports.hasTypeScriptModule = hasTypeScriptModule;
exports.getTsconfigPath = getTsconfigPath;
exports.getTsconfigInfo = getTsconfigInfo;
exports.resolveWithManualPaths = resolveWithManualPaths;
exports.getManualAliasMappings = getManualAliasMappings;
exports.resolveWithTsconfig = resolveWithTsconfig;
exports.resolveImport = resolveImport;
exports.reverseResolveManualAlias = reverseResolveManualAlias;
exports.reverseResolveTsconfigAlias = reverseResolveTsconfigAlias;
exports.getPreferredSourceSpecifier = getPreferredSourceSpecifier;
exports.getBarrelAnalysis = getBarrelAnalysis;
const node_fs_1 = __importDefault(require("node:fs"));
const node_path_1 = __importDefault(require("node:path"));
const analysis_1 = require("./analysis");
const path_utils_1 = require("./path-utils");
let loadTypeScriptModule = () => {
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('typescript');
}
catch (_a) {
/* c8 ignore next */
return null;
}
};
const sharedTsconfigCache = new Map();
const sharedTsconfigPathCache = new Map();
const sharedBarrelAnalysisCache = new Map();
function createResolutionCaches(sharedTsconfigCache = new Map(), sharedTsconfigPathCache = new Map()) {
return {
barrelAnalyses: new Map(),
importResolutions: new Map(),
tsconfigInfo: sharedTsconfigCache,
tsconfigPaths: sharedTsconfigPathCache,
};
}
function createSharedResolutionCaches() {
return Object.assign(Object.assign({}, createResolutionCaches(sharedTsconfigCache, sharedTsconfigPathCache)), { barrelAnalyses: sharedBarrelAnalysisCache });
}
function setTypeScriptModuleLoaderForTests(loader) {
sharedTsconfigCache.clear();
sharedTsconfigPathCache.clear();
sharedBarrelAnalysisCache.clear();
loadTypeScriptModule =
loader !== null && loader !== void 0 ? loader : (() => {
try {
// eslint-disable-next-line @typescript-eslint/no-require-imports
return require('typescript');
}
catch (_a) {
/* c8 ignore next */
return null;
}
});
}
function getTypeScriptModule() {
return loadTypeScriptModule();
}
function hasTypeScriptModule() {
return getTypeScriptModule() !== null;
}
function getTsconfigPath(options, importerFilename, cwd = process.cwd(), tsconfigPathCache = new Map()) {
var _a;
const typescript = getTypeScriptModule();
if (!typescript) {
return null;
}
if ((options === null || options === void 0 ? void 0 : options.tsconfig) === false) {
return null;
}
if (typeof (options === null || options === void 0 ? void 0 : options.tsconfig) === 'string') {
return node_path_1.default.isAbsolute(options.tsconfig) ? options.tsconfig : node_path_1.default.resolve(cwd, options.tsconfig);
}
const importerDirectory = node_path_1.default.dirname(importerFilename);
const cacheKey = `${(0, path_utils_1.getOptionsCacheKey)(options, cwd)}\0${importerDirectory}`;
const cachedPath = tsconfigPathCache.get(cacheKey);
if (cachedPath !== undefined) {
return cachedPath;
}
const tsconfigPath = (_a = typescript.findConfigFile(importerDirectory, typescript.sys.fileExists, 'tsconfig.json')) !== null && _a !== void 0 ? _a : null;
tsconfigPathCache.set(cacheKey, tsconfigPath);
return tsconfigPath;
}
function getTsconfigInfo(options, importerFilename, tsconfigCache, cwd = process.cwd(), tsconfigPathCache = new Map()) {
var _a;
const typescript = getTypeScriptModule();
if (!typescript) {
return null;
}
const tsconfigPath = getTsconfigPath(options, importerFilename, cwd, tsconfigPathCache);
if (!tsconfigPath) {
return null;
}
if (!tsconfigCache.has(tsconfigPath)) {
const configFile = typescript.readConfigFile(tsconfigPath, typescript.sys.readFile);
if (configFile.error) {
tsconfigCache.set(tsconfigPath, null);
}
else {
const parsedConfig = typescript.parseJsonConfigFileContent(configFile.config, typescript.sys, node_path_1.default.dirname(tsconfigPath), undefined, tsconfigPath);
tsconfigCache.set(tsconfigPath, {
compilerOptions: parsedConfig.options,
configFilePath: tsconfigPath,
moduleResolutionCache: typescript.createModuleResolutionCache(node_path_1.default.dirname(tsconfigPath), typescript.sys.useCaseSensitiveFileNames ? fileName => fileName : fileName => fileName.toLowerCase(), parsedConfig.options),
});
}
}
return (_a = tsconfigCache.get(tsconfigPath)) !== null && _a !== void 0 ? _a : null;
}
function resolveWithManualPaths(options, importerFilename, specifier, cwd = process.cwd()) {
const configuredPaths = options === null || options === void 0 ? void 0 : options.paths;
if (!configuredPaths) {
return null;
}
for (const [pattern, targetValue] of Object.entries(configuredPaths)) {
const wildcardValue = (0, path_utils_1.matchesAliasPattern)(specifier, pattern);
if (wildcardValue === null) {
continue;
}
const targets = Array.isArray(targetValue) ? targetValue : [targetValue];
for (const target of targets) {
const candidateSpecifier = (0, path_utils_1.applyAliasTarget)(target, wildcardValue);
const candidateBasePath = node_path_1.default.resolve(cwd, candidateSpecifier);
const resolvedFilePath = (0, path_utils_1.resolveModuleFile)(importerFilename, candidateBasePath);
if (resolvedFilePath) {
return resolvedFilePath;
}
}
}
return null;
}
function resolveWithBaseUrl(importerFilename, specifier, tsconfigInfo) {
const baseUrl = tsconfigInfo.compilerOptions.baseUrl;
if (!baseUrl) {
return null;
}
const configDirectory = node_path_1.default.dirname(tsconfigInfo.configFilePath);
const baseUrlDirectory = node_path_1.default.isAbsolute(baseUrl) ? baseUrl : node_path_1.default.resolve(configDirectory, baseUrl);
return (0, path_utils_1.resolveModuleFile)(importerFilename, node_path_1.default.resolve(baseUrlDirectory, specifier));
}
function hasMatchingTsconfigPath(specifier, tsconfigInfo) {
const paths = tsconfigInfo.compilerOptions.paths;
return (!!paths &&
typeof paths === 'object' &&
Object.keys(paths).some(pattern => (0, path_utils_1.matchesAliasPattern)(specifier, pattern) !== null));
}
function getManualAliasMappings(options) {
const configuredPaths = options === null || options === void 0 ? void 0 : options.paths;
if (!configuredPaths) {
return [];
}
return Object.entries(configuredPaths).flatMap(([pattern, targetValue]) => (Array.isArray(targetValue) ? targetValue : [targetValue]).map(target => ({
pattern,
target,
})));
}
function resolveWithTsconfig(options, importerFilename, specifier, tsconfigCache, cwd = process.cwd(), tsconfigPathCache = new Map()) {
const typescript = getTypeScriptModule();
if (!typescript) {
return null;
}
const tsconfigInfo = getTsconfigInfo(options, importerFilename, tsconfigCache, cwd, tsconfigPathCache);
if (!tsconfigInfo) {
return null;
}
const baseUrlResolution = resolveWithBaseUrl(importerFilename, specifier, tsconfigInfo);
if (baseUrlResolution) {
return baseUrlResolution;
}
if (!hasMatchingTsconfigPath(specifier, tsconfigInfo)) {
return null;
}
const resolvedModule = typescript.resolveModuleName(specifier, importerFilename, tsconfigInfo.compilerOptions, typescript.sys, tsconfigInfo.moduleResolutionCache).resolvedModule;
if (!resolvedModule || resolvedModule.isExternalLibraryImport) {
return null;
}
return node_fs_1.default.existsSync(resolvedModule.resolvedFileName) ? resolvedModule.resolvedFileName : null;
}
function resolveImport(options, resolutionCaches, importerFilename, specifier, cwd = process.cwd()) {
var _a;
const cacheKey = `${(0, path_utils_1.getOptionsCacheKey)(options, cwd)}\0${importerFilename}\0${specifier}`;
const cachedResult = resolutionCaches.importResolutions.get(cacheKey);
if (cachedResult !== undefined) {
return cachedResult;
}
const resolvedFilePath = (0, path_utils_1.isRelativePath)(specifier)
? (0, path_utils_1.resolveModuleFile)(importerFilename, specifier)
: ((_a = resolveWithManualPaths(options, importerFilename, specifier, cwd)) !== null && _a !== void 0 ? _a : resolveWithTsconfig(options, importerFilename, specifier, resolutionCaches.tsconfigInfo, cwd, resolutionCaches.tsconfigPaths));
resolutionCaches.importResolutions.set(cacheKey, resolvedFilePath);
return resolvedFilePath;
}
function reverseResolveManualAlias(options, resolvedFilePath, cwd = process.cwd()) {
const candidateAliases = getManualAliasMappings(options)
.map(mapping => {
if (mapping.target.includes('*')) {
const [rawPrefix = '', rawSuffix = ''] = mapping.target.split('*');
const normalizedResolvedFilePath = (0, path_utils_1.normalizeModulePath)(resolvedFilePath);
const normalizedPrefix = (0, path_utils_1.normalizeModulePath)(node_path_1.default.resolve(cwd, rawPrefix));
const normalizedSuffix = (0, path_utils_1.normalizeModulePath)(rawSuffix);
if (!normalizedResolvedFilePath.startsWith(normalizedPrefix) ||
!normalizedResolvedFilePath.endsWith(normalizedSuffix)) {
return null;
}
const wildcardValue = normalizedResolvedFilePath.slice(normalizedPrefix.length, normalizedResolvedFilePath.length - normalizedSuffix.length);
return (0, path_utils_1.buildAliasSpecifier)(mapping.pattern, wildcardValue.replace(/^\//, ''));
}
const targetFilePath = (0, path_utils_1.resolveModuleFile)(cwd, node_path_1.default.resolve(cwd, mapping.target));
return targetFilePath === resolvedFilePath ? mapping.pattern : null;
})
.filter((value) => value !== null);
return candidateAliases.length === 1 ? candidateAliases[0] : null;
}
function reverseResolveTsconfigAlias(options, importerFilename, resolvedFilePath, tsconfigCache, cwd = process.cwd(), tsconfigPathCache = new Map()) {
const tsconfigInfo = getTsconfigInfo(options, importerFilename, tsconfigCache, cwd, tsconfigPathCache);
if (!tsconfigInfo) {
return null;
}
const paths = tsconfigInfo.compilerOptions.paths;
if (!paths || typeof paths !== 'object') {
return null;
}
const configDirectory = node_path_1.default.dirname(tsconfigInfo.configFilePath);
const baseUrl = tsconfigInfo.compilerOptions.baseUrl;
const pathsBaseDirectory = baseUrl
? node_path_1.default.isAbsolute(baseUrl)
? baseUrl
: node_path_1.default.resolve(configDirectory, baseUrl)
: configDirectory;
const candidateAliases = Object.entries(paths)
.flatMap(([pattern, targets]) => targets.map(target => {
if (target.includes('*')) {
const [rawPrefix = '', rawSuffix = ''] = target.split('*');
const normalizedResolvedFilePath = (0, path_utils_1.normalizeModulePath)(resolvedFilePath);
const normalizedPrefix = (0, path_utils_1.normalizeModulePath)(node_path_1.default.resolve(pathsBaseDirectory, rawPrefix));
const normalizedSuffix = (0, path_utils_1.normalizeModulePath)(rawSuffix);
if (!normalizedResolvedFilePath.startsWith(normalizedPrefix) ||
!normalizedResolvedFilePath.endsWith(normalizedSuffix)) {
return null;
}
const wildcardValue = normalizedResolvedFilePath.slice(normalizedPrefix.length, normalizedResolvedFilePath.length - normalizedSuffix.length);
return (0, path_utils_1.buildAliasSpecifier)(pattern, wildcardValue.replace(/^\//, ''));
}
const targetFilePath = (0, path_utils_1.resolveModuleFile)(importerFilename, node_path_1.default.resolve(pathsBaseDirectory, target));
return targetFilePath === resolvedFilePath ? pattern : null;
}))
.filter((value) => value !== null);
return candidateAliases.length === 1 ? candidateAliases[0] : null;
}
function getPreferredSourceSpecifier(options, importerFilename, originalImportSpecifier, reExportTarget, tsconfigCache, cwd = process.cwd(), tsconfigPathCache = new Map()) {
var _a;
const fixStyle = (_a = options === null || options === void 0 ? void 0 : options.fixStyle) !== null && _a !== void 0 ? _a : 'auto';
if (fixStyle === 'relative') {
return (0, path_utils_1.toRelativeImportSpecifier)(importerFilename, reExportTarget.resolvedFilePath);
}
if (!(0, path_utils_1.isRelativePath)(reExportTarget.sourceSpecifier)) {
return reExportTarget.sourceSpecifier;
}
const aliasCandidates = [
reverseResolveManualAlias(options, reExportTarget.resolvedFilePath, cwd),
reverseResolveTsconfigAlias(options, importerFilename, reExportTarget.resolvedFilePath, tsconfigCache, cwd, tsconfigPathCache),
].filter((value) => value !== null);
const uniqueAliasCandidates = Array.from(new Set(aliasCandidates));
if (fixStyle === 'preserve-alias') {
return uniqueAliasCandidates.length === 1 ? uniqueAliasCandidates[0] : null;
}
if (!(0, path_utils_1.isRelativePath)(originalImportSpecifier) && uniqueAliasCandidates.length === 1) {
return uniqueAliasCandidates[0];
}
return (0, path_utils_1.toRelativeImportSpecifier)(importerFilename, reExportTarget.resolvedFilePath);
}
function getBarrelAnalysis(options, barrelFilePath, barrelExportCache, resolutionCaches, analysisCaches, cwd = process.cwd()) {
const cacheKey = `${(0, path_utils_1.getOptionsCacheKey)(options, cwd)}\0${barrelFilePath}`;
const cachedAnalysis = barrelExportCache.get(cacheKey);
if (cachedAnalysis !== undefined) {
return cachedAnalysis;
}
let barrelAnalysis = resolutionCaches.barrelAnalyses.get(cacheKey);
if (!resolutionCaches.barrelAnalyses.has(cacheKey)) {
barrelAnalysis = (0, analysis_1.parseBarrelFile)(barrelFilePath, (importerFilename, specifier) => resolveImport(options, resolutionCaches, importerFilename, specifier, cwd), analysisCaches);
resolutionCaches.barrelAnalyses.set(cacheKey, barrelAnalysis);
}
barrelExportCache.set(cacheKey, barrelAnalysis !== null && barrelAnalysis !== void 0 ? barrelAnalysis : null);
return barrelAnalysis !== null && barrelAnalysis !== void 0 ? barrelAnalysis : null;
}
//# sourceMappingURL=resolution.js.map