@jqassistant/ts-lce
Version:
Tool to extract language concepts from a TypeScript codebase and export them to a JSON file.
146 lines (145 loc) • 9.44 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.MemberExpressionDependencyProcessor = exports.IdentifierDependencyProcessor = exports.DeclarationScopeProcessor = exports.ScopeProcessor = void 0;
const utils_1 = require("@typescript-eslint/utils");
const type_concept_1 = require("../concepts/type.concept");
const context_1 = require("../context");
const execution_condition_1 = require("../execution-condition");
const processor_1 = require("../processor");
const processor_utils_1 = require("../utils/processor.utils");
const class_traverser_1 = require("../traversers/class.traverser");
const expression_traverser_1 = require("../traversers/expression.traverser");
const function_traverser_1 = require("../traversers/function.traverser");
const method_traverser_1 = require("../traversers/method.traverser");
const property_traverser_1 = require("../traversers/property.traverser");
const dependency_resolution_processor_1 = require("./dependency-resolution.processor");
const type_utils_1 = require("./type.utils");
const type_alias_declaration_traverser_1 = require("../traversers/type-alias-declaration.traverser");
const context_keys_1 = require("../context.keys");
/**
* Registers unnamed `FQNScope` local contexts for all nodes that create a new anonymous scope.
*/
class ScopeProcessor extends processor_1.Processor {
executionCondition = new execution_condition_1.ExecutionCondition([utils_1.AST_NODE_TYPES.BlockStatement, utils_1.AST_NODE_TYPES.ForStatement, utils_1.AST_NODE_TYPES.ForInStatement, utils_1.AST_NODE_TYPES.ForOfStatement], () => true);
preChildrenProcessing({ localContexts }) {
dependency_resolution_processor_1.DependencyResolutionProcessor.addScopeContext(localContexts);
}
}
exports.ScopeProcessor = ScopeProcessor;
/**
* Registers named `FQNScope` local contexts for all declaration nodes.
*/
class DeclarationScopeProcessor extends processor_1.Processor {
executionCondition = new execution_condition_1.ExecutionCondition([
utils_1.AST_NODE_TYPES.ClassDeclaration,
utils_1.AST_NODE_TYPES.FunctionDeclaration,
utils_1.AST_NODE_TYPES.TSDeclareFunction,
utils_1.AST_NODE_TYPES.TSInterfaceDeclaration,
utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration,
utils_1.AST_NODE_TYPES.TSEnumDeclaration,
], () => true);
preChildrenProcessing({ localContexts, node }) {
if ((node.type === utils_1.AST_NODE_TYPES.ClassDeclaration ||
node.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
node.type === utils_1.AST_NODE_TYPES.TSDeclareFunction ||
node.type === utils_1.AST_NODE_TYPES.TSInterfaceDeclaration ||
node.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration ||
node.type === utils_1.AST_NODE_TYPES.TSEnumDeclaration) &&
node.id) {
dependency_resolution_processor_1.DependencyResolutionProcessor.addScopeContext(localContexts, context_1.FQN.id(node.id.name));
}
else {
dependency_resolution_processor_1.DependencyResolutionProcessor.addScopeContext(localContexts);
}
}
}
exports.DeclarationScopeProcessor = DeclarationScopeProcessor;
class IdentifierDependencyProcessor extends processor_1.Processor {
/**
* This execution conditions filters out all identifier nodes that are already registered by other processors.
*/
executionCondition = new execution_condition_1.ExecutionCondition([utils_1.AST_NODE_TYPES.Identifier], ({ node, localContexts }) => !(node.parent?.type === utils_1.AST_NODE_TYPES.ClassDeclaration && (0, processor_utils_1.getParentPropName)(localContexts) === class_traverser_1.ClassTraverser.EXTENDS_PROP) &&
!((node.parent?.type === utils_1.AST_NODE_TYPES.MethodDefinition || node.parent?.type === utils_1.AST_NODE_TYPES.TSMethodSignature) &&
((0, processor_utils_1.getParentPropName)(localContexts) === method_traverser_1.MethodTraverser.KEY_PROP ||
(0, processor_utils_1.getParentPropName)(localContexts) === method_traverser_1.MethodTraverser.PARAMETERS_PROP)) &&
!((node.parent?.type === utils_1.AST_NODE_TYPES.PropertyDefinition || node.parent?.type === utils_1.AST_NODE_TYPES.TSPropertySignature) &&
(0, processor_utils_1.getParentPropName)(localContexts) === property_traverser_1.PropertyTraverser.KEY_PROP) &&
!((node.parent?.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
node.parent?.type === utils_1.AST_NODE_TYPES.TSDeclareFunction ||
node.parent?.type === utils_1.AST_NODE_TYPES.FunctionExpression) &&
(0, processor_utils_1.getParentPropName)(localContexts) === function_traverser_1.FunctionTraverser.PARAMETERS_PROP) &&
!(node.parent?.type === utils_1.AST_NODE_TYPES.ArrowFunctionExpression &&
(0, processor_utils_1.getParentPropName)(localContexts) === expression_traverser_1.ArrowFunctionExpressionTraverser.PARAMETERS_PROP) &&
!(node.parent?.type === utils_1.AST_NODE_TYPES.TaggedTemplateExpression &&
(0, processor_utils_1.getParentPropName)(localContexts) === expression_traverser_1.TaggedTemplateExpressionTraverser.TAG_PROP) &&
!(node.parent?.type === utils_1.AST_NODE_TYPES.MemberExpression && (0, processor_utils_1.getParentPropName)(localContexts) === expression_traverser_1.MemberExpressionTraverser.PROPERTY_PROP) &&
node.parent?.type !== utils_1.AST_NODE_TYPES.ArrayPattern &&
node.parent?.type !== utils_1.AST_NODE_TYPES.ObjectPattern &&
node.parent?.type !== utils_1.AST_NODE_TYPES.ImportExpression &&
node.parent?.type !== utils_1.AST_NODE_TYPES.TSInterfaceHeritage &&
!(node.parent?.type === utils_1.AST_NODE_TYPES.TSTypeReference && this.isDirectAncestorTypeAnnotation(node, localContexts)));
/**
* This method is used to filter out all type identifiers that are part of type annotations or type parameters, as they are already registered via the native type resolution
*/
isDirectAncestorTypeAnnotation(node, localContexts) {
let ancestor = node.parent;
let localContextIndex = localContexts.contexts.length - 2;
while (ancestor?.parent) {
const parentPropName = localContexts.contexts[localContextIndex].get(context_keys_1.CoreContextKeys.TRAVERSER_CONTEXT)
.parentPropName;
if (ancestor.parent.type === utils_1.AST_NODE_TYPES.TSTypeAnnotation ||
(ancestor.parent.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration &&
parentPropName === type_alias_declaration_traverser_1.TypeAliasDeclarationTraverser.TYPE_ANNOTATION_PROP) ||
(ancestor.parent.type === utils_1.AST_NODE_TYPES.TSTypeAliasDeclaration &&
parentPropName === type_alias_declaration_traverser_1.TypeAliasDeclarationTraverser.TYPE_PARAMETERS_PROP) ||
((ancestor.parent.type === utils_1.AST_NODE_TYPES.FunctionExpression ||
ancestor.parent.type === utils_1.AST_NODE_TYPES.FunctionDeclaration ||
ancestor.parent.type === utils_1.AST_NODE_TYPES.TSDeclareFunction ||
ancestor.parent.type === utils_1.AST_NODE_TYPES.TSEmptyBodyFunctionExpression) &&
parentPropName === function_traverser_1.FunctionTraverser.TYPE_PARAMETERS_PROP)) {
return true;
}
ancestor = ancestor.parent;
localContextIndex--;
if (localContextIndex < 0) {
break;
}
}
return false;
}
postChildrenProcessing({ node, localContexts }) {
if (node.type === utils_1.AST_NODE_TYPES.Identifier) {
dependency_resolution_processor_1.DependencyResolutionProcessor.registerDependency(localContexts, node.name);
}
return new Map();
}
}
exports.IdentifierDependencyProcessor = IdentifierDependencyProcessor;
/**
* Processes member expressions and adds appropriate dependencies.
* Only processes identifier and direct literal property accesses.
* Adds dependencies for all type member accesses.
*/
class MemberExpressionDependencyProcessor extends processor_1.Processor {
executionCondition = new execution_condition_1.ExecutionCondition([utils_1.AST_NODE_TYPES.MemberExpression], () => true);
postChildrenProcessing({ node, localContexts, ...unusedProcessingContext }) {
if (node.type === utils_1.AST_NODE_TYPES.MemberExpression &&
(node.property.type === utils_1.AST_NODE_TYPES.Identifier || node.property.type === utils_1.AST_NODE_TYPES.Literal)) {
const objectType = (0, type_utils_1.parseESNodeType)({ node, localContexts, ...unusedProcessingContext }, node.object, undefined, true);
if (objectType instanceof type_concept_1.LCETypeDeclared) {
const globalFqn = objectType.fqn.globalFqn + "." + this.getNamespace(node.property);
dependency_resolution_processor_1.DependencyResolutionProcessor.registerDependency(localContexts, globalFqn, false);
}
}
return new Map();
}
getNamespace(node) {
if (node.type === utils_1.AST_NODE_TYPES.Identifier) {
return node.name;
}
else {
return node.raw;
}
}
}
exports.MemberExpressionDependencyProcessor = MemberExpressionDependencyProcessor;