@compodoc/compodoc
Version:
The missing documentation tool for your Angular application
483 lines (447 loc) • 19.8 kB
text/typescript
import * as path from 'path';
import { Project, ts, PropertyDeclaration, SyntaxKind, VariableDeclaration } from 'ts-morph';
import FileEngine from '../app/engines/file.engine';
const ast = new Project();
export class ImportsUtil {
private static instance: ImportsUtil;
private constructor() {}
public static getInstance() {
if (!ImportsUtil.instance) {
ImportsUtil.instance = new ImportsUtil();
}
return ImportsUtil.instance;
}
/**
* Find for a sourceFile a variable value in a local enum
* @param srcFile
* @param variableName
* @param variableValue
*/
private findInEnums(srcFile, variableName: string, variableValue: string) {
let res = '';
srcFile.getEnum(e => {
if (e.getName() === variableName) {
e.getMember(m => {
if (m.getName() === variableValue) {
res = m.getValue();
}
});
}
});
return res;
}
/**
* Find for a sourceFile a variable value in a local static class
* @param srcFile
* @param variableName
* @param variableValue
*/
private findInClasses(srcFile, variableName: string, variableValue: string) {
let res = '';
srcFile.getClass(c => {
let staticProperty: PropertyDeclaration = c.getStaticProperty(variableValue);
if (staticProperty) {
if (staticProperty.getInitializer()) {
res = staticProperty.getInitializer().getText();
}
}
});
return res;
}
/**
* Find a value in a local variable declaration like an object
* @param variableDeclaration
* @param variablesAttributes
*/
private findInObjectVariableDeclaration(variableDeclaration, variablesAttributes) {
let variableKind = variableDeclaration.getKind();
if (variableKind && variableKind === SyntaxKind.VariableDeclaration) {
let initializer = variableDeclaration.getInitializer();
if (initializer) {
let initializerKind = initializer.getKind();
if (initializerKind && initializerKind === SyntaxKind.ObjectLiteralExpression) {
let compilerNode = initializer.compilerNode as ts.ObjectLiteralExpression,
finalValue = '';
// Find thestring from AVAR.BVAR.thestring inside properties
let depth = 0;
let loopProperties = properties => {
properties.forEach(prop => {
if (prop.name) {
if (variablesAttributes[depth + 1]) {
if (prop.name.getText() === variablesAttributes[depth + 1]) {
if (prop.initializer) {
if (prop.initializer.properties) {
depth += 1;
loopProperties(prop.initializer.properties);
} else {
finalValue = prop.initializer.text;
}
} else {
finalValue = prop.initializer.text;
}
}
}
}
});
};
loopProperties(compilerNode.properties);
return finalValue;
}
}
}
}
/**
* Find in imports something like myvar
* @param {string} inputVariableName like myvar
* @return {[type]} myvar value
*/
public findValueInImportOrLocalVariables(
inputVariableName: string,
sourceFile: ts.SourceFile,
decoratorType?: string
) {
let metadataVariableName = inputVariableName,
searchedImport,
aliasOriginalName = '',
foundWithNamedImport = false,
foundWithDefaultImport = false,
foundWithAlias = false;
const file =
typeof ast.getSourceFile(sourceFile.fileName) !== 'undefined'
? ast.getSourceFile(sourceFile.fileName)
: ast.addSourceFileAtPathIfExists(sourceFile.fileName); // tslint:disable-line
const imports = file.getImportDeclarations();
/**
* Loop through all imports, and find one matching inputVariableName
*/
imports.forEach(i => {
let namedImports = i.getNamedImports(),
namedImportsLength = namedImports.length,
j = 0;
if (namedImportsLength > 0) {
for (j; j < namedImportsLength; j++) {
let importName = namedImports[j].getNameNode().getText() as string,
importAlias;
if (namedImports[j].getAliasNode()) {
importAlias = namedImports[j].getAliasNode().getText();
}
if (importName === metadataVariableName) {
foundWithNamedImport = true;
searchedImport = i;
break;
}
if (importAlias === metadataVariableName) {
foundWithNamedImport = true;
foundWithAlias = true;
aliasOriginalName = importName;
searchedImport = i;
break;
}
}
}
const namespaceImport = i.getNamespaceImport();
if (namespaceImport) {
const namespaceImportLocalName = namespaceImport.getText();
if (namespaceImportLocalName === metadataVariableName) {
searchedImport = i;
}
}
if (!foundWithNamedImport) {
const defaultImport = i.getDefaultImport();
if (defaultImport) {
const defaultImportText = defaultImport.getText();
if (defaultImportText === metadataVariableName) {
foundWithDefaultImport = true;
searchedImport = i;
}
}
}
});
function hasFoundValues(variableDeclaration) {
let variableKind = variableDeclaration.getKind();
if (variableKind && variableKind === SyntaxKind.VariableDeclaration) {
let initializer = variableDeclaration.getInitializer();
if (initializer) {
let initializerKind = initializer.getKind();
if (initializerKind && initializerKind === SyntaxKind.ObjectLiteralExpression) {
let compilerNode = initializer.compilerNode as ts.ObjectLiteralExpression;
return compilerNode.properties;
}
}
}
}
if (typeof searchedImport !== 'undefined') {
let importPathReference = searchedImport.getModuleSpecifierSourceFile();
let importPath;
if (typeof importPathReference !== 'undefined') {
importPath = importPathReference.compilerNode.fileName;
const sourceFileImport =
typeof ast.getSourceFile(importPath) !== 'undefined'
? ast.getSourceFile(importPath)
: ast.addSourceFileAtPathIfExists(importPath); // tslint:disable-line
if (sourceFileImport) {
let variableName = foundWithAlias ? aliasOriginalName : metadataVariableName;
let variableDeclaration = sourceFileImport.getVariableDeclaration(variableName);
if (variableDeclaration) {
return hasFoundValues(variableDeclaration);
} else {
// Try with exports
const exportDeclarations = sourceFileImport.getExportedDeclarations();
if (exportDeclarations && exportDeclarations.size > 0) {
for (const [
exportDeclarationKey,
exportDeclarationValues
] of exportDeclarations) {
exportDeclarationValues.forEach(exportDeclarationValue => {
if (
exportDeclarationValue instanceof VariableDeclaration &&
exportDeclarationValue.getName() === variableName
) {
return hasFoundValues(exportDeclarationValue);
}
});
}
}
}
}
}
if (
!importPathReference &&
decoratorType === 'template' &&
searchedImport.getModuleSpecifierValue().indexOf('.html') !== -1
) {
const originalSourceFilePath = sourceFile.path;
const originalSourceFilePathFolder = originalSourceFilePath.substring(
0,
originalSourceFilePath.lastIndexOf('/')
);
const finalImportedPath =
originalSourceFilePathFolder + '/' + searchedImport.getModuleSpecifierValue();
const finalImportedPathData = FileEngine.getSync(finalImportedPath);
return finalImportedPathData;
}
} else {
// Find in local variables of the file
const variableDeclaration = file.getVariableDeclaration(metadataVariableName);
if (variableDeclaration) {
let variableKind = variableDeclaration.getKind();
if (variableKind && variableKind === SyntaxKind.VariableDeclaration) {
let initializer = variableDeclaration.getInitializer();
if (initializer) {
let initializerKind = initializer.getKind();
if (
initializerKind &&
initializerKind === SyntaxKind.ObjectLiteralExpression
) {
let compilerNode =
initializer.compilerNode as ts.ObjectLiteralExpression;
return compilerNode.properties;
} else if (
initializerKind &&
(initializerKind === SyntaxKind.StringLiteral ||
initializerKind === SyntaxKind.NoSubstitutionTemplateLiteral)
) {
if (decoratorType === 'template') {
return initializer.getText();
} else {
return variableDeclaration.compilerNode;
}
} else if (initializerKind) {
return variableDeclaration.compilerNode;
}
}
}
}
}
return [];
}
public getFileNameOfImport(variableName: string, sourceFile: ts.SourceFile) {
const file =
typeof ast.getSourceFile(sourceFile.fileName) !== 'undefined'
? ast.getSourceFile(sourceFile.fileName)
: ast.addSourceFileAtPath(sourceFile.fileName); // tslint:disable-line
const imports = file.getImportDeclarations();
let searchedImport,
aliasOriginalName = '',
finalPath = '',
foundWithAlias = false;
imports.forEach(i => {
let namedImports = i.getNamedImports(),
namedImportsLength = namedImports.length,
j = 0;
if (namedImportsLength > 0) {
for (j; j < namedImportsLength; j++) {
let importName = namedImports[j].getNameNode().getText() as string,
importAlias;
if (namedImports[j].getAliasNode()) {
importAlias = namedImports[j].getAliasNode().getText();
}
if (importName === variableName) {
searchedImport = i;
break;
}
if (importAlias === variableName) {
foundWithAlias = true;
aliasOriginalName = importName;
searchedImport = i;
break;
}
}
}
});
if (typeof searchedImport !== 'undefined') {
let importPath = path.resolve(
path.dirname(sourceFile.fileName) +
'/' +
searchedImport.getModuleSpecifierValue() +
'.ts'
);
let cleaner = (process.cwd() + path.sep).replace(/\\/g, '/');
finalPath = importPath.replace(cleaner, '');
}
return finalPath;
}
/**
* Find the file path of imported variable
* @param {string} inputVariableName like thestring
* @return {[type]} thestring destination path
*/
public findFilePathOfImportedVariable(inputVariableName, sourceFilePath: string) {
let searchedImport,
finalPath = '',
aliasOriginalName = '',
foundWithAlias = false;
const file =
typeof ast.getSourceFile(sourceFilePath) !== 'undefined'
? ast.getSourceFile(sourceFilePath)
: ast.addSourceFileAtPath(sourceFilePath); // tslint:disable-line
const imports = file.getImportDeclarations();
/**
* Loop through all imports, and find one matching inputVariableName
*/
imports.forEach(i => {
let namedImports = i.getNamedImports(),
namedImportsLength = namedImports.length,
j = 0;
if (namedImportsLength > 0) {
for (j; j < namedImportsLength; j++) {
let importName = namedImports[j].getNameNode().getText() as string,
importAlias;
if (namedImports[j].getAliasNode()) {
importAlias = namedImports[j].getAliasNode().getText();
}
if (importName === inputVariableName) {
searchedImport = i;
break;
}
if (importAlias === inputVariableName) {
foundWithAlias = true;
aliasOriginalName = importName;
searchedImport = i;
break;
}
}
}
});
if (typeof searchedImport !== 'undefined') {
finalPath = path.resolve(
path.dirname(sourceFilePath) +
'/' +
searchedImport.getModuleSpecifierValue() +
'.ts'
);
}
return finalPath;
}
/**
* Find in imports something like VAR.AVAR.BVAR.thestring
* @param {string} inputVariableName like VAR.AVAR.BVAR.thestring
* @return {[type]} thestring value
*/
public findPropertyValueInImportOrLocalVariables(inputVariableName, sourceFile: ts.SourceFile) {
let variablesAttributes = inputVariableName.split('.'),
metadataVariableName = variablesAttributes[0],
searchedImport,
aliasOriginalName = '',
foundWithAlias = false;
const file =
typeof ast.getSourceFile(sourceFile.fileName) !== 'undefined'
? ast.getSourceFile(sourceFile.fileName)
: ast.addSourceFileAtPath(sourceFile.fileName); // tslint:disable-line
const imports = file.getImportDeclarations();
/**
* Loop through all imports, and find one matching inputVariableName
*/
imports.forEach(i => {
let namedImports = i.getNamedImports(),
namedImportsLength = namedImports.length,
j = 0;
if (namedImportsLength > 0) {
for (j; j < namedImportsLength; j++) {
let importName = namedImports[j].getNameNode().getText() as string,
importAlias;
if (namedImports[j].getAliasNode()) {
importAlias = namedImports[j].getAliasNode().getText();
}
if (importName === metadataVariableName) {
searchedImport = i;
break;
}
if (importAlias === metadataVariableName) {
foundWithAlias = true;
aliasOriginalName = importName;
searchedImport = i;
break;
}
}
}
});
let fileToSearchIn, variableDeclaration;
if (typeof searchedImport !== 'undefined') {
let importPath = path.resolve(
path.dirname(sourceFile.fileName) +
'/' +
searchedImport.getModuleSpecifierValue() +
'.ts'
);
const sourceFileImport =
typeof ast.getSourceFile(importPath) !== 'undefined'
? ast.getSourceFile(importPath)
: ast.addSourceFileAtPath(importPath); // tslint:disable-line
if (sourceFileImport) {
fileToSearchIn = sourceFileImport;
let variableName = foundWithAlias ? aliasOriginalName : metadataVariableName;
variableDeclaration = fileToSearchIn.getVariableDeclaration(variableName);
}
} else {
fileToSearchIn = file;
// Find in local variables of the file
variableDeclaration = fileToSearchIn.getVariableDeclaration(metadataVariableName);
}
if (variableDeclaration) {
return this.findInObjectVariableDeclaration(variableDeclaration, variablesAttributes);
}
// Try find it in enums
if (variablesAttributes.length > 0) {
if (typeof fileToSearchIn !== 'undefined') {
let val = this.findInEnums(
fileToSearchIn,
metadataVariableName,
variablesAttributes[1]
);
if (val !== '') {
return val;
}
val = this.findInClasses(
fileToSearchIn,
metadataVariableName,
variablesAttributes[1]
);
if (val !== '') {
return val;
}
}
}
}
}
export default ImportsUtil.getInstance();