@grafema/core 0.1.1-alpha → 0.2.0-beta
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/Orchestrator.d.ts +7 -0
- package/dist/Orchestrator.d.ts.map +1 -1
- package/dist/Orchestrator.js +25 -3
- package/dist/config/ConfigLoader.d.ts +18 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -1
- package/dist/config/ConfigLoader.js +65 -3
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +139 -0
- package/dist/core/NodeFactory.d.ts +44 -5
- package/dist/core/NodeFactory.d.ts.map +1 -1
- package/dist/core/NodeFactory.js +52 -7
- package/dist/core/nodes/ArrayLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ArrayLiteralNode.js +4 -2
- package/dist/core/nodes/BranchNode.d.ts +41 -0
- package/dist/core/nodes/BranchNode.d.ts.map +1 -0
- package/dist/core/nodes/BranchNode.js +82 -0
- package/dist/core/nodes/CallSiteNode.d.ts +2 -2
- package/dist/core/nodes/CallSiteNode.d.ts.map +1 -1
- package/dist/core/nodes/CallSiteNode.js +9 -5
- package/dist/core/nodes/CaseNode.d.ts +43 -0
- package/dist/core/nodes/CaseNode.d.ts.map +1 -0
- package/dist/core/nodes/CaseNode.js +81 -0
- package/dist/core/nodes/ClassNode.d.ts +2 -2
- package/dist/core/nodes/ClassNode.d.ts.map +1 -1
- package/dist/core/nodes/ClassNode.js +8 -4
- package/dist/core/nodes/ConstantNode.d.ts +2 -2
- package/dist/core/nodes/ConstantNode.d.ts.map +1 -1
- package/dist/core/nodes/ConstantNode.js +6 -4
- package/dist/core/nodes/ConstructorCallNode.d.ts +51 -0
- package/dist/core/nodes/ConstructorCallNode.d.ts.map +1 -0
- package/dist/core/nodes/ConstructorCallNode.js +171 -0
- package/dist/core/nodes/DatabaseQueryNode.d.ts +3 -2
- package/dist/core/nodes/DatabaseQueryNode.d.ts.map +1 -1
- package/dist/core/nodes/DatabaseQueryNode.js +5 -2
- package/dist/core/nodes/DecoratorNode.d.ts +2 -2
- package/dist/core/nodes/DecoratorNode.d.ts.map +1 -1
- package/dist/core/nodes/DecoratorNode.js +5 -3
- package/dist/core/nodes/EnumNode.d.ts +2 -2
- package/dist/core/nodes/EnumNode.d.ts.map +1 -1
- package/dist/core/nodes/EnumNode.js +5 -3
- package/dist/core/nodes/EventListenerNode.d.ts +4 -4
- package/dist/core/nodes/EventListenerNode.d.ts.map +1 -1
- package/dist/core/nodes/EventListenerNode.js +7 -4
- package/dist/core/nodes/ExportNode.d.ts +2 -2
- package/dist/core/nodes/ExportNode.d.ts.map +1 -1
- package/dist/core/nodes/ExportNode.js +8 -4
- package/dist/core/nodes/ExpressionNode.d.ts +2 -2
- package/dist/core/nodes/ExpressionNode.d.ts.map +1 -1
- package/dist/core/nodes/ExpressionNode.js +6 -4
- package/dist/core/nodes/ExternalModuleNode.d.ts +4 -0
- package/dist/core/nodes/ExternalModuleNode.d.ts.map +1 -1
- package/dist/core/nodes/ExternalModuleNode.js +10 -2
- package/dist/core/nodes/HttpRequestNode.d.ts +4 -4
- package/dist/core/nodes/HttpRequestNode.d.ts.map +1 -1
- package/dist/core/nodes/HttpRequestNode.js +7 -4
- package/dist/core/nodes/ImportNode.d.ts +10 -2
- package/dist/core/nodes/ImportNode.d.ts.map +1 -1
- package/dist/core/nodes/ImportNode.js +21 -4
- package/dist/core/nodes/InterfaceNode.d.ts +2 -2
- package/dist/core/nodes/InterfaceNode.d.ts.map +1 -1
- package/dist/core/nodes/InterfaceNode.js +5 -3
- package/dist/core/nodes/LiteralNode.d.ts +2 -2
- package/dist/core/nodes/LiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/LiteralNode.js +6 -4
- package/dist/core/nodes/MethodCallNode.d.ts +2 -2
- package/dist/core/nodes/MethodCallNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodCallNode.js +9 -5
- package/dist/core/nodes/MethodNode.d.ts +2 -2
- package/dist/core/nodes/MethodNode.d.ts.map +1 -1
- package/dist/core/nodes/MethodNode.js +8 -4
- package/dist/core/nodes/ObjectLiteralNode.d.ts.map +1 -1
- package/dist/core/nodes/ObjectLiteralNode.js +4 -2
- package/dist/core/nodes/ParameterNode.d.ts +2 -2
- package/dist/core/nodes/ParameterNode.d.ts.map +1 -1
- package/dist/core/nodes/ParameterNode.js +5 -3
- package/dist/core/nodes/TypeNode.d.ts +2 -2
- package/dist/core/nodes/TypeNode.d.ts.map +1 -1
- package/dist/core/nodes/TypeNode.js +5 -3
- package/dist/core/nodes/VariableDeclarationNode.d.ts +2 -2
- package/dist/core/nodes/VariableDeclarationNode.d.ts.map +1 -1
- package/dist/core/nodes/VariableDeclarationNode.js +9 -5
- package/dist/core/nodes/index.d.ts +3 -0
- package/dist/core/nodes/index.d.ts.map +1 -1
- package/dist/core/nodes/index.js +3 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts +78 -0
- package/dist/data/builtins/BuiltinRegistry.d.ts.map +1 -0
- package/dist/data/builtins/BuiltinRegistry.js +110 -0
- package/dist/data/builtins/definitions.d.ts +28 -0
- package/dist/data/builtins/definitions.d.ts.map +1 -0
- package/dist/data/builtins/definitions.js +250 -0
- package/dist/data/builtins/index.d.ts +10 -0
- package/dist/data/builtins/index.d.ts.map +1 -0
- package/dist/data/builtins/index.js +8 -0
- package/dist/data/builtins/jsGlobals.d.ts +18 -0
- package/dist/data/builtins/jsGlobals.d.ts.map +1 -0
- package/dist/data/builtins/jsGlobals.js +26 -0
- package/dist/data/builtins/types.d.ts +34 -0
- package/dist/data/builtins/types.d.ts.map +1 -0
- package/dist/data/builtins/types.js +7 -0
- package/dist/data/globals/definitions.d.ts +27 -0
- package/dist/data/globals/definitions.d.ts.map +1 -0
- package/dist/data/globals/definitions.js +117 -0
- package/dist/data/globals/index.d.ts +36 -0
- package/dist/data/globals/index.d.ts.map +1 -0
- package/dist/data/globals/index.js +52 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +23 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -1
- package/dist/diagnostics/DiagnosticReporter.js +88 -0
- package/dist/diagnostics/index.d.ts +1 -1
- package/dist/diagnostics/index.d.ts.map +1 -1
- package/dist/errors/GrafemaError.d.ts +43 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -1
- package/dist/errors/GrafemaError.js +50 -0
- package/dist/index.d.ts +17 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +17 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/DatabaseAnalyzer.js +3 -2
- package/dist/plugins/analysis/ExpressAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressAnalyzer.js +3 -1
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts +148 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.d.ts.map +1 -0
- package/dist/plugins/analysis/ExpressResponseAnalyzer.js +495 -0
- package/dist/plugins/analysis/ExpressRouteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/ExpressRouteAnalyzer.js +53 -18
- package/dist/plugins/analysis/FetchAnalyzer.d.ts +40 -0
- package/dist/plugins/analysis/FetchAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/FetchAnalyzer.js +163 -15
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts +157 -26
- package/dist/plugins/analysis/JSASTAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/JSASTAnalyzer.js +2418 -191
- package/dist/plugins/analysis/RustAnalyzer.js +4 -4
- package/dist/plugins/analysis/SQLiteAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SQLiteAnalyzer.js +4 -2
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts +9 -0
- package/dist/plugins/analysis/SocketIOAnalyzer.d.ts.map +1 -1
- package/dist/plugins/analysis/SocketIOAnalyzer.js +91 -7
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts +173 -0
- package/dist/plugins/analysis/ast/GraphBuilder.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/GraphBuilder.js +1256 -65
- package/dist/plugins/analysis/ast/types.d.ts +294 -0
- package/dist/plugins/analysis/ast/types.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts +5 -1
- package/dist/plugins/analysis/ast/visitors/ASTVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts +1 -0
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/CallExpressionVisitor.js +12 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts +10 -0
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/FunctionVisitor.js +62 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts +4 -0
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/ImportExportVisitor.js +101 -0
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts +16 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.d.ts.map +1 -1
- package/dist/plugins/analysis/ast/visitors/VariableVisitor.js +233 -39
- package/dist/plugins/discovery/WorkspaceDiscovery.d.ts.map +1 -1
- package/dist/plugins/discovery/WorkspaceDiscovery.js +9 -4
- package/dist/plugins/enrichment/AliasTracker.d.ts.map +1 -1
- package/dist/plugins/enrichment/AliasTracker.js +16 -1
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts +32 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.d.ts.map +1 -0
- package/dist/plugins/enrichment/ArgumentParameterLinker.js +175 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts +51 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.d.ts.map +1 -0
- package/dist/plugins/enrichment/ClosureCaptureEnricher.js +205 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts +42 -0
- package/dist/plugins/enrichment/ExternalCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/ExternalCallResolver.js +213 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts +58 -0
- package/dist/plugins/enrichment/FunctionCallResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/FunctionCallResolver.js +340 -0
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts +16 -3
- package/dist/plugins/enrichment/HTTPConnectionEnricher.d.ts.map +1 -1
- package/dist/plugins/enrichment/HTTPConnectionEnricher.js +64 -20
- package/dist/plugins/enrichment/MethodCallResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MethodCallResolver.js +15 -1
- package/dist/plugins/enrichment/MountPointResolver.d.ts +14 -12
- package/dist/plugins/enrichment/MountPointResolver.d.ts.map +1 -1
- package/dist/plugins/enrichment/MountPointResolver.js +172 -151
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts +44 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.d.ts.map +1 -0
- package/dist/plugins/enrichment/NodejsBuiltinsResolver.js +271 -0
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts +5 -27
- package/dist/plugins/enrichment/ValueDomainAnalyzer.d.ts.map +1 -1
- package/dist/plugins/enrichment/ValueDomainAnalyzer.js +62 -139
- package/dist/plugins/indexing/JSModuleIndexer.d.ts +15 -0
- package/dist/plugins/indexing/JSModuleIndexer.d.ts.map +1 -1
- package/dist/plugins/indexing/JSModuleIndexer.js +58 -0
- package/dist/plugins/indexing/RustModuleIndexer.d.ts +1 -1
- package/dist/plugins/indexing/RustModuleIndexer.js +4 -4
- package/dist/plugins/validation/BrokenImportValidator.d.ts +31 -0
- package/dist/plugins/validation/BrokenImportValidator.d.ts.map +1 -0
- package/dist/plugins/validation/BrokenImportValidator.js +249 -0
- package/dist/plugins/validation/CallResolverValidator.d.ts +21 -10
- package/dist/plugins/validation/CallResolverValidator.d.ts.map +1 -1
- package/dist/plugins/validation/CallResolverValidator.js +101 -76
- package/dist/plugins/validation/DataFlowValidator.d.ts.map +1 -1
- package/dist/plugins/validation/DataFlowValidator.js +49 -41
- package/dist/plugins/validation/GraphConnectivityValidator.d.ts.map +1 -1
- package/dist/plugins/validation/GraphConnectivityValidator.js +25 -1
- package/dist/plugins/validation/SQLInjectionValidator.d.ts.map +1 -1
- package/dist/plugins/validation/SQLInjectionValidator.js +2 -3
- package/dist/queries/findCallsInFunction.d.ts +52 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +135 -0
- package/dist/queries/findContainingFunction.d.ts +45 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +54 -0
- package/dist/queries/index.d.ts +14 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +11 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +299 -0
- package/dist/queries/types.d.ts +163 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +9 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +124 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +112 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +2 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +12 -18
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -1
- package/dist/storage/backends/RFDBServerBackend.js +41 -52
- package/dist/storage/backends/typeValidation.d.ts.map +1 -1
- package/dist/storage/backends/typeValidation.js +1 -0
- package/package.json +3 -3
- package/src/Orchestrator.ts +35 -3
- package/src/config/ConfigLoader.ts +94 -3
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/NodeFactory.ts +72 -8
- package/src/core/nodes/ArrayLiteralNode.ts +3 -2
- package/src/core/nodes/BranchNode.ts +113 -0
- package/src/core/nodes/CallSiteNode.ts +7 -5
- package/src/core/nodes/CaseNode.ts +123 -0
- package/src/core/nodes/ClassNode.ts +6 -4
- package/src/core/nodes/ConstantNode.ts +5 -4
- package/src/core/nodes/ConstructorCallNode.ts +217 -0
- package/src/core/nodes/DatabaseQueryNode.ts +5 -1
- package/src/core/nodes/DecoratorNode.ts +4 -3
- package/src/core/nodes/EnumNode.ts +4 -3
- package/src/core/nodes/EventListenerNode.ts +7 -4
- package/src/core/nodes/ExportNode.ts +6 -4
- package/src/core/nodes/ExpressionNode.ts +5 -4
- package/src/core/nodes/ExternalModuleNode.ts +11 -2
- package/src/core/nodes/HttpRequestNode.ts +7 -4
- package/src/core/nodes/ImportNode.ts +31 -4
- package/src/core/nodes/InterfaceNode.ts +4 -3
- package/src/core/nodes/LiteralNode.ts +5 -4
- package/src/core/nodes/MethodCallNode.ts +7 -5
- package/src/core/nodes/MethodNode.ts +6 -4
- package/src/core/nodes/ObjectLiteralNode.ts +3 -2
- package/src/core/nodes/ParameterNode.ts +4 -3
- package/src/core/nodes/TypeNode.ts +4 -3
- package/src/core/nodes/VariableDeclarationNode.ts +7 -5
- package/src/core/nodes/index.ts +3 -0
- package/src/data/builtins/BuiltinRegistry.ts +124 -0
- package/src/data/builtins/definitions.ts +267 -0
- package/src/data/builtins/index.ts +10 -0
- package/src/data/builtins/jsGlobals.ts +28 -0
- package/src/data/builtins/types.ts +36 -0
- package/src/data/globals/definitions.ts +156 -0
- package/src/data/globals/index.ts +66 -0
- package/src/diagnostics/DiagnosticReporter.ts +120 -0
- package/src/diagnostics/index.ts +1 -1
- package/src/errors/GrafemaError.ts +65 -0
- package/src/index.ts +45 -0
- package/src/plugins/analysis/DatabaseAnalyzer.ts +4 -2
- package/src/plugins/analysis/ExpressAnalyzer.ts +5 -1
- package/src/plugins/analysis/ExpressResponseAnalyzer.ts +636 -0
- package/src/plugins/analysis/ExpressRouteAnalyzer.ts +57 -18
- package/src/plugins/analysis/FetchAnalyzer.ts +204 -16
- package/src/plugins/analysis/JSASTAnalyzer.ts +2958 -260
- package/src/plugins/analysis/RustAnalyzer.ts +4 -4
- package/src/plugins/analysis/SQLiteAnalyzer.ts +5 -2
- package/src/plugins/analysis/SocketIOAnalyzer.ts +121 -7
- package/src/plugins/analysis/ast/GraphBuilder.ts +1578 -70
- package/src/plugins/analysis/ast/types.ts +387 -0
- package/src/plugins/analysis/ast/visitors/ASTVisitor.ts +8 -0
- package/src/plugins/analysis/ast/visitors/CallExpressionVisitor.ts +16 -1
- package/src/plugins/analysis/ast/visitors/FunctionVisitor.ts +77 -2
- package/src/plugins/analysis/ast/visitors/ImportExportVisitor.ts +112 -1
- package/src/plugins/analysis/ast/visitors/VariableVisitor.ts +272 -47
- package/src/plugins/discovery/WorkspaceDiscovery.ts +11 -4
- package/src/plugins/enrichment/AliasTracker.ts +22 -1
- package/src/plugins/enrichment/ArgumentParameterLinker.ts +240 -0
- package/src/plugins/enrichment/ClosureCaptureEnricher.ts +267 -0
- package/src/plugins/enrichment/ExternalCallResolver.ts +262 -0
- package/src/plugins/enrichment/FunctionCallResolver.ts +456 -0
- package/src/plugins/enrichment/HTTPConnectionEnricher.ts +70 -20
- package/src/plugins/enrichment/MethodCallResolver.ts +21 -1
- package/src/plugins/enrichment/MountPointResolver.ts +206 -198
- package/src/plugins/enrichment/NodejsBuiltinsResolver.ts +365 -0
- package/src/plugins/enrichment/ValueDomainAnalyzer.ts +67 -184
- package/src/plugins/indexing/JSModuleIndexer.ts +66 -0
- package/src/plugins/indexing/RustModuleIndexer.ts +4 -4
- package/src/plugins/validation/BrokenImportValidator.ts +325 -0
- package/src/plugins/validation/CallResolverValidator.ts +129 -109
- package/src/plugins/validation/DataFlowValidator.ts +75 -58
- package/src/plugins/validation/GraphConnectivityValidator.ts +39 -1
- package/src/plugins/validation/SQLInjectionValidator.ts +2 -5
- package/src/queries/README.md +46 -0
- package/src/queries/findCallsInFunction.ts +206 -0
- package/src/queries/findContainingFunction.ts +83 -0
- package/src/queries/index.ts +23 -0
- package/src/queries/traceValues.ts +398 -0
- package/src/queries/types.ts +187 -0
- package/src/schema/GraphSchemaExtractor.ts +177 -0
- package/src/schema/InterfaceSchemaExtractor.ts +173 -0
- package/src/schema/index.ts +5 -0
- package/src/storage/backends/RFDBServerBackend.ts +58 -70
- package/src/storage/backends/typeValidation.ts +1 -0
|
@@ -21,7 +21,9 @@ import type {
|
|
|
21
21
|
FunctionDeclaration,
|
|
22
22
|
ClassDeclaration,
|
|
23
23
|
Identifier,
|
|
24
|
-
Node
|
|
24
|
+
Node,
|
|
25
|
+
CallExpression,
|
|
26
|
+
TemplateLiteral
|
|
25
27
|
} from '@babel/types';
|
|
26
28
|
import type { NodePath } from '@babel/traverse';
|
|
27
29
|
import { ASTVisitor, type VisitorModule, type VisitorCollections, type VisitorHandlers } from './ASTVisitor.js';
|
|
@@ -49,6 +51,9 @@ interface ImportInfo {
|
|
|
49
51
|
specifiers: ImportSpecifierInfo[];
|
|
50
52
|
line: number;
|
|
51
53
|
column?: number;
|
|
54
|
+
isDynamic?: boolean; // true for dynamic import() expressions
|
|
55
|
+
isResolvable?: boolean; // true if path is a string literal (statically analyzable)
|
|
56
|
+
dynamicPath?: string; // original expression for template/variable paths
|
|
52
57
|
}
|
|
53
58
|
|
|
54
59
|
/**
|
|
@@ -132,10 +137,116 @@ export class ImportExportVisitor extends ASTVisitor {
|
|
|
132
137
|
line: getLine(node),
|
|
133
138
|
column: getColumn(node)
|
|
134
139
|
});
|
|
140
|
+
},
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Handle dynamic import() expressions
|
|
144
|
+
* Examples:
|
|
145
|
+
* - import('./module.js') -> isResolvable: true
|
|
146
|
+
* - import(`./plugins/${name}.js`) -> isResolvable: false, source: './plugins/'
|
|
147
|
+
* - import(modulePath) -> isResolvable: false, source: '<dynamic>'
|
|
148
|
+
*/
|
|
149
|
+
CallExpression: (path: NodePath) => {
|
|
150
|
+
const node = path.node as CallExpression;
|
|
151
|
+
|
|
152
|
+
// Check if this is an import() call
|
|
153
|
+
if (node.callee.type !== 'Import') {
|
|
154
|
+
return;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
const arg = node.arguments[0];
|
|
158
|
+
if (!arg) return;
|
|
159
|
+
|
|
160
|
+
let source: string;
|
|
161
|
+
let isResolvable: boolean;
|
|
162
|
+
let dynamicPath: string | undefined;
|
|
163
|
+
|
|
164
|
+
if (arg.type === 'StringLiteral') {
|
|
165
|
+
// import('./module.js') - literal path, fully resolvable
|
|
166
|
+
source = arg.value;
|
|
167
|
+
isResolvable = true;
|
|
168
|
+
} else if (arg.type === 'TemplateLiteral') {
|
|
169
|
+
// import(`./plugins/${name}.js`) - template literal
|
|
170
|
+
const templateArg = arg as TemplateLiteral;
|
|
171
|
+
const firstQuasi = templateArg.quasis[0];
|
|
172
|
+
|
|
173
|
+
// Extract static prefix (part before first expression)
|
|
174
|
+
const prefix = firstQuasi?.value?.raw || '';
|
|
175
|
+
|
|
176
|
+
if (prefix) {
|
|
177
|
+
source = prefix;
|
|
178
|
+
} else {
|
|
179
|
+
// No static prefix - e.g., import(`${baseDir}/loader.js`)
|
|
180
|
+
source = '<dynamic>';
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
isResolvable = false;
|
|
184
|
+
// Capture the original template for debugging/analysis
|
|
185
|
+
dynamicPath = this.templateLiteralToString(templateArg);
|
|
186
|
+
} else if (arg.type === 'Identifier') {
|
|
187
|
+
// import(modulePath) - variable path
|
|
188
|
+
source = '<dynamic>';
|
|
189
|
+
isResolvable = false;
|
|
190
|
+
dynamicPath = (arg as Identifier).name;
|
|
191
|
+
} else {
|
|
192
|
+
// Other expressions (e.g., function calls, member expressions)
|
|
193
|
+
source = '<dynamic>';
|
|
194
|
+
isResolvable = false;
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
// Find the receiving variable name from parent
|
|
198
|
+
// Patterns: const mod = await import(...) or const mod = import(...)
|
|
199
|
+
let localName = '*'; // Default for side-effect imports
|
|
200
|
+
const parent = path.parent;
|
|
201
|
+
|
|
202
|
+
if (parent?.type === 'AwaitExpression') {
|
|
203
|
+
// const mod = await import(...)
|
|
204
|
+
const awaitParent = path.parentPath?.parent;
|
|
205
|
+
if (awaitParent?.type === 'VariableDeclarator' &&
|
|
206
|
+
awaitParent.id?.type === 'Identifier') {
|
|
207
|
+
localName = awaitParent.id.name;
|
|
208
|
+
}
|
|
209
|
+
} else if (parent?.type === 'VariableDeclarator' &&
|
|
210
|
+
parent.id?.type === 'Identifier') {
|
|
211
|
+
// const mod = import(...) (without await)
|
|
212
|
+
localName = parent.id.name;
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
(imports as ImportInfo[]).push({
|
|
216
|
+
source,
|
|
217
|
+
specifiers: [{
|
|
218
|
+
imported: '*', // Dynamic imports are always namespace imports
|
|
219
|
+
local: localName
|
|
220
|
+
}],
|
|
221
|
+
line: getLine(node),
|
|
222
|
+
column: getColumn(node),
|
|
223
|
+
isDynamic: true,
|
|
224
|
+
isResolvable,
|
|
225
|
+
dynamicPath
|
|
226
|
+
});
|
|
135
227
|
}
|
|
136
228
|
};
|
|
137
229
|
}
|
|
138
230
|
|
|
231
|
+
/**
|
|
232
|
+
* Convert a TemplateLiteral to a string representation for debugging
|
|
233
|
+
*/
|
|
234
|
+
private templateLiteralToString(template: TemplateLiteral): string {
|
|
235
|
+
let result = '';
|
|
236
|
+
for (let i = 0; i < template.quasis.length; i++) {
|
|
237
|
+
result += template.quasis[i].value.raw;
|
|
238
|
+
if (i < template.expressions.length) {
|
|
239
|
+
const expr = template.expressions[i];
|
|
240
|
+
if (expr.type === 'Identifier') {
|
|
241
|
+
result += `\${${expr.name}}`;
|
|
242
|
+
} else {
|
|
243
|
+
result += '${...}';
|
|
244
|
+
}
|
|
245
|
+
}
|
|
246
|
+
}
|
|
247
|
+
return result;
|
|
248
|
+
}
|
|
249
|
+
|
|
139
250
|
getExportHandlers(): VisitorHandlers {
|
|
140
251
|
const { exports } = this.collections;
|
|
141
252
|
const extractVariableNamesFromPattern = this.extractVariableNamesFromPattern;
|
|
@@ -29,6 +29,7 @@ export interface VariableInfo {
|
|
|
29
29
|
loc: { start: { line: number; column: number } };
|
|
30
30
|
propertyPath?: string[];
|
|
31
31
|
arrayIndex?: number;
|
|
32
|
+
isRest?: boolean;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
/**
|
|
@@ -47,7 +48,10 @@ export type TrackVariableAssignmentCallback = (
|
|
|
47
48
|
line: number,
|
|
48
49
|
literals: unknown[],
|
|
49
50
|
variableAssignments: unknown[],
|
|
50
|
-
literalCounterRef: CounterRef
|
|
51
|
+
literalCounterRef: CounterRef,
|
|
52
|
+
objectLiterals: unknown[],
|
|
53
|
+
objectProperties: unknown[],
|
|
54
|
+
objectLiteralCounterRef: CounterRef
|
|
51
55
|
) => void;
|
|
52
56
|
|
|
53
57
|
/**
|
|
@@ -100,11 +104,82 @@ interface VariableAssignmentInfo {
|
|
|
100
104
|
file?: string;
|
|
101
105
|
}
|
|
102
106
|
|
|
107
|
+
/**
|
|
108
|
+
* Call info extracted from CallExpression (REG-223)
|
|
109
|
+
*/
|
|
110
|
+
interface CallInfo {
|
|
111
|
+
line: number;
|
|
112
|
+
column: number;
|
|
113
|
+
name: string;
|
|
114
|
+
isMethodCall: boolean;
|
|
115
|
+
}
|
|
116
|
+
|
|
103
117
|
export class VariableVisitor extends ASTVisitor {
|
|
104
118
|
private extractVariableNamesFromPattern: ExtractVariableNamesCallback;
|
|
105
119
|
private trackVariableAssignment: TrackVariableAssignmentCallback;
|
|
106
120
|
private scopeTracker?: ScopeTracker;
|
|
107
121
|
|
|
122
|
+
/**
|
|
123
|
+
* Recursively unwrap AwaitExpression to get the underlying expression.
|
|
124
|
+
* await await fetch() -> fetch() (REG-223)
|
|
125
|
+
*/
|
|
126
|
+
private unwrapAwaitExpression(node: Node): Node {
|
|
127
|
+
if (node.type === 'AwaitExpression' && (node as { argument?: Node }).argument) {
|
|
128
|
+
return this.unwrapAwaitExpression((node as { argument: Node }).argument);
|
|
129
|
+
}
|
|
130
|
+
return node;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Check if expression is CallExpression or AwaitExpression wrapping a call. (REG-223)
|
|
135
|
+
*/
|
|
136
|
+
private isCallOrAwaitExpression(node: Node): boolean {
|
|
137
|
+
const unwrapped = this.unwrapAwaitExpression(node);
|
|
138
|
+
return unwrapped.type === 'CallExpression';
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Extract call site information from CallExpression. (REG-223)
|
|
143
|
+
* Returns null if not a valid CallExpression.
|
|
144
|
+
*/
|
|
145
|
+
private extractCallInfo(node: Node): CallInfo | null {
|
|
146
|
+
if (node.type !== 'CallExpression') {
|
|
147
|
+
return null;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const callExpr = node as { callee: Node; loc?: { start: { line: number; column: number } } };
|
|
151
|
+
const callee = callExpr.callee;
|
|
152
|
+
let name: string;
|
|
153
|
+
let isMethodCall = false;
|
|
154
|
+
|
|
155
|
+
// Direct call: fetchUser()
|
|
156
|
+
if (callee.type === 'Identifier') {
|
|
157
|
+
name = (callee as Identifier).name;
|
|
158
|
+
}
|
|
159
|
+
// Method call: obj.fetchUser() or arr.map()
|
|
160
|
+
else if (callee.type === 'MemberExpression') {
|
|
161
|
+
isMethodCall = true;
|
|
162
|
+
const memberExpr = callee as { object: Node; property: Node };
|
|
163
|
+
const objectName = memberExpr.object.type === 'Identifier'
|
|
164
|
+
? (memberExpr.object as Identifier).name
|
|
165
|
+
: (memberExpr.object.type === 'ThisExpression' ? 'this' : 'unknown');
|
|
166
|
+
const methodName = memberExpr.property.type === 'Identifier'
|
|
167
|
+
? (memberExpr.property as Identifier).name
|
|
168
|
+
: 'unknown';
|
|
169
|
+
name = `${objectName}.${methodName}`;
|
|
170
|
+
}
|
|
171
|
+
else {
|
|
172
|
+
return null;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
return {
|
|
176
|
+
line: callExpr.loc?.start.line ?? 0,
|
|
177
|
+
column: callExpr.loc?.start.column ?? 0,
|
|
178
|
+
name,
|
|
179
|
+
isMethodCall
|
|
180
|
+
};
|
|
181
|
+
}
|
|
182
|
+
|
|
108
183
|
/**
|
|
109
184
|
* @param module - Current module being analyzed
|
|
110
185
|
* @param collections - Must contain arrays and counter refs
|
|
@@ -131,13 +206,22 @@ export class VariableVisitor extends ASTVisitor {
|
|
|
131
206
|
const classInstantiations = this.collections.classInstantiations ?? [];
|
|
132
207
|
const literals = (this.collections.literals ?? []) as unknown[];
|
|
133
208
|
const variableAssignments = this.collections.variableAssignments ?? [];
|
|
209
|
+
const scopes = (this.collections.scopes ?? []) as unknown[];
|
|
134
210
|
const varDeclCounterRef = (this.collections.varDeclCounterRef ?? { value: 0 }) as CounterRef;
|
|
135
211
|
const literalCounterRef = (this.collections.literalCounterRef ?? { value: 0 }) as CounterRef;
|
|
212
|
+
const scopeCounterRef = (this.collections.scopeCounterRef ?? { value: 0 }) as CounterRef;
|
|
213
|
+
// Object literal tracking collections (REG-328)
|
|
214
|
+
const objectLiterals = (this.collections.objectLiterals ?? []) as unknown[];
|
|
215
|
+
const objectProperties = (this.collections.objectProperties ?? []) as unknown[];
|
|
216
|
+
const objectLiteralCounterRef = (this.collections.objectLiteralCounterRef ?? { value: 0 }) as CounterRef;
|
|
136
217
|
const scopeTracker = this.scopeTracker;
|
|
137
218
|
|
|
138
219
|
const extractVariableNamesFromPattern = this.extractVariableNamesFromPattern;
|
|
139
220
|
const trackVariableAssignment = this.trackVariableAssignment;
|
|
140
221
|
|
|
222
|
+
// Track which loops we've already created scopes for
|
|
223
|
+
const processedLoops = new Set<unknown>();
|
|
224
|
+
|
|
141
225
|
return {
|
|
142
226
|
VariableDeclaration: (path: NodePath) => {
|
|
143
227
|
// Only module-level variables
|
|
@@ -146,6 +230,41 @@ export class VariableVisitor extends ASTVisitor {
|
|
|
146
230
|
const varNode = path.node as VariableDeclaration;
|
|
147
231
|
const isConst = varNode.kind === 'const';
|
|
148
232
|
|
|
233
|
+
// Check if this is a loop variable (for...of or for...in)
|
|
234
|
+
const parent = path.parent;
|
|
235
|
+
const isLoopVariable = (parent.type === 'ForOfStatement' || parent.type === 'ForInStatement')
|
|
236
|
+
&& (parent as {left?: unknown}).left === varNode;
|
|
237
|
+
|
|
238
|
+
// If this is a loop variable, create the loop scope first (if not already created)
|
|
239
|
+
if (isLoopVariable && !processedLoops.has(parent)) {
|
|
240
|
+
processedLoops.add(parent);
|
|
241
|
+
|
|
242
|
+
const loopNode = parent as { type: string; loc?: { start: { line: number } } };
|
|
243
|
+
const line = loopNode.loc?.start.line ?? 0;
|
|
244
|
+
const scopeType = loopNode.type === 'ForOfStatement' ? 'for-of-loop' : 'for-in-loop';
|
|
245
|
+
const trackerType = loopNode.type === 'ForOfStatement' ? 'for-of' : 'for-in';
|
|
246
|
+
const scopeId = `SCOPE#${scopeType}#${module.file}#${line}:${scopeCounterRef.value++}`;
|
|
247
|
+
|
|
248
|
+
// Enter scope in tracker BEFORE generating semantic ID
|
|
249
|
+
if (scopeTracker) {
|
|
250
|
+
scopeTracker.enterCountedScope(trackerType);
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
const semanticId = scopeTracker
|
|
254
|
+
? scopeTracker.getContext().scopePath.join('->')
|
|
255
|
+
: scopeId;
|
|
256
|
+
|
|
257
|
+
(scopes as { id: string; type: string; scopeType: string; semanticId: string; file: string; line: number; parentScopeId: string }[]).push({
|
|
258
|
+
id: scopeId,
|
|
259
|
+
type: 'SCOPE',
|
|
260
|
+
scopeType,
|
|
261
|
+
semanticId,
|
|
262
|
+
file: module.file,
|
|
263
|
+
line,
|
|
264
|
+
parentScopeId: module.id
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
|
|
149
268
|
varNode.declarations.forEach((declarator: VariableDeclarator) => {
|
|
150
269
|
// Extract all variable names from the pattern (handles destructuring)
|
|
151
270
|
const variables = extractVariableNamesFromPattern(declarator.id);
|
|
@@ -155,9 +274,9 @@ export class VariableVisitor extends ASTVisitor {
|
|
|
155
274
|
const isLiteral = literalValue !== null;
|
|
156
275
|
const isNewExpression = declarator.init && declarator.init.type === 'NewExpression';
|
|
157
276
|
|
|
158
|
-
//
|
|
159
|
-
//
|
|
160
|
-
const shouldBeConstant = isConst && (isLiteral || isNewExpression);
|
|
277
|
+
// Loop variables with const should be CONSTANT (they can't be reassigned in loop body)
|
|
278
|
+
// Regular variables with const are CONSTANT only if initialized with literal or new expression
|
|
279
|
+
const shouldBeConstant = isConst && (isLoopVariable || isLiteral || isNewExpression);
|
|
161
280
|
|
|
162
281
|
const nodeType = shouldBeConstant ? 'CONSTANT' : 'VARIABLE';
|
|
163
282
|
|
|
@@ -215,67 +334,173 @@ export class VariableVisitor extends ASTVisitor {
|
|
|
215
334
|
}
|
|
216
335
|
|
|
217
336
|
// Track assignment for data flow analysis
|
|
218
|
-
|
|
337
|
+
// For loop variables, the "init" is the right side of for...of/for...in
|
|
338
|
+
const initExpression = isLoopVariable
|
|
339
|
+
? (parent as {right?: Node}).right
|
|
340
|
+
: declarator.init;
|
|
341
|
+
|
|
342
|
+
if (initExpression) {
|
|
343
|
+
// For loop variables, create DERIVES_FROM edges instead of ASSIGNED_FROM
|
|
344
|
+
// Loop variables derive their values from the collection (semantic difference)
|
|
345
|
+
if (isLoopVariable && initExpression.type === 'Identifier') {
|
|
346
|
+
const sourceName = (initExpression as Identifier).name;
|
|
347
|
+
(variableAssignments as unknown[]).push({
|
|
348
|
+
variableId: varId,
|
|
349
|
+
sourceType: 'DERIVES_FROM_VARIABLE',
|
|
350
|
+
sourceName,
|
|
351
|
+
file: module.file,
|
|
352
|
+
line: varInfo.loc.start.line
|
|
353
|
+
});
|
|
354
|
+
}
|
|
219
355
|
// Handle destructuring - create EXPRESSION for property path
|
|
220
|
-
if (varInfo.propertyPath || varInfo.arrayIndex !== undefined) {
|
|
221
|
-
//
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
let expressionPath = initName;
|
|
226
|
-
|
|
227
|
-
if (varInfo.propertyPath) {
|
|
228
|
-
expressionPath = `${initName}.${varInfo.propertyPath.join('.')}`;
|
|
229
|
-
} else if (varInfo.arrayIndex !== undefined) {
|
|
230
|
-
expressionPath = `${initName}[${varInfo.arrayIndex}]`;
|
|
231
|
-
}
|
|
356
|
+
else if (varInfo.propertyPath || varInfo.arrayIndex !== undefined || varInfo.isRest) {
|
|
357
|
+
// Phase 1: Simple Identifier init expressions (REG-201)
|
|
358
|
+
if (initExpression.type === 'Identifier') {
|
|
359
|
+
const sourceBaseName = (initExpression as Identifier).name;
|
|
360
|
+
const expressionLine = varInfo.loc.start.line;
|
|
232
361
|
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
362
|
+
// Handle rest elements specially - create edge to whole source
|
|
363
|
+
if (varInfo.isRest) {
|
|
364
|
+
(variableAssignments as unknown[]).push({
|
|
365
|
+
variableId: varId,
|
|
366
|
+
sourceType: 'VARIABLE',
|
|
367
|
+
sourceName: sourceBaseName,
|
|
368
|
+
line: expressionLine
|
|
369
|
+
});
|
|
370
|
+
return;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
const expressionColumn = varInfo.loc.start.column;
|
|
374
|
+
|
|
375
|
+
// Build property path string
|
|
376
|
+
let fullPath = sourceBaseName;
|
|
377
|
+
if (varInfo.propertyPath && varInfo.propertyPath.length > 0) {
|
|
378
|
+
fullPath = `${sourceBaseName}.${varInfo.propertyPath.join('.')}`;
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
// Generate expression ID (matches GraphBuilder expectations)
|
|
382
|
+
const expressionId = `${module.file}:EXPRESSION:MemberExpression:${expressionLine}:${expressionColumn}`;
|
|
383
|
+
|
|
384
|
+
// Determine property for display
|
|
385
|
+
let property: string;
|
|
386
|
+
if (varInfo.propertyPath && varInfo.propertyPath.length > 0) {
|
|
387
|
+
property = varInfo.propertyPath[varInfo.propertyPath.length - 1];
|
|
388
|
+
} else if (varInfo.arrayIndex !== undefined) {
|
|
389
|
+
property = String(varInfo.arrayIndex);
|
|
390
|
+
} else {
|
|
391
|
+
property = '';
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
// Push assignment with full metadata for GraphBuilder (REG-201)
|
|
395
|
+
// GraphBuilder will create the EXPRESSION node from this metadata
|
|
396
|
+
(variableAssignments as unknown[]).push({
|
|
397
|
+
variableId: varId,
|
|
398
|
+
sourceId: expressionId,
|
|
399
|
+
sourceType: 'EXPRESSION',
|
|
400
|
+
expressionType: 'MemberExpression',
|
|
401
|
+
object: sourceBaseName,
|
|
402
|
+
property: property,
|
|
403
|
+
computed: varInfo.arrayIndex !== undefined,
|
|
404
|
+
path: fullPath,
|
|
405
|
+
objectSourceName: sourceBaseName, // Use objectSourceName for DERIVES_FROM edge creation
|
|
243
406
|
propertyPath: varInfo.propertyPath || undefined,
|
|
244
|
-
arrayIndex: varInfo.arrayIndex
|
|
407
|
+
arrayIndex: varInfo.arrayIndex,
|
|
408
|
+
file: module.file,
|
|
409
|
+
line: expressionLine,
|
|
410
|
+
column: expressionColumn
|
|
411
|
+
});
|
|
412
|
+
}
|
|
413
|
+
// Phase 2: CallExpression or AwaitExpression (REG-223)
|
|
414
|
+
else if (this.isCallOrAwaitExpression(initExpression)) {
|
|
415
|
+
const unwrapped = this.unwrapAwaitExpression(initExpression);
|
|
416
|
+
const callInfo = this.extractCallInfo(unwrapped);
|
|
417
|
+
|
|
418
|
+
if (!callInfo) {
|
|
419
|
+
// Unsupported call pattern (computed callee, etc.)
|
|
420
|
+
return;
|
|
245
421
|
}
|
|
246
|
-
);
|
|
247
422
|
|
|
248
|
-
|
|
249
|
-
|
|
423
|
+
const callRepresentation = `${callInfo.name}()`;
|
|
424
|
+
const expressionLine = varInfo.loc.start.line;
|
|
425
|
+
const expressionColumn = varInfo.loc.start.column;
|
|
250
426
|
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
427
|
+
// Handle rest elements - create direct CALL_SITE assignment
|
|
428
|
+
if (varInfo.isRest) {
|
|
429
|
+
(variableAssignments as unknown[]).push({
|
|
430
|
+
variableId: varId,
|
|
431
|
+
sourceType: 'CALL_SITE',
|
|
432
|
+
callName: callInfo.name,
|
|
433
|
+
callLine: callInfo.line,
|
|
434
|
+
callColumn: callInfo.column,
|
|
435
|
+
callSourceLine: callInfo.line,
|
|
436
|
+
callSourceColumn: callInfo.column,
|
|
437
|
+
callSourceFile: module.file,
|
|
438
|
+
callSourceName: callInfo.name,
|
|
439
|
+
line: expressionLine
|
|
440
|
+
});
|
|
441
|
+
return;
|
|
442
|
+
}
|
|
257
443
|
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
444
|
+
// Generate expression ID (matches GraphBuilder expectations)
|
|
445
|
+
const expressionId = `${module.file}:EXPRESSION:MemberExpression:${expressionLine}:${expressionColumn}`;
|
|
446
|
+
|
|
447
|
+
// Determine property for display
|
|
448
|
+
let property: string;
|
|
449
|
+
if (varInfo.propertyPath && varInfo.propertyPath.length > 0) {
|
|
450
|
+
property = varInfo.propertyPath[varInfo.propertyPath.length - 1];
|
|
451
|
+
} else if (varInfo.arrayIndex !== undefined) {
|
|
452
|
+
property = String(varInfo.arrayIndex);
|
|
453
|
+
} else {
|
|
454
|
+
property = '';
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
// Build property path string: "fetchUser().data" or "fetchUser().user.name"
|
|
458
|
+
let fullPath = callRepresentation;
|
|
459
|
+
if (varInfo.propertyPath && varInfo.propertyPath.length > 0) {
|
|
460
|
+
fullPath = `${callRepresentation}.${varInfo.propertyPath.join('.')}`;
|
|
461
|
+
}
|
|
462
|
+
|
|
463
|
+
// Push assignment with call source metadata for GraphBuilder (REG-223)
|
|
464
|
+
(variableAssignments as unknown[]).push({
|
|
465
|
+
variableId: varId,
|
|
466
|
+
sourceId: expressionId,
|
|
467
|
+
sourceType: 'EXPRESSION',
|
|
468
|
+
expressionType: 'MemberExpression',
|
|
469
|
+
object: callRepresentation, // "fetchUser()" - display name
|
|
470
|
+
property: property,
|
|
471
|
+
computed: varInfo.arrayIndex !== undefined,
|
|
472
|
+
path: fullPath,
|
|
473
|
+
propertyPath: varInfo.propertyPath || undefined,
|
|
474
|
+
arrayIndex: varInfo.arrayIndex,
|
|
475
|
+
// Call source for DERIVES_FROM lookup (REG-223)
|
|
476
|
+
callSourceLine: callInfo.line,
|
|
477
|
+
callSourceColumn: callInfo.column,
|
|
478
|
+
callSourceFile: module.file,
|
|
479
|
+
callSourceName: callInfo.name,
|
|
480
|
+
sourceMetadata: {
|
|
481
|
+
sourceType: callInfo.isMethodCall ? 'method-call' : 'call'
|
|
482
|
+
},
|
|
483
|
+
file: module.file,
|
|
484
|
+
line: expressionLine,
|
|
485
|
+
column: expressionColumn
|
|
266
486
|
});
|
|
267
487
|
}
|
|
488
|
+
// Unsupported init type (MemberExpression without call, etc.)
|
|
489
|
+
// Skip silently
|
|
268
490
|
} else {
|
|
269
491
|
// Normal assignment tracking
|
|
270
492
|
trackVariableAssignment(
|
|
271
|
-
|
|
493
|
+
initExpression,
|
|
272
494
|
varId,
|
|
273
495
|
varInfo.name,
|
|
274
496
|
module,
|
|
275
497
|
varInfo.loc.start.line,
|
|
276
498
|
literals,
|
|
277
499
|
variableAssignments,
|
|
278
|
-
literalCounterRef as CounterRef
|
|
500
|
+
literalCounterRef as CounterRef,
|
|
501
|
+
objectLiterals,
|
|
502
|
+
objectProperties,
|
|
503
|
+
objectLiteralCounterRef
|
|
279
504
|
);
|
|
280
505
|
}
|
|
281
506
|
}
|
|
@@ -10,6 +10,8 @@
|
|
|
10
10
|
* - lerna.json
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
+
import { join } from 'path';
|
|
14
|
+
|
|
13
15
|
import { DiscoveryPlugin } from './DiscoveryPlugin.js';
|
|
14
16
|
import { createSuccessResult, createErrorResult } from '../Plugin.js';
|
|
15
17
|
import type { PluginContext, PluginResult, PluginMetadata } from '../Plugin.js';
|
|
@@ -124,7 +126,7 @@ export class WorkspaceDiscovery extends DiscoveryPlugin {
|
|
|
124
126
|
metadata: {
|
|
125
127
|
workspaceType: detection.type!,
|
|
126
128
|
relativePath: pkg.relativePath,
|
|
127
|
-
entrypoint: serviceNode.entrypoint,
|
|
129
|
+
entrypoint: (serviceNode.metadata?.entrypoint as string | null) ?? null,
|
|
128
130
|
packageJson: pkg.packageJson as Record<string, unknown>
|
|
129
131
|
}
|
|
130
132
|
});
|
|
@@ -146,13 +148,18 @@ export class WorkspaceDiscovery extends DiscoveryPlugin {
|
|
|
146
148
|
*/
|
|
147
149
|
private createServiceNode(pkg: WorkspacePackage, workspaceType: string, _projectPath: string) {
|
|
148
150
|
// Resolve entrypoint (prefer TypeScript source)
|
|
149
|
-
const
|
|
151
|
+
const relativeEntrypoint = resolveSourceEntrypoint(pkg.path, pkg.packageJson)
|
|
150
152
|
?? (pkg.packageJson.main as string | undefined)
|
|
151
153
|
?? null;
|
|
152
154
|
|
|
155
|
+
// Convert to absolute path (REG-247: JSModuleIndexer expects absolute paths)
|
|
156
|
+
const absoluteEntrypoint = relativeEntrypoint
|
|
157
|
+
? join(pkg.path, relativeEntrypoint)
|
|
158
|
+
: null;
|
|
159
|
+
|
|
153
160
|
const serviceNode = NodeFactory.createService(pkg.name, pkg.path, {
|
|
154
161
|
discoveryMethod: 'workspace',
|
|
155
|
-
entrypoint:
|
|
162
|
+
entrypoint: absoluteEntrypoint ?? undefined,
|
|
156
163
|
version: pkg.packageJson.version as string | undefined,
|
|
157
164
|
description: pkg.packageJson.description as string | undefined,
|
|
158
165
|
dependencies: Object.keys(pkg.packageJson.dependencies || {})
|
|
@@ -169,7 +176,7 @@ export class WorkspaceDiscovery extends DiscoveryPlugin {
|
|
|
169
176
|
description: pkg.packageJson.description as string | undefined,
|
|
170
177
|
private: pkg.packageJson.private as boolean | undefined,
|
|
171
178
|
dependencies: Object.keys(pkg.packageJson.dependencies || {}),
|
|
172
|
-
entrypoint:
|
|
179
|
+
entrypoint: absoluteEntrypoint
|
|
173
180
|
};
|
|
174
181
|
|
|
175
182
|
return nodeWithMetadata;
|
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
import { Plugin, createSuccessResult } from '../Plugin.js';
|
|
17
17
|
import type { PluginContext, PluginResult, PluginMetadata } from '../Plugin.js';
|
|
18
18
|
import type { BaseNodeRecord, NodeRecord } from '@grafema/types';
|
|
19
|
+
import { StrictModeError } from '../../errors/GrafemaError.js';
|
|
19
20
|
|
|
20
21
|
/**
|
|
21
22
|
* Alias info from index
|
|
@@ -88,6 +89,7 @@ export class AliasTracker extends Plugin {
|
|
|
88
89
|
let aliasesFound = 0;
|
|
89
90
|
let edgesCreated = 0;
|
|
90
91
|
let resolvedToMethod = 0;
|
|
92
|
+
const errors: Error[] = [];
|
|
91
93
|
|
|
92
94
|
// Трекинг превышений глубины
|
|
93
95
|
this.depthExceeded = [];
|
|
@@ -192,11 +194,30 @@ export class AliasTracker extends Plugin {
|
|
|
192
194
|
chain: info.chain.join(' → ')
|
|
193
195
|
}))
|
|
194
196
|
});
|
|
197
|
+
|
|
198
|
+
// In strict mode, report as errors
|
|
199
|
+
if (context.strictMode) {
|
|
200
|
+
for (const info of this.depthExceeded) {
|
|
201
|
+
const error = new StrictModeError(
|
|
202
|
+
`Alias chain exceeded max depth (${info.depth}): ${info.name}`,
|
|
203
|
+
'STRICT_ALIAS_DEPTH_EXCEEDED',
|
|
204
|
+
{
|
|
205
|
+
filePath: info.file,
|
|
206
|
+
phase: 'ENRICHMENT',
|
|
207
|
+
plugin: 'AliasTracker',
|
|
208
|
+
aliasName: info.name,
|
|
209
|
+
chainLength: info.depth,
|
|
210
|
+
},
|
|
211
|
+
`Possible circular alias reference. Chain: ${info.chain.slice(0, 3).join(' -> ')}...`
|
|
212
|
+
);
|
|
213
|
+
errors.push(error);
|
|
214
|
+
}
|
|
215
|
+
}
|
|
195
216
|
}
|
|
196
217
|
|
|
197
218
|
logger.info('Summary', summary);
|
|
198
219
|
|
|
199
|
-
return createSuccessResult({ nodes: 0, edges: edgesCreated }, summary);
|
|
220
|
+
return createSuccessResult({ nodes: 0, edges: edgesCreated }, summary, errors);
|
|
200
221
|
}
|
|
201
222
|
|
|
202
223
|
/**
|