@hadss/hmrouter-plugin
Version:
HMRouter Compiler Plugin
301 lines (300 loc) • 13.9 kB
JavaScript
"use strict";
var __importDefault = (this && this.__importDefault) || function (mod) {
return (mod && mod.__esModule) ? mod : { "default": mod };
};
Object.defineProperty(exports, "__esModule", { value: true });
exports.ConstantResolver = void 0;
const ts_morph_1 = require("ts-morph");
const framework_1 = require("../../../framework");
const constants_1 = require("../../constants");
const ImportAnalyzer_1 = require("./ImportAnalyzer");
const PluginError_1 = require("../../error/PluginError");
const path_1 = __importDefault(require("path"));
class ConstantResolver {
constructor() {
this.importMapCache = new Map();
this.importMapCacheFilePath = [];
}
setContext(context) {
this.context = context;
}
resolveConstant(value, sourceFile, filePath) {
if (value.type === 'constant') {
return this.parseConstantValue(framework_1.TsAstUtil.getSourceFile(value.variableFilePath), value.variableName);
}
else if (value.type === 'object') {
return this.parseConstantValue(framework_1.TsAstUtil.getSourceFile(value.variableFilePath), value.variableName, value.propertyName);
}
else if (value.type === 'array') {
return value.value.map((item) => {
return this.resolveConstant(item, sourceFile, filePath);
});
}
else {
return value;
}
}
resolvePropertyValue(value, sourceFile, filePath) {
switch (value.getKind()) {
case ts_morph_1.SyntaxKind.Identifier:
if (value.getText() === 'undefined') {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.INVALID_STRING_VALUE, '', filePath);
}
return {
type: 'constant',
variableName: value.getText(),
variableFilePath: this.getVariableFilePath(value.getText(), sourceFile, filePath),
};
case ts_morph_1.SyntaxKind.PropertyAccessExpression:
return {
type: 'object',
variableName: value.getExpression().getText(),
propertyName: value?.getName(),
variableFilePath: this.getVariableFilePath(value?.getExpression().getText(), sourceFile, filePath),
};
case ts_morph_1.SyntaxKind.ArrayLiteralExpression:
return {
type: 'array',
value: value
.asKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression)
?.getElements()
.map((item) => this.resolvePropertyValue(item, sourceFile, filePath)),
};
default:
return this.parsePrimitiveValue(value);
}
}
getVariableFilePath(variableName, sourceFile, filePath) {
let resultPath = '';
const classesNames = sourceFile.getClasses().map((classes) => classes.getName());
const variableNames = sourceFile
.getVariableDeclarations()
.map((variableDeclaration) => variableDeclaration.getName());
if (classesNames.includes(variableName) || variableNames.includes(variableName)) {
return filePath;
}
let importMap;
if (this.importMapCache.has(filePath)) {
importMap = this.importMapCache.get(filePath);
}
else {
importMap = ImportAnalyzer_1.ImportAnalyzer.analyzeImports(sourceFile);
this.importMapCache.set(filePath, importMap);
}
for (const [importPath, importNames] of importMap.entries()) {
if (importNames.includes(variableName)) {
const currentDir = framework_1.PluginFileUtil.pathResolve(filePath, constants_1.FilePathConstants.PARENT_DELIMITER);
const tempFilePath = framework_1.PluginFileUtil.pathResolve(currentDir, importPath + constants_1.FilePathConstants.ETS_SUFFIX);
if (framework_1.PluginFileUtil.exist(tempFilePath)) {
resultPath = tempFilePath;
break;
}
}
}
if (!resultPath) {
for (const [importPath, importNames] of importMap.entries()) {
if (importNames.includes(variableName)) {
resultPath = this.getOtherModuleVariableFilePath(importPath, variableName);
break;
}
}
}
return resultPath;
}
getOtherModuleVariableFilePath(moduleName, variableName) {
const dependencies = this.context?.moduleContext.getOhpmDependencyInfo() || {};
for (const [dependencyName, dependencyInfo] of Object.entries(dependencies)) {
if (moduleName.indexOf(dependencyName) === 0) {
const cacheImport = this.importMapCacheFilePath.find((f) => f.dependencyName === dependencyName &&
f.importConstantName === variableName && f.importPath === moduleName);
if (cacheImport) {
return cacheImport.importFullPath;
}
const isFullPathImport = dependencyName !== moduleName;
let dependencyFilePath = '';
if (isFullPathImport) {
dependencyFilePath = dependencyInfo.packagePath + moduleName.replace(dependencyName, '') + constants_1.FilePathConstants.ETS_SUFFIX;
}
else {
const dependPackageFileName = framework_1.PluginFileUtil.readJson5(framework_1.PluginFileUtil.pathResolve(dependencyInfo.packagePath, constants_1.FilePathConstants.OH_PACKAGE_FILE_NAME));
dependencyFilePath = framework_1.PluginFileUtil.pathResolve(dependencyInfo.packagePath, dependPackageFileName.main || 'Index.ets');
}
const path = this.findExportInFile(dependencyFilePath, variableName);
if (path) {
this.importMapCacheFilePath.push({
dependencyName: dependencyName,
importPath: moduleName,
importConstantName: variableName,
importFullPath: path
});
return path;
}
}
}
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.UNKNOWN_VARIABLE, '', variableName);
}
findExportInFile(filePath, variableName) {
if (!this.isFileExists(filePath)) {
return undefined;
}
const sourceFile = framework_1.TsAstUtil.getSourceFile(filePath);
const localDefinitionPath = this.findLocalDefinition(sourceFile, filePath, variableName);
if (localDefinitionPath) {
return localDefinitionPath;
}
const reExportedPath = this.findReExportedDeclaration(sourceFile, filePath, variableName);
if (reExportedPath) {
return reExportedPath;
}
const namedExportPath = this.findNamedExport(sourceFile, filePath, variableName);
if (namedExportPath) {
return namedExportPath;
}
return undefined;
}
isFileExists(filePath) {
if (!framework_1.PluginFileUtil.exist(filePath)) {
const alternativePath = filePath.replace(constants_1.FilePathConstants.ETS_SUFFIX, constants_1.FilePathConstants.D_ETS_SUFFIX);
return framework_1.PluginFileUtil.exist(alternativePath);
}
return true;
}
findLocalDefinition(sourceFile, filePath, variableName) {
const localDefinitions = [
...sourceFile.getVariableDeclarations(),
...sourceFile.getClasses(),
...sourceFile.getInterfaces(),
].filter(node => node.getName() === variableName);
if (localDefinitions.length > 0) {
framework_1.Logger.debug('', `Object "${variableName}" is defined locally in file: ${filePath}`);
return filePath;
}
return undefined;
}
findReExportedDeclaration(sourceFile, filePath, variableName) {
const exportDeclarations = sourceFile.getExportDeclarations();
for (const exportDecl of exportDeclarations) {
const moduleSpecifier = exportDecl.getModuleSpecifierValue();
if (!moduleSpecifier) {
continue;
}
if (!this.shouldCheckReExport(exportDecl, variableName)) {
continue;
}
const originalDefinitionPath = this.findReExport(moduleSpecifier, filePath, variableName);
if (originalDefinitionPath) {
return originalDefinitionPath;
}
}
for (const exportDecl of exportDeclarations) {
const moduleSpecifier = exportDecl.getModuleSpecifierValue();
if (!moduleSpecifier) {
continue;
}
if (!exportDecl.isNamespaceExport()) {
continue;
}
const originalDefinitionPath = this.findReExport(moduleSpecifier, filePath, variableName);
if (originalDefinitionPath) {
return originalDefinitionPath;
}
}
return undefined;
}
findReExport(moduleSpecifier, filePath, variableName) {
const resolvedPath = framework_1.PluginFileUtil.pathResolve(path_1.default.dirname(filePath), moduleSpecifier + constants_1.FilePathConstants.ETS_SUFFIX);
const originalDefinitionPath = this.findExportInFile(resolvedPath, variableName);
if (originalDefinitionPath) {
framework_1.Logger.debug('', `Object "${variableName}" is re-exported from: ${resolvedPath}`);
return originalDefinitionPath;
}
return undefined;
}
shouldCheckReExport(exportDecl, variableName) {
const namedExports = exportDecl.getNamedExports();
if (namedExports.some(specifier => specifier.getAliasNode()?.getText() === variableName || specifier.getName() === variableName)) {
return true;
}
return false;
}
findNamedExport(sourceFile, filePath, variableName) {
const exportSpecifiers = sourceFile.getExportedDeclarations().get(variableName);
if (!exportSpecifiers || exportSpecifiers.length === 0) {
return undefined;
}
const exportSpecifier = exportSpecifiers[0];
const symbol = exportSpecifier.getSymbol();
if (!symbol) {
return undefined;
}
const definitions = symbol.getDeclarations();
for (const definition of definitions) {
const definitionFilePath = definition.getSourceFile().getFilePath();
if (definitionFilePath !== filePath) {
framework_1.Logger.debug('', `Object "${variableName}" is exported from: ${definitionFilePath}`);
return definitionFilePath;
}
}
return undefined;
}
parsePrimitiveValue(value) {
let propertyValue;
switch (value.getKind()) {
case ts_morph_1.SyntaxKind.StringLiteral:
propertyValue = value.asKind(ts_morph_1.SyntaxKind.StringLiteral)?.getLiteralValue();
break;
case ts_morph_1.SyntaxKind.NumericLiteral:
propertyValue = value.asKind(ts_morph_1.SyntaxKind.NumericLiteral)?.getLiteralValue();
break;
case ts_morph_1.SyntaxKind.TrueKeyword:
propertyValue = true;
break;
case ts_morph_1.SyntaxKind.FalseKeyword:
propertyValue = false;
break;
case ts_morph_1.SyntaxKind.ArrayLiteralExpression:
propertyValue = value
.asKind(ts_morph_1.SyntaxKind.ArrayLiteralExpression)
?.getElements()
.map((item) => item.asKind(ts_morph_1.SyntaxKind.StringLiteral)?.getLiteralValue());
break;
}
return propertyValue;
}
parseConstantValue(sourceFile, variableName, propertyName) {
let result;
if (propertyName) {
let classInstance = sourceFile.getClasses().find((classes) => {
return classes.getName() === variableName;
});
if (!classInstance) {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.UNKNOWN_CLASS, '', variableName);
}
let property = classInstance.getProperties().find((properties) => {
return properties.getName() === propertyName;
});
if (!property) {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.UNKNOWN_PROPERTY, '', propertyName);
}
result = property.getInitializer();
}
else {
let constant = sourceFile.getVariableDeclarations().find((declaration) => {
return declaration.getName() === variableName;
});
if (!constant) {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.UNKNOWN_CONSTANT, '', variableName);
}
result = constant.getInitializer();
}
if (result.getKind() !== ts_morph_1.SyntaxKind.StringLiteral) {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.INVALID_STRING_VALUE, '', variableName);
}
const resultValue = result.asKind(ts_morph_1.SyntaxKind.StringLiteral)?.getLiteralValue();
if (!resultValue) {
throw PluginError_1.PluginError.create(PluginError_1.ErrorCode.NOT_EMPTY_STRING, '', variableName);
}
return resultValue;
}
}
exports.ConstantResolver = ConstantResolver;