mp-lens
Version:
微信小程序分析工具 (Unused Code, Dependencies, Visualization)
223 lines • 10.2 kB
JavaScript
"use strict";
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
var desc = Object.getOwnPropertyDescriptor(m, k);
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
desc = { enumerable: true, get: function() { return m[k]; } };
}
Object.defineProperty(o, k2, desc);
}) : (function(o, m, k, k2) {
if (k2 === undefined) k2 = k;
o[k2] = m[k];
}));
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
Object.defineProperty(o, "default", { enumerable: true, value: v });
}) : function(o, v) {
o["default"] = v;
});
var __importStar = (this && this.__importStar) || (function () {
var ownKeys = function(o) {
ownKeys = Object.getOwnPropertyNames || function (o) {
var ar = [];
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
return ar;
};
return ownKeys(o);
};
return function (mod) {
if (mod && mod.__esModule) return mod;
var result = {};
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
__setModuleDefault(result, mod);
return result;
};
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.AliasResolver = void 0;
const fs = __importStar(require("fs"));
const path = __importStar(require("path"));
const debug_logger_1 = require("./debug-logger");
/**
* 别名解析器: 负责从不同配置文件中加载路径别名
*/
class AliasResolver {
constructor(projectRoot) {
this.aliases = {};
this.initialized = false;
this.projectRoot = projectRoot;
}
/**
* 初始化别名解析器
* @returns 是否找到有效的别名配置
*/
initialize() {
if (this.initialized)
return Object.keys(this.aliases).length > 0;
// 尝试从不同来源加载别名
const foundTsConfig = this.loadFromTsConfig();
const foundCustomConfig = this.loadFromCustomConfig();
if (foundTsConfig) {
debug_logger_1.logger.info(`已从tsconfig.json加载别名配置`);
}
if (foundCustomConfig) {
debug_logger_1.logger.info(`已从mp-lens.config.json加载别名配置`);
}
if (this.projectRoot) {
debug_logger_1.logger.info(`alias解析的根目录: ${this.projectRoot}`);
}
this.initialized = true;
// 如果至少找到一个来源的别名配置,返回true
return foundTsConfig || foundCustomConfig;
}
/**
* 解析别名路径
* @param importPath 导入路径
* @param currentFile 当前文件路径
* @returns 解析后的路径,如果找不到匹配的别名则返回null
*/
resolve(importPath, currentFile) {
if (!this.initialized) {
this.initialize();
}
debug_logger_1.logger.trace(`Resolving alias prefix for import '${importPath}' in file '${currentFile}'`);
for (const [alias, targets] of Object.entries(this.aliases)) {
// Basic alias pattern check (e.g., starts with @/ or aliasName/)
const aliasPrefix = alias + '/'; // e.g., "@/"
if (importPath.startsWith(aliasPrefix)) {
debug_logger_1.logger.trace(`Found matching alias prefix: ${alias} => ${targets.join(' or ')}`);
// Try the first target path defined for the alias
// TODO: Handle multiple targets? For now, use the first.
if (targets.length > 0) {
const target = targets[0];
// target can be absolute (tsconfig) or relative (custom config)
const resolvedBaseDir = path.isAbsolute(target)
? target
: path.resolve(this.projectRoot, target);
// Get the part of the import path *after* the alias prefix
const remainingPath = importPath.substring(aliasPrefix.length);
// Construct the potential absolute path *without* extension checking
const potentialPath = path.join(resolvedBaseDir, remainingPath);
debug_logger_1.logger.trace(`Alias resolved to potential base path: ${potentialPath}`);
// Return the potential path. The caller (FileParser) will handle existence checks,
// index files, and extension appending based on context.
return potentialPath;
}
else {
debug_logger_1.logger.warn(`Alias '${alias}' found but has no target paths defined.`);
}
// If we found a matching alias but couldn't resolve (e.g., no targets),
// stop checking other aliases for this import path.
return null;
}
// Handle aliases without a trailing slash (e.g., alias maps directly to a file/dir)
else if (importPath === alias) {
debug_logger_1.logger.trace(`Found matching alias (exact match): ${alias} => ${targets.join(' or ')}`);
if (targets.length > 0) {
const target = targets[0];
const potentialPath = path.isAbsolute(target)
? target
: path.resolve(this.projectRoot, target);
debug_logger_1.logger.trace(`Alias resolved to potential base path: ${potentialPath}`);
return potentialPath;
}
else {
debug_logger_1.logger.warn(`Alias '${alias}' found but has no target paths defined.`);
}
return null;
}
}
debug_logger_1.logger.trace(`No matching alias prefix found for ${importPath}`);
return null; // No alias matched
}
/**
* 从tsconfig.json加载路径别名
* @returns 是否成功加载到别名配置
*/
loadFromTsConfig() {
// 首先尝试在项目根目录查找
let tsconfigPath = path.join(this.projectRoot, 'tsconfig.json');
// 如果根目录没有,可能在上级目录
if (!fs.existsSync(tsconfigPath)) {
// 尝试向上查找,最多向上3级
let currentDir = this.projectRoot;
let found = false;
for (let i = 0; i < 3; i++) {
currentDir = path.dirname(currentDir);
const testPath = path.join(currentDir, 'tsconfig.json');
if (fs.existsSync(testPath)) {
tsconfigPath = testPath;
found = true;
break;
}
}
if (!found) {
return false;
}
}
try {
debug_logger_1.logger.debug(`尝试从${tsconfigPath}加载别名配置`);
const tsconfig = JSON.parse(fs.readFileSync(tsconfigPath, 'utf-8'));
if (tsconfig.compilerOptions && tsconfig.compilerOptions.paths) {
// 获取tsconfig所在目录,因为paths是相对于tsconfig的baseUrl
const tsconfigDir = path.dirname(tsconfigPath);
const baseUrl = tsconfig.compilerOptions.baseUrl || '.';
const baseDir = path.resolve(tsconfigDir, baseUrl);
debug_logger_1.logger.debug(`tsconfig.json的baseUrl: ${baseUrl}, 解析为: ${baseDir}`);
for (const [alias, targets] of Object.entries(tsconfig.compilerOptions.paths)) {
// 处理 paths 中的通配符模式 (如 "@/*" => ["src/*"])
const normalizedAlias = alias.replace(/\/\*$/, ''); // e.g., '@'
this.aliases[normalizedAlias] = targets.map((target) => {
const targetPath = target.replace(/\/\*$/, ''); // e.g., 'src'
// 总是解析为绝对路径
const absoluteTargetPath = path.resolve(baseDir, targetPath);
debug_logger_1.logger.verbose(`Mapping alias '${normalizedAlias}' target '${target}' -> '${absoluteTargetPath}'`);
return absoluteTargetPath;
});
}
debug_logger_1.logger.debug('从tsconfig.json加载的别名:', this.aliases);
return Object.keys(this.aliases).length > 0;
}
}
catch (error) {
debug_logger_1.logger.warn(`无法解析 tsconfig.json: ${error.message}`);
}
return false;
}
/**
* 从自定义配置文件加载路径别名
* @returns 是否成功加载到别名配置
*/
loadFromCustomConfig() {
// 尝试从mp-lens.config.json加载配置
const configPath = path.join(this.projectRoot, 'mp-lens.config.json');
if (!fs.existsSync(configPath)) {
return false;
}
try {
const config = JSON.parse(fs.readFileSync(configPath, 'utf-8'));
if (config.aliases && typeof config.aliases === 'object') {
const initialAliasCount = Object.keys(this.aliases).length;
for (const [alias, targets] of Object.entries(config.aliases)) {
this.aliases[alias] = Array.isArray(targets) ? targets : [targets];
}
// 检查是否添加了新的别名
return Object.keys(this.aliases).length > initialAliasCount;
}
}
catch (error) {
debug_logger_1.logger.warn(`Failed to parse mp-lens.config.json: ${error.message}`);
}
return false;
}
/**
* 获取所有配置的别名
*/
getAliases() {
if (!this.initialized) {
this.initialize();
}
return this.aliases;
}
}
exports.AliasResolver = AliasResolver;
//# sourceMappingURL=alias-resolver.js.map