UNPKG

eslint-plugin-no-barrel-files

Version:

ESLint plugin for reducing barrel-file usage in two ways:

294 lines 15.3 kB
"use strict"; 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