UNPKG

@sourcefield/lsif-typescript

Version:
924 lines (841 loc) 121 kB
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(