@sourcefield/lsif-typescript
Version:
LSIF indexer for TypeScript and JavaScript
924 lines (841 loc) • 121 kB
text/typescript
import { Console } from 'console';
import * as ts from 'typescript';
import { is } from 'uvu/assert';
import { Complexity } from './Complexity';
import { Counter } from './Counter';
import { DefinitionRange } from './DefinitionRange';
import {
metaDescriptor,
methodDescriptor,
packageDescriptor,
parameterDescriptor,
termDescriptor,
typeDescriptor,
typeParameterDescriptor,
} from './Descriptor';
import { Input } from './Input';
import * as lsif from './lsif';
import { FullRange, Moniker, Position, Range as LsifRange, ResultSet } from './lsif-data/lsif';
import { LsifSymbol } from './LsifSymbol';
import { Packages } from './Packages';
import { ParentChildRelationships } from './ParentChildRelationships';
import { Range } from './Range';
import { keywordStrings, keywordToStringMap, operatorTokenToStringMap } from './ToStringMaps';
type Descriptor = lsif.lib.codeintel.lsiftyped.Descriptor;
export class FileIndexer {
private localCounter = new Counter();
private propertyCounters: Map<string, Counter> = new Map();
private localSymbolTable: Map<ts.Node, LsifSymbol> = new Map();
private parentChildRelationships: ParentChildRelationships[] = Array<ParentChildRelationships>();
// Since a file is a module, we don't want to start randomly in the parentChildRelationships array.
// We want to aggregate parents from the "file"/module-level.
private parentChildRelationshipsModuleLevel: ParentChildRelationships[] = Array<ParentChildRelationships>();
public currentComponentHeirarchy: Complexity[] = new Array<Complexity>();
private currentComponentHeirarchyPositions: number[] = Array<number>();
private indentLevel = 0;
constructor(
public readonly checker: ts.TypeChecker,
public readonly input: Input,
public readonly document: lsif.lib.codeintel.lsiftyped.Document,
public readonly globalSymbolTable: Map<ts.Node, LsifSymbol>,
public readonly packages: Packages,
public readonly sourceFile: ts.SourceFile,
public readonly writeIndex: (index: any) => void,
public readonly lsifCounter: Counter,
public readonly definitions: Map<number, DefinitionRange> = new Map<number, DefinitionRange>(),
public readonly references: Map<number, DefinitionRange[]>,
public readonly languageService: ts.LanguageService,
public readonly dev: boolean,
public readonly underTest: boolean = false
) {}
public index(): void {
this.visit(this.sourceFile);
this.emitDocumentSymbolResults();
}
private indent(): string {
return '\t'.repeat(this.indentLevel);
}
private emitDocumentSymbolResults() {
for (let parentChildRelationshipModuleLevel of this.parentChildRelationshipsModuleLevel) {
if (parentChildRelationshipModuleLevel.children.length == 0) continue;
this.writeIndex(parentChildRelationshipModuleLevel.getEmittable(this.lsifCounter.next()));
}
}
private pushComponentToHeirarchy(id: number, isSourceFile: boolean = false) {
this.indentLevel += 1;
if (!isSourceFile) {
let parentChildRelationship = new ParentChildRelationships(id, this.parentChildRelationships.length == 0);
this.parentChildRelationships.push(parentChildRelationship);
}
this.currentComponentHeirarchy.push(new Complexity(id));
this.currentComponentHeirarchyPositions.push(0);
this.currentComponentHeirarchyPositions = this.currentComponentHeirarchyPositions.map((element) => element - 1);
}
private popComponentFromHeirarchy(node: ts.Node) {
this.indentLevel -= 1;
let finalElementPosition = this.currentComponentHeirarchyPositions.pop();
if (this.underTest) return;
let currentComplexityNode = this.currentComponentHeirarchy.pop();
if (this.dev) console.log('currentComplexityNode', currentComplexityNode);
if (currentComplexityNode) {
this.writeIndex(currentComplexityNode.getEmittable(this.lsifCounter.next()));
}
let child = this.parentChildRelationships.pop();
if (child === undefined) return;
if (this.parentChildRelationships.length == 0) {
this.parentChildRelationshipsModuleLevel.push(child);
return;
}
this.parentChildRelationships[this.parentChildRelationships.length - 1].children.push(child);
this.currentComponentHeirarchyPositions = this.currentComponentHeirarchyPositions.map((element) => element + 1);
}
private visit(node: ts.Node): void {
if (this.dev) console.log(`${this.indent()}• visit [${node.pos}:${node.end}]`);
if (!this.continueWalk(node)) return;
if (this.dev) console.log('visit...');
ts.forEachChild(node, (node) => {
if (this.dev) console.log(`${this.indent()}• visit.child [${node.pos}:${node.end}]`);
this.visit(node);
});
}
private continueWalk(node: ts.Node): boolean {
if (this.dev) console.log('continueWalk', node.kind);
if (ts.isSourceFile(node)) return this.visitSourceFile(node);
if (ts.isImportDeclaration(node)) return this.visitImportDeclaration(node);
if (ts.isNamedImports(node)) return this.visitNamedImports(node);
if (ts.isNamespaceImport(node)) return this.visitNamespaceImport(node);
if (ts.isAsteriskToken(node)) return this.visitAsteriskToken(node);
if (keywordToStringMap.has(node.kind)) return this.visitKeyword(node.kind);
if (operatorTokenToStringMap.has(node.kind)) return this.visitOperator(node.kind);
if (ts.isNumericLiteral(node) || ts.isBigIntLiteral(node)) return this.visitNumericLiteral(node);
if (ts.isStringLiteral(node)) return this.visitStringLiteral(node);
if (ts.isBlock(node)) return this.visitBlock(node);
if (ts.isClassStaticBlockDeclaration(node)) return this.visitClassStaticBlockDeclaration(node);
if (ts.isParameter(node)) return this.visitParameter(node);
if (ts.isCallExpression(node)) return this.visitCallExpression(node);
if (ts.isIdentifier(node)) return this.visitIdentifier(node);
if (ts.isBinaryExpression(node)) return this.visitBinaryExpression(node);
if (ts.isIfStatement(node)) return this.visitIfStatement(node);
if (node.kind === ts.SyntaxKind.SyntaxList) return this.visitSyntaxList(<ts.SyntaxList>(<unknown>node));
if (ts.isExpressionStatement(node)) return this.visitExpressionStatement(node);
if (ts.isClassDeclaration(node)) return this.visitClassDeclaration(node);
if (ts.isMethodDeclaration(node)) return this.visitMethodDeclaration(node);
if (ts.isFunctionDeclaration(node)) return this.visitFunctionDeclaration(node);
if (ts.isFunctionExpression(node)) return this.visitFunctionExpression(node);
if (ts.isPropertyDeclaration(node)) return this.visitPropertyDeclaration(node);
if (ts.isArrayTypeNode(node)) return this.visitArrayTypeNode(node);
if (ts.isReturnStatement(node)) return this.visitReturnStatement(node);
if (ts.isPropertyAccessExpression(node)) return this.visitPropertyAccessExpression(node);
if (ts.isTypeReferenceNode(node)) return this.visitTypeReferenceNode(node);
if (ts.isVariableStatement(node)) return this.visitVariableStatement(node);
if (ts.isVariableDeclarationList(node)) return this.visitVariableDeclarationList(node);
if (ts.isVariableDeclaration(node)) return this.visitVariableDeclaration(node);
if (ts.isArrowFunction(node)) return this.visitArrowFunction(node);
if (ts.isConstructorDeclaration(node)) return this.visitConstructorDeclaration(node);
if (ts.isInterfaceDeclaration(node)) return this.visitInterfaceDeclaration(node);
if (ts.isMethodSignature(node)) return this.visitMethodSignature(node);
if (ts.isTypeParameterDeclaration(node)) return this.visitTypeParameterDeclaration(node);
if (ts.isHeritageClause(node)) return this.visitHeritageClause(node);
if (ts.isExpressionWithTypeArguments(node)) return this.visitExpressionWithTypeArguments(node);
if (ts.isNewExpression(node)) return this.visitNewExpression(node);
if (ts.isTypeAliasDeclaration(node)) return this.visitTypeAliasDeclaration(node);
if (ts.isTypeLiteralNode(node)) return this.visitTypeLiteralNode(node);
if (ts.isPropertySignature(node)) return this.visitPropertySignature(node);
if (ts.isComputedPropertyName(node)) return this.visitComputedPropertyName(node);
if (ts.isExportAssignment(node)) return this.visitExportAssignment(node);
if (ts.isModuleDeclaration(node)) return this.visitModuleDeclaration(node);
if (ts.isModuleBlock(node)) return this.visitModuleBlock(node);
if (ts.isSetAccessorDeclaration(node)) return this.visitSetAccesssorDeclaration(node);
if (ts.isGetAccessorDeclaration(node)) return this.visitGetAccessorDeclaration(node);
if (ts.isSetAccessor(node)) return this.visitSetAccesssor(node);
if (ts.isConstructSignatureDeclaration(node)) return this.visitConstructSignatureDeclaration(node);
if (ts.isFunctionTypeNode(node)) return this.visitFunctionTypeNode(node);
if (ts.isForStatement(node)) return this.visitForStatement(node);
if (ts.isExportDeclaration(node)) return this.visitExportDeclaration(node);
if (ts.isPrefixUnaryExpression(node)) return this.visitPrefixUnaryExpression(node);
if (ts.isBreakStatement(node)) return this.visitBreakStatement(node);
if (ts.isContinueStatement(node)) return this.visitContinueStatement(node);
if (ts.isParenthesizedExpression(node)) return this.visitParenthesizedExpression(node);
if (ts.isUnionTypeNode(node)) return this.visitUnionTypeNode(node);
if (ts.isTypeQueryNode(node)) return this.visitTypeQueryNode(node);
if (ts.isArrayLiteralExpression(node)) return this.visitArrayLiteralExpression(node);
if (ts.isObjectBindingPattern(node)) return this.visitObjectBindingPattern(node);
if (ts.isBindingElement(node)) return this.visitBindingElement(node);
if (ts.isObjectLiteralExpression(node)) return this.visitObjectLiteralExpression(node);
if (ts.isShorthandPropertyAssignment(node)) return this.visitShorthandPropertyAssignment(node);
if (ts.isPropertyAssignment(node)) return this.visitPropertyAssignment(node);
if (ts.isImportEqualsDeclaration(node)) return this.visitImportEqualsDeclaration(node);
if (ts.isQualifiedName(node)) return this.visitQualifiedName(node);
if (ts.isPrivateIdentifier(node)) return this.visitPrivateIdentifier(node);
if (ts.isCallSignatureDeclaration(node)) return this.visitCallSignatureDeclaration(node);
if (ts.isAwaitExpression(node)) return this.visitAwaitExpression(node);
if (ts.isPostfixUnaryExpression(node)) return this.visitPostfixUnaryExpression(node);
if (ts.isJsxText(node)) return this.visitJsxText(node);
if (ts.isRegularExpressionLiteral(node)) return this.visitRegularExpressionLiteral(node);
if (ts.isNoSubstitutionTemplateLiteral(node)) return this.visitNoSubstitutionTemplateLiteral(node);
if (ts.isTemplateHead(node)) return this.visitTemplateHead(node);
if (ts.isTemplateMiddle(node)) return this.visitTemplateMiddle(node);
if (ts.isTemplateTail(node)) return this.visitTemplateTail(node);
if (ts.isDotDotDotToken(node)) return this.visitDotDotDotToken(node);
if (ts.isPlusToken(node)) return this.visitPlusToken(node);
if (ts.isMinusToken(node)) return this.visitMinusToken(node);
if (ts.isDecorator(node)) return this.visitDecorator(node);
if (ts.isIndexSignatureDeclaration(node)) return this.visitIndexSignatureDeclaration(node);
if (ts.isTypePredicateNode(node)) return this.visitTypePredicateNode(node);
if (ts.isConstructorTypeNode(node)) return this.visitConstructorTypeNode(node);
if (ts.isTupleTypeNode(node)) return this.visitTupleTypeNode(node);
if (ts.isOptionalTypeNode(node)) return this.visitOptionalTypeNode(node);
if (ts.isRestTypeNode(node)) return this.visitRestTypeNode(node);
if (ts.isIntersectionTypeNode(node)) return this.visitIntersectionTypeNode(node);
if (ts.isConditionalTypeNode(node)) return this.visitConditionalTypeNode(node);
if (ts.isInferTypeNode(node)) return this.visitInferTypeNode(node);
if (ts.isParenthesizedTypeNode(node)) return this.visitParenthesizedTypeNode(node);
if (ts.isThisTypeNode(node)) return this.visitThisTypeNode(node);
if (ts.isTypeOperatorNode(node)) return this.visitTypeOperatorNode(node);
if (ts.isIndexedAccessTypeNode(node)) return this.visitIndexedAccessTypeNode(node);
if (ts.isMappedTypeNode(node)) return this.visitMappedTypeNode(node);
if (ts.isLiteralTypeNode(node)) return this.visitLiteralTypeNode(node);
if (ts.isImportTypeNode(node)) return this.visitImportTypeNode(node);
if (ts.isTemplateLiteralTypeSpan(node)) return this.visitTemplateLiteralTypeSpan(node);
if (ts.isTemplateLiteralTypeNode(node)) return this.visitTemplateLiteralTypeNode(node);
if (ts.isArrayBindingPattern(node)) return this.visitArrayBindingPattern(node);
if (ts.isElementAccessExpression(node)) return this.visitElementAccessExpression(node);
if (ts.isTaggedTemplateExpression(node)) return this.visitTaggedTemplateExpression(node);
if (ts.isTypeAssertionExpression(node)) return this.visitTypeAssertionExpression(node);
if (ts.isDeleteExpression(node)) return this.visitDeleteExpression(node);
if (ts.isTypeOfExpression(node)) return this.visitTypeOfExpression(node);
if (ts.isVoidExpression(node)) return this.visitVoidExpression(node);
if (ts.isConditionalExpression(node)) return this.visitConditionalExpression(node);
if (ts.isTemplateExpression(node)) return this.visitTemplateExpression(node);
if (ts.isYieldExpression(node)) return this.visitYieldExpression(node);
if (ts.isSpreadElement(node)) return this.visitSpreadElement(node);
if (ts.isClassExpression(node)) return this.visitClassExpression(node);
if (ts.isOmittedExpression(node)) return this.visitOmittedExpression(node);
if (ts.isAsExpression(node)) return this.visitAsExpression(node);
if (ts.isNonNullExpression(node)) return this.visitNonNullExpression(node);
if (ts.isMetaProperty(node)) return this.visitMetaProperty(node);
if (ts.isSyntheticExpression(node)) return this.visitSyntheticExpression(node);
if (ts.isPartiallyEmittedExpression(node)) return this.visitPartiallyEmittedExpression(node);
if (ts.isCommaListExpression(node)) return this.visitCommaListExpression(node);
if (ts.isTemplateSpan(node)) return this.visitTemplateSpan(node);
if (ts.isSemicolonClassElement(node)) return this.visitSemicolonClassElement(node);
if (ts.isEmptyStatement(node)) return this.visitEmptyStatement(node);
if (ts.isDoStatement(node)) return this.visitDoStatement(node);
if (ts.isWhileStatement(node)) return this.visitWhileStatement(node);
if (ts.isForInStatement(node)) return this.visitForInForOfStatement(node, 'in');
if (ts.isForOfStatement(node)) return this.visitForInForOfStatement(node, 'of');
if (ts.isWithStatement(node)) return this.visitWithStatement(node);
if (ts.isSwitchStatement(node)) return this.visitSwitchStatement(node);
if (ts.isLabeledStatement(node)) return this.visitLabeledStatement(node);
if (ts.isThrowStatement(node)) return this.visitThrowStatement(node);
if (ts.isTryStatement(node)) return this.visitTryStatement(node);
if (ts.isDebuggerStatement(node)) return this.visitDebuggerStatement(node);
if (ts.isEnumDeclaration(node)) return this.visitEnumDeclaration(node);
if (ts.isCaseBlock(node)) return this.visitCaseBlock(node);
if (ts.isNamespaceExportDeclaration(node)) return this.visitNamespaceExportDeclaration(node);
if (ts.isImportClause(node)) return this.visitImportClause(node);
if (ts.isImportTypeAssertionContainer(node)) return this.visitImportTypeAssertionContainer(node);
if (ts.isAssertClause(node)) return this.visitAssertClause(node);
if (ts.isAssertEntry(node)) return this.visitAssertEntry(node);
if (ts.isNamespaceExport(node)) return this.visitNamespaceExport(node);
if (ts.isImportSpecifier(node)) return this.visitImportSpecifier(node);
if (ts.isNamedExports(node)) return this.visitNamedExports(node);
if (ts.isExportSpecifier(node)) return this.visitExportSpecifier(node);
if (ts.isMissingDeclaration(node)) return this.visitMissingDeclaration(node);
if (ts.isNotEmittedStatement(node)) return this.visitNotEmittedStatement(node);
if (ts.isExternalModuleReference(node)) return this.visitExternalModuleReference(node);
if (ts.isJsxElement(node)) return this.visitJsxElement(node);
if (ts.isJsxSelfClosingElement(node)) return this.visitJsxSelfClosingElement(node);
if (ts.isJsxOpeningElement(node)) return this.visitJsxOpeningElement(node);
if (ts.isJsxClosingElement(node)) return this.visitJsxClosingElement(node);
if (ts.isJsxFragment(node)) return this.visitJsxFragment(node);
if (ts.isJsxOpeningFragment(node)) return this.visitJsxOpeningFragment(node);
if (ts.isJsxClosingFragment(node)) return this.visitJsxClosingFragment(node);
if (ts.isJsxAttribute(node)) return this.visitJsxAttribute(node);
if (ts.isJsxAttributes(node)) return this.visitJsxAttributes(node);
if (ts.isJsxSpreadAttribute(node)) return this.visitJsxSpreadAttribute(node);
if (ts.isJsxExpression(node)) return this.visitJsxExpression(node);
if (ts.isCaseClause(node)) return this.visitCaseClause(node);
if (ts.isDefaultClause(node)) return this.visitDefaultClause(node);
if (ts.isCatchClause(node)) return this.visitCatchClause(node);
if (ts.isSpreadAssignment(node)) return this.visitSpreadAssignment(node);
if (ts.isEnumMember(node)) return this.visitEnumMember(node);
if (ts.isUnparsedPrepend(node)) return this.visitUnparsedPrepend(node);
if (ts.isBundle(node)) return this.visitBundle(node);
if (ts.isUnparsedSource(node)) return this.visitUnparsedSource(node);
if (ts.isJSDocTypeExpression(node)) return this.visitJSDocTypeExpression(node);
if (ts.isJSDocNameReference(node)) return this.visitJSDocNameReference(node);
if (ts.isJSDocMemberName(node)) return this.visitJSDocMemberName(node);
if (ts.isJSDocLink(node)) return this.visitJSDocLink(node);
if (ts.isJSDocLinkCode(node)) return this.visitJSDocLinkCode(node);
if (ts.isJSDocLinkPlain(node)) return this.visitJSDocLinkPlain(node);
if (ts.isJSDocAllType(node)) return this.visitJSDocAllType(node);
if (ts.isJSDocUnknownType(node)) return this.visitJSDocUnknownType(node);
if (ts.isJSDocNullableType(node)) return this.visitJSDocNullableType(node);
if (ts.isJSDocNonNullableType(node)) return this.visitJSDocNonNullableType(node);
if (ts.isJSDocOptionalType(node)) return this.visitJSDocOptionalType(node);
if (ts.isJSDocFunctionType(node)) return this.visitJSDocFunctionType(node);
if (ts.isJSDocVariadicType(node)) return this.visitJSDocVariadicType(node);
if (ts.isJSDocNamepathType(node)) return this.visitJSDocNamepathType(node);
if (ts.isJSDoc(node)) return this.visitJSDoc(node);
if (ts.isJSDocTypeLiteral(node)) return this.visitJSDocTypeLiteral(node);
if (ts.isJSDocSignature(node)) return this.visitJSDocSignature(node);
if (ts.isJSDocAugmentsTag(node)) return this.visitJSDocAugmentsTag(node);
if (ts.isJSDocAuthorTag(node)) return this.visitJSDocAuthorTag(node);
if (ts.isJSDocClassTag(node)) return this.visitJSDocClassTag(node);
if (ts.isJSDocCallbackTag(node)) return this.visitJSDocCallbackTag(node);
if (ts.isJSDocPublicTag(node)) return this.visitJSDocPublicTag(node);
if (ts.isJSDocPrivateTag(node)) return this.visitJSDocPrivateTag(node);
if (ts.isJSDocProtectedTag(node)) return this.visitJSDocProtectedTag(node);
if (ts.isJSDocReadonlyTag(node)) return this.visitJSDocReadonlyTag(node);
if (ts.isJSDocOverrideTag(node)) return this.visitJSDocOverrideTag(node);
if (ts.isJSDocDeprecatedTag(node)) return this.visitJSDocDeprecatedTag(node);
if (ts.isJSDocSeeTag(node)) return this.visitJSDocSeeTag(node);
if (ts.isJSDocEnumTag(node)) return this.visitJSDocEnumTag(node);
if (ts.isJSDocParameterTag(node)) return this.visitJSDocParameterTag(node);
if (ts.isJSDocReturnTag(node)) return this.visitJSDocReturnTag(node);
if (ts.isJSDocThisTag(node)) return this.visitJSDocThisTag(node);
if (ts.isJSDocTypeTag(node)) return this.visitJSDocTypeTag(node);
if (ts.isJSDocTemplateTag(node)) return this.visitJSDocTemplateTag(node);
if (ts.isJSDocTypedefTag(node)) return this.visitJSDocTypedefTag(node);
if (ts.isJSDocUnknownTag(node)) return this.visitJSDocUnknownTag(node);
if (ts.isJSDocPropertyTag(node)) return this.visitJSDocPropertyTag(node);
if (ts.isJSDocImplementsTag(node)) return this.visitJSDocImplementsTag(node);
return true;
}
private visitSourceFile(node: ts.SourceFile) {
if (this.dev) console.log(`**FILE** -->${node.fileName}`);
if (this.dev) console.log(`${this.indent()}• visitSourceFile [${node.pos}:${node.end}]`);
this.pushComponentToHeirarchy(this.lsifCounter.get());
this.visitBlockStatements(node.statements);
return false;
}
private visitImportDeclaration(node: ts.ImportDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitImportDeclaration [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['import']);
if (node.importClause) {
this.continueWalk(node.importClause);
this.addOperatorsToAllHalstead(['from']);
}
this.continueWalk(node.moduleSpecifier);
if (node.assertClause) {
this.continueWalk(node.assertClause);
}
if (this.dev) console.log(`${this.indent()}• visitImportDeclaration [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitNamespaceImport(node: ts.NamespaceImport): boolean {
if (this.dev) console.log(`${this.indent()}• visitNamespaceImport [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['*', 'as']);
this.continueWalk(node.name);
if (this.dev) console.log(`${this.indent()}• visitNamespaceImport [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitNamedImports(node: ts.NamedImports): boolean {
if (this.dev) console.log(`${this.indent()}• visitNamedImports [${node.pos}:${node.end}]`);
this.visitNodeArray(node.elements);
if (this.dev) console.log(`${this.indent()}• visitNamedImports [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitAsteriskToken(node: ts.AsteriskToken): boolean {
if (this.dev) console.log(`${this.indent()}• visitAsteriskToken [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['*']);
if (this.dev) console.log(`${this.indent()}• visitAsteriskToken [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitKeyword(kind: ts.SyntaxKind): boolean {
if (this.dev) console.log(`${this.indent()}• visitKeyword`);
let keywordString = keywordToStringMap.get(kind);
if (keywordString) {
this.addOperatorsToAllHalstead([keywordString]);
}
if (this.dev) console.log(`${this.indent()}• visitKeyword <<EXIT>>`);
return false;
}
private visitOperator(kind: ts.SyntaxKind): boolean {
if (this.dev) console.log(`${this.indent()}• visitOperator`, kind);
let operatorString = operatorTokenToStringMap.get(kind);
if (operatorString) {
this.addOperatorsToAllHalstead([operatorString]);
}
if (this.dev) console.log(`${this.indent()}• visitOperator <<EXIT>>`);
return false;
}
private visitNumericLiteral(node: ts.NumericLiteral | ts.BigIntLiteral): boolean {
if (this.dev) console.log(`${this.indent()}• visitNumericLiteral [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([node.text]);
if (this.dev) console.log(`${this.indent()}• visitNumericLiteral [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitStringLiteral(node: ts.StringLiteral) {
if (this.dev) console.log(`${this.indent()}• visitStringLiteral [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([`"${node.text}"`]);
if (this.dev) console.log(`${this.indent()}• visitStringLiteral [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitBlock(node: ts.Block): boolean {
if (this.dev) console.log(`${this.indent()}• visitBlock [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['{}']);
node.statements.forEach((child) => {
if (this.dev) console.log(`${this.indent()}• visitBlock [${node.pos}:${node.end}], node.child`, child);
this.continueWalk(child);
});
if (this.dev) console.log(`${this.indent()}• visitBlock [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitClassStaticBlockDeclaration(node: ts.ClassStaticBlockDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitClassStaticBlockDeclaration [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['static']);
this.continueWalk(node.body);
return false;
}
private visitParameter(node: ts.ParameterDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitParameter [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
if (node.dotDotDotToken) {
this.addOperatorsToAllHalstead(['...']);
}
if (node.name) this.continueWalk(node.name);
if (node.questionToken) {
this.addOperatorsToAllHalstead(['?']);
}
if (node.type) {
this.addOperatorsToAllHalstead([':']);
this.continueWalk(node.type);
}
if (node.initializer) {
this.addOperatorsToAllHalstead(['=']);
this.continueWalk(node.initializer);
}
if (this.dev) console.log(`${this.indent()}• visitParameter [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitArrayTypeNode(node: ts.ArrayTypeNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitArrayTypeNode [${node.pos}:${node.end}]`);
this.continueWalk(node.elementType);
this.addOperatorsToAllHalstead(['[]']);
if (this.dev) console.log(`${this.indent()}• visitArrayTypeNode [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitCallExpression(node: ts.CallExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitCallExpression [${node.pos}:${node.end}]`);
this.continueWalk(node.expression);
this.visitNodeArray(node.arguments, '()');
if (this.dev) console.log(`${this.indent()}• visitCallExpression [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitBinaryExpression(node: ts.BinaryExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitBinaryExpression [${node.pos}:${node.end}]`);
this.continueWalk(node.left);
this.continueWalk(node.operatorToken);
this.continueWalk(node.right);
if (this.dev) console.log(`${this.indent()}• visitBinaryExpression [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitIdentifier(node: ts.Identifier) {
if (this.dev) console.log(`${this.indent()}• visitIdentifier [${node.pos}:${node.end}]`);
let identifier = node.escapedText.toString();
if (this.dev) console.log(`${this.indent()}• visitIdentifier [${node.pos}:${node.end}]`, identifier);
if (keywordStrings.indexOf(identifier) > -1) {
this.addOperatorsToAllHalstead([identifier]);
return false;
}
this.addOperandsToAllHalstead([identifier]);
if (this.dev) console.log(`${this.indent()}• visitIdentifier [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitIfStatement(node: ts.IfStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitIfStatement [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['if', '()']);
this.continueWalk(node.expression);
this.continueWalk(node.thenStatement);
if (node.elseStatement) {
this.addOperatorsToAllHalstead(['else']);
this.continueWalk(node.elseStatement);
}
if (this.dev) console.log(`${this.indent()}• visitIfStatement [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitForStatement(node: ts.ForStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitForStatement [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['for', '()']);
if (node.initializer) this.continueWalk(node.initializer);
this.addOperatorsToAllHalstead([';']);
if (node.condition) this.continueWalk(node.condition);
this.addOperatorsToAllHalstead([';']);
if (node.incrementor) this.continueWalk(node.incrementor);
this.continueWalk(node.statement);
if (this.dev) console.log(`${this.indent()}• visitForStatement [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitPrefixUnaryExpression(node: ts.PrefixUnaryExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitPrefixUnaryExpression [${node.pos}:${node.end}]`);
this.visitOperator(node.operator);
this.continueWalk(node.operand);
if (this.dev) console.log(`${this.indent()}• visitPrefixUnaryExpression [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitPostfixUnaryExpression(node: ts.PostfixUnaryExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitPostfixUnaryExpression [${node.pos}:${node.end}]`);
this.continueWalk(node.operand);
this.visitOperator(node.operator);
if (this.dev) console.log(`${this.indent()}• visitPostfixUnaryExpression [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitSyntaxList(node: ts.SyntaxList): boolean {
if (this.dev) console.log(`${this.indent()}• visitSyntaxList [${node.pos}:${node.end}]`);
node.getChildren().forEach((child) => {
this.continueWalk(child);
});
if (this.dev) console.log(`${this.indent()}• visitSyntaxList [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitExpressionStatement(node: ts.ExpressionStatement): boolean {
if (this.dev)
console.log(
`${this.indent()}• visitExpressionStatement [${node.pos}:${node.end}], node.expression`,
node.expression
);
this.continueWalk(node.expression);
if (this.dev) console.log(`${this.indent()}• visitExpressionStatement [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitReturnStatement(node: ts.ReturnStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitReturnStatement [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['return']);
if (node.expression) return this.continueWalk(node.expression);
if (this.dev) console.log(`${this.indent()}• visitReturnStatement [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitPropertyAccessExpression(node: ts.PropertyAccessExpression): boolean {
if (this.dev)
console.log(
`${this.indent()}• visitPropertyAccessExpression - ${node.expression}.${node.name.escapedText} - [${
node.pos
}:${node.end}]`,
node
);
this.continueWalk(node.expression);
if (node.questionDotToken) this.addOperatorsToAllHalstead(['?']);
this.addOperatorsToAllHalstead(['.']);
this.continueWalk(node.name);
if (this.dev) console.log(`${this.indent()}• visitPropertyAccessExpression [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitComputedPropertyName(node: ts.ComputedPropertyName): boolean {
if (this.dev) console.log(`${this.indent()}• visitComputedPropertyName [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['[]']);
this.continueWalk(node.expression);
return false;
}
private visitTypeParameterDeclaration(node: ts.TypeParameterDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitTypeParameterDeclaration [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
if (node.constraint) {
this.addOperatorsToAllHalstead(['[]']);
this.continueWalk(node.name);
this.addOperatorsToAllHalstead(['in']);
this.continueWalk(node.constraint);
return false;
}
if (node.default) {
this.addOperatorsToAllHalstead(['=']);
this.continueWalk(node.default);
}
if (node.expression) throw new Error('************************ URGENT & NEW, node.expression');
this.continueWalk(node.name);
if (this.dev) console.log(`${this.indent()}• visitTypeParameterDeclaration [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitTypeReferenceNode(node: ts.TypeReferenceNode) {
if (this.dev) console.log(`${this.indent()}• visitTypeReferenceNode [${node.pos}:${node.end}]`);
this.continueWalk(node.typeName);
if (node.typeArguments) {
this.addOperatorsToAllHalstead(['<>']);
this.visitNodeArray(node.typeArguments, '', ',', false);
}
if (this.dev) console.log(`${this.indent()}• visitTypeReferenceNode [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitVariableStatement(node: ts.VariableStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitVariableStatement [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
this.continueWalk(node.declarationList);
if (this.dev) console.log(`${this.indent()}• visitVariableStatement [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitVariableDeclarationList(node: ts.VariableDeclarationList): boolean {
if (this.dev) console.log(`${this.indent()}• visitVariableDeclarationList [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
// TODO - investigate https://github.com/source-field/sourcefield-lsif-typescript/pull/1#discussion_r977227847
if (node.flags == ts.NodeFlags.None || node.flags & ts.NodeFlags.None) this.addOperatorsToAllHalstead(['var']);
if (node.flags == ts.NodeFlags.Let || node.flags & ts.NodeFlags.Let) this.addOperatorsToAllHalstead(['let']);
if (node.flags == ts.NodeFlags.Const || node.flags & ts.NodeFlags.Const)
this.addOperatorsToAllHalstead(['const']);
const maxLoop = node.declarations.length - 1;
node.declarations.forEach((declaration, i) => {
if (this.dev)
console.log(`${this.indent()}• visitVariableDeclarationList visiting declaration`, declaration.kind);
this.continueWalk(declaration);
if (i != maxLoop) this.addOperatorsToAllHalstead([',']);
});
if (this.dev) console.log(`${this.indent()}• visitVariableDeclarationList [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitVariableDeclaration(node: ts.VariableDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitVariableDeclaration [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
this.continueWalk(node.name);
if (node.type) {
this.addOperatorsToAllHalstead([':']);
this.continueWalk(node.type);
}
// TODO - find one that has an initializer...unsure of the OOO
if (node.initializer) {
this.addOperatorsToAllHalstead(['=']);
this.continueWalk(node.initializer);
}
if (node.exclamationToken) this.continueWalk(node.exclamationToken);
if (this.dev) console.log(`${this.indent()}• visitVariableDeclaration [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitArrowFunction(node: ts.ArrowFunction): boolean {
if (this.dev) console.log(`${this.indent()}• visitArrowFunction [${node.pos}:${node.end}]`, node);
this.visitNodeArray(node.parameters, '()', ','); // TODO - solve why some arrow functions have this and others do not
if (node.equalsGreaterThanToken.pos != node.equalsGreaterThanToken.end) this.addOperatorsToAllHalstead(['=>']);
this.continueWalk(node.body);
if (this.dev) console.log(`${this.indent()}• visitArrowFunction [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitAwaitExpression(node: ts.AwaitExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitAwaitExpression [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['await']);
this.continueWalk(node.expression);
return false;
}
private visitHeritageClause(node: ts.HeritageClause): boolean {
if (this.dev) console.log(`${this.indent()}• visitHeritageClause [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
this.visitNodeArray(node.types, '', ',', false);
if (this.dev) console.log(`${this.indent()}• visitHeritageClause [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitExpressionWithTypeArguments(node: ts.ExpressionWithTypeArguments): boolean {
if (this.dev) console.log(`${this.indent()}• visitExpressionWithTypeArguments [${node.pos}:${node.end}]`);
node.modifiers?.forEach((modifier) => this.continueWalk(modifier));
this.continueWalk(node.expression);
if (node.typeArguments) this.visitNodeArray(node.typeArguments, '<>');
if (this.dev)
console.log(`${this.indent()}• visitExpressionWithTypeArguments [${node.pos}:${node.end}] <<EXIT>>`);
return false;
}
private visitNewExpression(node: ts.NewExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitNewExpression [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['new']);
this.continueWalk(node.expression);
if (node.arguments) this.visitNodeArray(node.arguments, '()');
return false;
}
private visitTypeLiteralNode(node: ts.TypeLiteralNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitTypeLiteralNode [${node.pos}:${node.end}]`);
this.visitNodeArray(node.members, '{}', ',');
return false;
}
private visitPropertySignature(node: ts.PropertySignature): boolean {
if (this.dev) console.log(`${this.indent()}• visitPropertySignature [${node.pos}:${node.end}]`);
this.continueWalk(node.name);
if (node.questionToken) this.addOperatorsToAllHalstead(['?']);
if (node.type) {
this.addOperatorsToAllHalstead([':']);
this.continueWalk(node.type);
}
return false;
}
private visitExportAssignment(node: ts.ExportAssignment): boolean {
if (this.dev) console.log(`${this.indent()}• visitExportAssignment [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['export']);
if (node.isExportEquals) {
this.addOperatorsToAllHalstead(['=']);
} else {
this.addOperatorsToAllHalstead(['default']);
}
this.continueWalk(node.expression);
return false;
}
private visitModuleBlock(node: ts.ModuleBlock): boolean {
if (this.dev) console.log(`${this.indent()}• visitModuleBlock [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['{}']);
this.visitBlockStatements(node.statements);
return false;
}
private visitBlockStatements(statements: ts.NodeArray<ts.Statement>): boolean {
if (this.dev) console.log(`${this.indent()}• visitBlockStatements`, statements);
for (const statement of statements) {
if (statement.flags & ts.NodeFlags.ThisNodeHasError) continue;
if (this.dev) console.log('** visitSourceFile.statement', statement.pos, statement.end);
this.continueWalk(statement);
}
return false;
}
private visitSetAccesssor(node: ts.SetAccessorDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitSetAccessor [${node.pos}:${node.end}]`);
return false;
}
private visitFunctionTypeNode(node: ts.FunctionTypeNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitFunctionTypeNode [${node.pos}:${node.end}]`);
this.visitNodeArray(node.parameters, '()');
this.addOperatorsToAllHalstead(['=>']);
this.continueWalk(node.type);
return false;
}
private visitBreakStatement(node: ts.BreakStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitBreakStatement [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['break']);
return false;
}
private visitContinueStatement(node: ts.ContinueStatement): boolean {
if (this.dev) console.log(`${this.indent()}• visitContinueStatement [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['continue']);
return false;
}
private visitParenthesizedExpression(node: ts.ParenthesizedExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitParenthesizedExpression [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['()']);
this.continueWalk(node.expression);
return false;
}
private visitUnionTypeNode(node: ts.UnionTypeNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitUnionTypeNode [${node.pos}:${node.end}]`);
this.visitNodeArray(node.types, '', '|', false);
return false;
}
private visitTypeQueryNode(node: ts.TypeQueryNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitTypeQueryNode [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['typeof']);
this.continueWalk(node.exprName);
return false;
}
private visitArrayLiteralExpression(node: ts.ArrayLiteralExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitArrayLiteralExpression [${node.pos}:${node.end}]`);
this.visitNodeArray(node.elements, '[]');
return false;
}
private visitObjectBindingPattern(node: ts.ObjectBindingPattern): boolean {
if (this.dev) console.log(`${this.indent()}• visitObjectBindingPattern [${node.pos}:${node.end}]`);
this.visitNodeArray(node.elements, '{}');
return false;
}
private visitBindingElement(node: ts.BindingElement): boolean {
if (this.dev) console.log(`${this.indent()}• visitBindingElement [${node.pos}:${node.end}]`);
if (node.propertyName) {
this.continueWalk(node.propertyName);
this.addOperatorsToAllHalstead([':']);
}
this.continueWalk(node.name);
return false;
}
private visitObjectLiteralExpression(node: ts.ObjectLiteralExpression): boolean {
if (this.dev) console.log(`${this.indent()}• visitObjectLiteralExpression [${node.pos}:${node.end}]`);
this.visitNodeArray(node.properties, '{}');
return false;
}
private visitShorthandPropertyAssignment(node: ts.ShorthandPropertyAssignment): boolean {
if (this.dev) console.log(`${this.indent()}• visitShorthandPropertyAssignment [${node.pos}:${node.end}]`);
this.continueWalk(node.name);
return false;
}
private visitPropertyAssignment(node: ts.PropertyAssignment): boolean {
if (this.dev) console.log(`${this.indent()}• visitPropertyAssignment [${node.pos}:${node.end}]`);
this.continueWalk(node.name);
this.addOperatorsToAllHalstead([':']);
this.continueWalk(node.initializer);
return false;
}
private visitQualifiedName(node: ts.QualifiedName): boolean {
if (this.dev) console.log(`${this.indent()}• visitQualifiedName [${node.pos}:${node.end}]`);
this.continueWalk(node.left);
this.addOperatorsToAllHalstead(['.']);
this.continueWalk(node.right);
return false;
}
private visitPrivateIdentifier(node: ts.PrivateIdentifier): boolean {
if (this.dev) console.log(`${this.indent()}• visitPrivateIdentifier [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([node.escapedText.toString()]);
return false;
}
private visitJsxText(node: ts.JsxText): boolean {
if (this.dev) console.log(`${this.indent()}• visitJsxText [${node.pos}:${node.end}]`);
let text = node.text.replace(/(\r\n\s*|\n\s*|\r\s*)/gm, '');
if (text == '') return false;
this.addOperandsToAllHalstead([`"${text}"`]);
return false;
}
private visitRegularExpressionLiteral(node: ts.RegularExpressionLiteral): boolean {
if (this.dev) console.log(`${this.indent()}• visitRegularExpressionLiteral [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([node.text]);
return false;
}
private visitNoSubstitutionTemplateLiteral(node: ts.NoSubstitutionTemplateLiteral): boolean {
if (this.dev) console.log(`${this.indent()}• visitNoSubstitutionTemplateLiteral [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([`"${node.text}"`]);
return false;
}
private visitTemplateHead(node: ts.TemplateHead): boolean {
if (this.dev) console.log(`${this.indent()}• visitTemplateHead [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([`"${node.text}"`]);
return false;
}
private visitTemplateMiddle(node: ts.TemplateMiddle): boolean {
if (this.dev) console.log(`${this.indent()}• visitTemplateMiddle [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([`"${node.text}"`]);
return false;
}
private visitTemplateTail(node: ts.TemplateTail): boolean {
if (this.dev) console.log(`${this.indent()}• visitTemplateTail [${node.pos}:${node.end}]`);
this.addOperandsToAllHalstead([`"${node.text}"`]);
return false;
}
private visitDotDotDotToken(node: ts.DotDotDotToken): boolean {
if (this.dev) console.log(`${this.indent()}• visitDotDotDotToken [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['...']);
return false;
}
private visitPlusToken(node: ts.PlusToken): boolean {
if (this.dev) console.log(`${this.indent()}• visitPlusToken [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['+']);
return false;
}
private visitMinusToken(node: ts.MinusToken): boolean {
if (this.dev) console.log(`${this.indent()}• visitMinusToken [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['-']);
return false;
}
private visitDecorator(node: ts.Decorator): boolean {
if (this.dev) console.log(`${this.indent()}• visitDecorator [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['@']);
this.continueWalk(node.expression);
return false;
}
private visitIndexSignatureDeclaration(node: ts.IndexSignatureDeclaration): boolean {
if (this.dev) console.log(`${this.indent()}• visitIndexSignatureDeclaration [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['[]']);
this.visitNodeArray(node.parameters, '', ',', false);
this.addOperatorsToAllHalstead([':']);
this.continueWalk(node.type);
return false;
}
private visitTypePredicateNode(node: ts.TypePredicateNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitTypePredicateNode [${node.pos}:${node.end}]`);
this.continueWalk(node.parameterName);
if (node.type) {
this.addOperatorsToAllHalstead(['is']);
this.continueWalk(node.type);
}
return false;
}
private visitConstructorTypeNode(node: ts.ConstructorTypeNode): boolean {
if (this.dev) console.log(`${this.indent()}• visitConstructorTypeNode [${node.pos}:${node.end}]`);
this.addOperatorsToAllHalstead(['new']);
this.visitNodeArray(node.parameters, '()');
this.addOperatorsToAllHalstead(['=>']);
this.continueWalk(