@grafema/util 0.3.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/LICENSE +190 -0
- package/dist/api/GraphAPI.d.ts +87 -0
- package/dist/api/GraphAPI.d.ts.map +1 -0
- package/dist/api/GraphAPI.js +212 -0
- package/dist/api/GraphAPI.js.map +1 -0
- package/dist/api/GuaranteeAPI.d.ts +147 -0
- package/dist/api/GuaranteeAPI.d.ts.map +1 -0
- package/dist/api/GuaranteeAPI.js +290 -0
- package/dist/api/GuaranteeAPI.js.map +1 -0
- package/dist/config/ConfigLoader.d.ts +214 -0
- package/dist/config/ConfigLoader.d.ts.map +1 -0
- package/dist/config/ConfigLoader.js +441 -0
- package/dist/config/ConfigLoader.js.map +1 -0
- package/dist/config/index.d.ts +6 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +5 -0
- package/dist/config/index.js.map +1 -0
- package/dist/core/CoverageAnalyzer.d.ts +65 -0
- package/dist/core/CoverageAnalyzer.d.ts.map +1 -0
- package/dist/core/CoverageAnalyzer.js +199 -0
- package/dist/core/CoverageAnalyzer.js.map +1 -0
- package/dist/core/FileExplainer.d.ts +101 -0
- package/dist/core/FileExplainer.d.ts.map +1 -0
- package/dist/core/FileExplainer.js +140 -0
- package/dist/core/FileExplainer.js.map +1 -0
- package/dist/core/FileOverview.d.ts +124 -0
- package/dist/core/FileOverview.d.ts.map +1 -0
- package/dist/core/FileOverview.js +279 -0
- package/dist/core/FileOverview.js.map +1 -0
- package/dist/core/GrafemaUri.d.ts +66 -0
- package/dist/core/GrafemaUri.d.ts.map +1 -0
- package/dist/core/GrafemaUri.js +191 -0
- package/dist/core/GrafemaUri.js.map +1 -0
- package/dist/core/GraphBackend.d.ts +158 -0
- package/dist/core/GraphBackend.d.ts.map +1 -0
- package/dist/core/GraphBackend.js +85 -0
- package/dist/core/GraphBackend.js.map +1 -0
- package/dist/core/GraphFreshnessChecker.d.ts +33 -0
- package/dist/core/GraphFreshnessChecker.d.ts.map +1 -0
- package/dist/core/GraphFreshnessChecker.js +104 -0
- package/dist/core/GraphFreshnessChecker.js.map +1 -0
- package/dist/core/GuaranteeManager.d.ts +254 -0
- package/dist/core/GuaranteeManager.d.ts.map +1 -0
- package/dist/core/GuaranteeManager.js +447 -0
- package/dist/core/GuaranteeManager.js.map +1 -0
- package/dist/core/HashUtils.d.ts +24 -0
- package/dist/core/HashUtils.d.ts.map +1 -0
- package/dist/core/HashUtils.js +46 -0
- package/dist/core/HashUtils.js.map +1 -0
- package/dist/core/IncrementalReanalyzer.d.ts +33 -0
- package/dist/core/IncrementalReanalyzer.d.ts.map +1 -0
- package/dist/core/IncrementalReanalyzer.js +67 -0
- package/dist/core/IncrementalReanalyzer.js.map +1 -0
- package/dist/core/ResourceRegistry.d.ts +17 -0
- package/dist/core/ResourceRegistry.d.ts.map +1 -0
- package/dist/core/ResourceRegistry.js +32 -0
- package/dist/core/ResourceRegistry.js.map +1 -0
- package/dist/core/SemanticId.d.ts +159 -0
- package/dist/core/SemanticId.d.ts.map +1 -0
- package/dist/core/SemanticId.js +291 -0
- package/dist/core/SemanticId.js.map +1 -0
- package/dist/core/VersionManager.d.ts +166 -0
- package/dist/core/VersionManager.d.ts.map +1 -0
- package/dist/core/VersionManager.js +239 -0
- package/dist/core/VersionManager.js.map +1 -0
- package/dist/core/brandNodeInternal.d.ts +14 -0
- package/dist/core/brandNodeInternal.d.ts.map +1 -0
- package/dist/core/brandNodeInternal.js +4 -0
- package/dist/core/brandNodeInternal.js.map +1 -0
- package/dist/core/nodes/GuaranteeNode.d.ts +76 -0
- package/dist/core/nodes/GuaranteeNode.d.ts.map +1 -0
- package/dist/core/nodes/GuaranteeNode.js +118 -0
- package/dist/core/nodes/GuaranteeNode.js.map +1 -0
- package/dist/core/nodes/IssueNode.d.ts +73 -0
- package/dist/core/nodes/IssueNode.d.ts.map +1 -0
- package/dist/core/nodes/IssueNode.js +130 -0
- package/dist/core/nodes/IssueNode.js.map +1 -0
- package/dist/core/nodes/NodeKind.d.ts +104 -0
- package/dist/core/nodes/NodeKind.d.ts.map +1 -0
- package/dist/core/nodes/NodeKind.js +166 -0
- package/dist/core/nodes/NodeKind.js.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts +103 -0
- package/dist/diagnostics/DiagnosticCollector.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticCollector.js +133 -0
- package/dist/diagnostics/DiagnosticCollector.js.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts +122 -0
- package/dist/diagnostics/DiagnosticReporter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticReporter.js +300 -0
- package/dist/diagnostics/DiagnosticReporter.js.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts +31 -0
- package/dist/diagnostics/DiagnosticWriter.d.ts.map +1 -0
- package/dist/diagnostics/DiagnosticWriter.js +44 -0
- package/dist/diagnostics/DiagnosticWriter.js.map +1 -0
- package/dist/diagnostics/categories.d.ts +57 -0
- package/dist/diagnostics/categories.d.ts.map +1 -0
- package/dist/diagnostics/categories.js +71 -0
- package/dist/diagnostics/categories.js.map +1 -0
- package/dist/diagnostics/index.d.ts +17 -0
- package/dist/diagnostics/index.d.ts.map +1 -0
- package/dist/diagnostics/index.js +15 -0
- package/dist/diagnostics/index.js.map +1 -0
- package/dist/errors/GrafemaError.d.ts +200 -0
- package/dist/errors/GrafemaError.d.ts.map +1 -0
- package/dist/errors/GrafemaError.js +209 -0
- package/dist/errors/GrafemaError.js.map +1 -0
- package/dist/index.d.ts +75 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +76 -0
- package/dist/index.js.map +1 -0
- package/dist/instructions/index.d.ts +8 -0
- package/dist/instructions/index.d.ts.map +1 -0
- package/dist/instructions/index.js +20 -0
- package/dist/instructions/index.js.map +1 -0
- package/dist/instructions/onboarding.md +133 -0
- package/dist/knowledge/KnowledgeBase.d.ts +113 -0
- package/dist/knowledge/KnowledgeBase.d.ts.map +1 -0
- package/dist/knowledge/KnowledgeBase.js +420 -0
- package/dist/knowledge/KnowledgeBase.js.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts +59 -0
- package/dist/knowledge/SemanticAddressResolver.d.ts.map +1 -0
- package/dist/knowledge/SemanticAddressResolver.js +160 -0
- package/dist/knowledge/SemanticAddressResolver.js.map +1 -0
- package/dist/knowledge/git-ingest.d.ts +58 -0
- package/dist/knowledge/git-ingest.d.ts.map +1 -0
- package/dist/knowledge/git-ingest.js +301 -0
- package/dist/knowledge/git-ingest.js.map +1 -0
- package/dist/knowledge/git-queries.d.ts +86 -0
- package/dist/knowledge/git-queries.d.ts.map +1 -0
- package/dist/knowledge/git-queries.js +177 -0
- package/dist/knowledge/git-queries.js.map +1 -0
- package/dist/knowledge/index.d.ts +14 -0
- package/dist/knowledge/index.d.ts.map +1 -0
- package/dist/knowledge/index.js +10 -0
- package/dist/knowledge/index.js.map +1 -0
- package/dist/knowledge/parser.d.ts +39 -0
- package/dist/knowledge/parser.d.ts.map +1 -0
- package/dist/knowledge/parser.js +292 -0
- package/dist/knowledge/parser.js.map +1 -0
- package/dist/knowledge/types.d.ts +133 -0
- package/dist/knowledge/types.d.ts.map +1 -0
- package/dist/knowledge/types.js +8 -0
- package/dist/knowledge/types.js.map +1 -0
- package/dist/logging/Logger.d.ts +98 -0
- package/dist/logging/Logger.d.ts.map +1 -0
- package/dist/logging/Logger.js +274 -0
- package/dist/logging/Logger.js.map +1 -0
- package/dist/notation/archetypes.d.ts +36 -0
- package/dist/notation/archetypes.d.ts.map +1 -0
- package/dist/notation/archetypes.js +173 -0
- package/dist/notation/archetypes.js.map +1 -0
- package/dist/notation/fold.d.ts +25 -0
- package/dist/notation/fold.d.ts.map +1 -0
- package/dist/notation/fold.js +598 -0
- package/dist/notation/fold.js.map +1 -0
- package/dist/notation/index.d.ts +18 -0
- package/dist/notation/index.d.ts.map +1 -0
- package/dist/notation/index.js +16 -0
- package/dist/notation/index.js.map +1 -0
- package/dist/notation/lodExtractor.d.ts +32 -0
- package/dist/notation/lodExtractor.d.ts.map +1 -0
- package/dist/notation/lodExtractor.js +149 -0
- package/dist/notation/lodExtractor.js.map +1 -0
- package/dist/notation/nameShortener.d.ts +22 -0
- package/dist/notation/nameShortener.d.ts.map +1 -0
- package/dist/notation/nameShortener.js +24 -0
- package/dist/notation/nameShortener.js.map +1 -0
- package/dist/notation/perspectives.d.ts +11 -0
- package/dist/notation/perspectives.d.ts.map +1 -0
- package/dist/notation/perspectives.js +16 -0
- package/dist/notation/perspectives.js.map +1 -0
- package/dist/notation/renderer.d.ts +31 -0
- package/dist/notation/renderer.d.ts.map +1 -0
- package/dist/notation/renderer.js +315 -0
- package/dist/notation/renderer.js.map +1 -0
- package/dist/notation/traceRenderer.d.ts +39 -0
- package/dist/notation/traceRenderer.d.ts.map +1 -0
- package/dist/notation/traceRenderer.js +358 -0
- package/dist/notation/traceRenderer.js.map +1 -0
- package/dist/notation/types.d.ts +66 -0
- package/dist/notation/types.d.ts.map +1 -0
- package/dist/notation/types.js +10 -0
- package/dist/notation/types.js.map +1 -0
- package/dist/queries/NodeContext.d.ts +81 -0
- package/dist/queries/NodeContext.d.ts.map +1 -0
- package/dist/queries/NodeContext.js +196 -0
- package/dist/queries/NodeContext.js.map +1 -0
- package/dist/queries/findCallsInFunction.d.ts +62 -0
- package/dist/queries/findCallsInFunction.d.ts.map +1 -0
- package/dist/queries/findCallsInFunction.js +169 -0
- package/dist/queries/findCallsInFunction.js.map +1 -0
- package/dist/queries/findContainingFunction.d.ts +57 -0
- package/dist/queries/findContainingFunction.d.ts.map +1 -0
- package/dist/queries/findContainingFunction.js +91 -0
- package/dist/queries/findContainingFunction.js.map +1 -0
- package/dist/queries/index.d.ts +18 -0
- package/dist/queries/index.d.ts.map +1 -0
- package/dist/queries/index.js +14 -0
- package/dist/queries/index.js.map +1 -0
- package/dist/queries/traceDataflow.d.ts +65 -0
- package/dist/queries/traceDataflow.d.ts.map +1 -0
- package/dist/queries/traceDataflow.js +754 -0
- package/dist/queries/traceDataflow.js.map +1 -0
- package/dist/queries/traceValues.d.ts +70 -0
- package/dist/queries/traceValues.d.ts.map +1 -0
- package/dist/queries/traceValues.js +373 -0
- package/dist/queries/traceValues.js.map +1 -0
- package/dist/queries/types.d.ts +166 -0
- package/dist/queries/types.d.ts.map +1 -0
- package/dist/queries/types.js +10 -0
- package/dist/queries/types.js.map +1 -0
- package/dist/schema/GraphSchemaExtractor.d.ts +53 -0
- package/dist/schema/GraphSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/GraphSchemaExtractor.js +125 -0
- package/dist/schema/GraphSchemaExtractor.js.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts +73 -0
- package/dist/schema/InterfaceSchemaExtractor.d.ts.map +1 -0
- package/dist/schema/InterfaceSchemaExtractor.js +113 -0
- package/dist/schema/InterfaceSchemaExtractor.js.map +1 -0
- package/dist/schema/index.d.ts +5 -0
- package/dist/schema/index.d.ts.map +1 -0
- package/dist/schema/index.js +3 -0
- package/dist/schema/index.js.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts +356 -0
- package/dist/storage/backends/RFDBServerBackend.d.ts.map +1 -0
- package/dist/storage/backends/RFDBServerBackend.js +748 -0
- package/dist/storage/backends/RFDBServerBackend.js.map +1 -0
- package/dist/storage/backends/typeValidation.d.ts +47 -0
- package/dist/storage/backends/typeValidation.d.ts.map +1 -0
- package/dist/storage/backends/typeValidation.js +141 -0
- package/dist/storage/backends/typeValidation.js.map +1 -0
- package/dist/utils/findRfdbBinary.d.ts +67 -0
- package/dist/utils/findRfdbBinary.d.ts.map +1 -0
- package/dist/utils/findRfdbBinary.js +261 -0
- package/dist/utils/findRfdbBinary.js.map +1 -0
- package/dist/utils/lazyDownload.d.ts +43 -0
- package/dist/utils/lazyDownload.d.ts.map +1 -0
- package/dist/utils/lazyDownload.js +175 -0
- package/dist/utils/lazyDownload.js.map +1 -0
- package/dist/utils/moduleResolution.d.ts +134 -0
- package/dist/utils/moduleResolution.d.ts.map +1 -0
- package/dist/utils/moduleResolution.js +189 -0
- package/dist/utils/moduleResolution.js.map +1 -0
- package/dist/utils/resolveNodeFile.d.ts +13 -0
- package/dist/utils/resolveNodeFile.d.ts.map +1 -0
- package/dist/utils/resolveNodeFile.js +18 -0
- package/dist/utils/resolveNodeFile.js.map +1 -0
- package/dist/utils/startRfdbServer.d.ts +63 -0
- package/dist/utils/startRfdbServer.d.ts.map +1 -0
- package/dist/utils/startRfdbServer.js +142 -0
- package/dist/utils/startRfdbServer.js.map +1 -0
- package/dist/validation/PathValidator.d.ts +80 -0
- package/dist/validation/PathValidator.d.ts.map +1 -0
- package/dist/validation/PathValidator.js +252 -0
- package/dist/validation/PathValidator.js.map +1 -0
- package/dist/version.d.ts +11 -0
- package/dist/version.d.ts.map +1 -0
- package/dist/version.js +26 -0
- package/dist/version.js.map +1 -0
- package/package.json +50 -0
- package/src/api/GraphAPI.ts +307 -0
- package/src/api/GuaranteeAPI.ts +402 -0
- package/src/config/ConfigLoader.ts +653 -0
- package/src/config/index.ts +13 -0
- package/src/core/CoverageAnalyzer.ts +243 -0
- package/src/core/FileExplainer.ts +179 -0
- package/src/core/FileOverview.ts +397 -0
- package/src/core/GrafemaUri.ts +216 -0
- package/src/core/GraphBackend.ts +266 -0
- package/src/core/GraphFreshnessChecker.ts +145 -0
- package/src/core/GuaranteeManager.ts +684 -0
- package/src/core/HashUtils.ts +48 -0
- package/src/core/IncrementalReanalyzer.ts +106 -0
- package/src/core/ResourceRegistry.ts +39 -0
- package/src/core/SemanticId.ts +423 -0
- package/src/core/VersionManager.ts +405 -0
- package/src/core/brandNodeInternal.ts +16 -0
- package/src/core/nodes/GuaranteeNode.ts +162 -0
- package/src/core/nodes/IssueNode.ts +177 -0
- package/src/core/nodes/NodeKind.ts +192 -0
- package/src/diagnostics/DiagnosticCollector.ts +170 -0
- package/src/diagnostics/DiagnosticReporter.ts +395 -0
- package/src/diagnostics/DiagnosticWriter.ts +50 -0
- package/src/diagnostics/categories.ts +104 -0
- package/src/diagnostics/index.ts +30 -0
- package/src/errors/GrafemaError.ts +297 -0
- package/src/index.ts +261 -0
- package/src/instructions/index.ts +21 -0
- package/src/instructions/onboarding.md +133 -0
- package/src/knowledge/KnowledgeBase.ts +486 -0
- package/src/knowledge/SemanticAddressResolver.ts +191 -0
- package/src/knowledge/git-ingest.ts +402 -0
- package/src/knowledge/git-queries.ts +269 -0
- package/src/knowledge/index.ts +29 -0
- package/src/knowledge/parser.ts +294 -0
- package/src/knowledge/types.ts +146 -0
- package/src/logging/Logger.ts +303 -0
- package/src/notation/archetypes.ts +189 -0
- package/src/notation/fold.ts +696 -0
- package/src/notation/index.ts +27 -0
- package/src/notation/lodExtractor.ts +177 -0
- package/src/notation/nameShortener.ts +24 -0
- package/src/notation/perspectives.ts +18 -0
- package/src/notation/renderer.ts +394 -0
- package/src/notation/traceRenderer.ts +458 -0
- package/src/notation/types.ts +79 -0
- package/src/queries/NodeContext.ts +280 -0
- package/src/queries/findCallsInFunction.ts +249 -0
- package/src/queries/findContainingFunction.ts +124 -0
- package/src/queries/index.ts +44 -0
- package/src/queries/traceDataflow.ts +838 -0
- package/src/queries/traceValues.ts +531 -0
- package/src/queries/types.ts +191 -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 +895 -0
- package/src/storage/backends/typeValidation.ts +154 -0
- package/src/utils/findRfdbBinary.ts +288 -0
- package/src/utils/lazyDownload.ts +206 -0
- package/src/utils/moduleResolution.ts +271 -0
- package/src/utils/resolveNodeFile.ts +18 -0
- package/src/utils/startRfdbServer.ts +197 -0
- package/src/validation/PathValidator.ts +334 -0
- package/src/version.ts +28 -0
|
@@ -0,0 +1,271 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Module Resolution Utilities (REG-320)
|
|
3
|
+
*
|
|
4
|
+
* Unified module path resolution logic extracted from:
|
|
5
|
+
* - MountPointResolver.resolveImportSource()
|
|
6
|
+
* - JSModuleIndexer.resolveModulePath()
|
|
7
|
+
* - FunctionCallResolver._resolveImportPath()
|
|
8
|
+
* - IncrementalModuleIndexer.tryResolve()
|
|
9
|
+
*
|
|
10
|
+
* Provides consistent module resolution across all plugins.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { existsSync, statSync } from 'fs';
|
|
14
|
+
import { dirname, extname, resolve, join } from 'path';
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Default file extensions to try when resolving modules.
|
|
18
|
+
* Order: exact match first, then JS variants, then TS variants.
|
|
19
|
+
*/
|
|
20
|
+
export const DEFAULT_EXTENSIONS = ['', '.js', '.mjs', '.cjs', '.jsx', '.ts', '.tsx'];
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* TypeScript extension redirects (REG-426).
|
|
24
|
+
* Maps JS-family extensions to their TS equivalents.
|
|
25
|
+
* Used when an import specifies a .js extension but only a .ts file exists.
|
|
26
|
+
* This matches TypeScript's own module resolution behavior for ESM.
|
|
27
|
+
*/
|
|
28
|
+
const TS_EXTENSION_REDIRECTS: Record<string, string[]> = {
|
|
29
|
+
'.js': ['.ts', '.tsx'],
|
|
30
|
+
'.jsx': ['.tsx'],
|
|
31
|
+
'.mjs': ['.mts'],
|
|
32
|
+
'.cjs': ['.cts'],
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Default index files to try when resolving directory imports.
|
|
37
|
+
* Order: JS variants first (most common), then TS variants.
|
|
38
|
+
*/
|
|
39
|
+
export const DEFAULT_INDEX_FILES = [
|
|
40
|
+
'index.js',
|
|
41
|
+
'index.ts',
|
|
42
|
+
'index.mjs',
|
|
43
|
+
'index.cjs',
|
|
44
|
+
'index.jsx',
|
|
45
|
+
'index.tsx'
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Options for module path resolution.
|
|
50
|
+
*
|
|
51
|
+
* @example Filesystem mode (default)
|
|
52
|
+
* ```ts
|
|
53
|
+
* resolveModulePath('/app/utils')
|
|
54
|
+
* // → '/app/utils.js' if exists
|
|
55
|
+
* ```
|
|
56
|
+
*
|
|
57
|
+
* @example In-memory mode (for enrichment plugins)
|
|
58
|
+
* ```ts
|
|
59
|
+
* resolveModulePath('/app/utils', {
|
|
60
|
+
* useFilesystem: false,
|
|
61
|
+
* fileIndex: new Set(['/app/utils.ts'])
|
|
62
|
+
* })
|
|
63
|
+
* // → '/app/utils.ts'
|
|
64
|
+
* ```
|
|
65
|
+
*/
|
|
66
|
+
export interface ModuleResolutionOptions {
|
|
67
|
+
/**
|
|
68
|
+
* Use filesystem for path verification.
|
|
69
|
+
* Default: true
|
|
70
|
+
*
|
|
71
|
+
* When true: uses existsSync() to check if files exist
|
|
72
|
+
* When false: uses fileIndex.has() for lookup
|
|
73
|
+
*
|
|
74
|
+
* Performance note: For high-frequency calls during enrichment,
|
|
75
|
+
* use in-memory mode (useFilesystem: false) with a pre-built fileIndex.
|
|
76
|
+
* For indexing phase, filesystem mode is acceptable.
|
|
77
|
+
*/
|
|
78
|
+
useFilesystem?: boolean;
|
|
79
|
+
|
|
80
|
+
/**
|
|
81
|
+
* Pre-built set of known file paths.
|
|
82
|
+
* Required when useFilesystem=false.
|
|
83
|
+
*
|
|
84
|
+
* Throws Error if useFilesystem=false and fileIndex is not provided.
|
|
85
|
+
*/
|
|
86
|
+
fileIndex?: Set<string> | null;
|
|
87
|
+
|
|
88
|
+
/**
|
|
89
|
+
* Extensions to try (in order).
|
|
90
|
+
* Default: ['', '.js', '.mjs', '.cjs', '.jsx', '.ts', '.tsx']
|
|
91
|
+
*
|
|
92
|
+
* Empty string '' means try exact path first.
|
|
93
|
+
*/
|
|
94
|
+
extensions?: string[];
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Index files to try (in order).
|
|
98
|
+
* Default: ['index.js', 'index.ts', 'index.mjs', 'index.cjs', 'index.jsx', 'index.tsx']
|
|
99
|
+
*/
|
|
100
|
+
indexFiles?: string[];
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
/**
|
|
104
|
+
* Check if path exists using the configured method.
|
|
105
|
+
*/
|
|
106
|
+
function pathExists(
|
|
107
|
+
testPath: string,
|
|
108
|
+
useFilesystem: boolean,
|
|
109
|
+
fileIndex?: Set<string> | null
|
|
110
|
+
): boolean {
|
|
111
|
+
if (useFilesystem) {
|
|
112
|
+
return existsSync(testPath);
|
|
113
|
+
}
|
|
114
|
+
return fileIndex?.has(testPath) ?? false;
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
/**
|
|
118
|
+
* Check if path is a directory (filesystem mode only).
|
|
119
|
+
*/
|
|
120
|
+
function isDirectory(path: string, useFilesystem: boolean): boolean {
|
|
121
|
+
if (!useFilesystem) {
|
|
122
|
+
// In in-memory mode, we can't check if it's a directory
|
|
123
|
+
// The fileIndex should only contain file paths, not directories
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
try {
|
|
127
|
+
return statSync(path).isDirectory();
|
|
128
|
+
} catch {
|
|
129
|
+
return false;
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* Resolve a base path to an actual file by trying extensions and index files.
|
|
135
|
+
*
|
|
136
|
+
* @param basePath - Absolute path (without extension) to resolve
|
|
137
|
+
* @param options - Resolution options (filesystem vs in-memory, extensions, index files)
|
|
138
|
+
* @returns Resolved file path or null if not found
|
|
139
|
+
*
|
|
140
|
+
* @example Filesystem mode (default)
|
|
141
|
+
* ```ts
|
|
142
|
+
* resolveModulePath('/app/utils')
|
|
143
|
+
* // → '/app/utils.js' (if exists)
|
|
144
|
+
* ```
|
|
145
|
+
*
|
|
146
|
+
* @example In-memory mode (for enrichment plugins)
|
|
147
|
+
* ```ts
|
|
148
|
+
* resolveModulePath('/app/utils', {
|
|
149
|
+
* useFilesystem: false,
|
|
150
|
+
* fileIndex: new Set(['/app/utils.ts'])
|
|
151
|
+
* })
|
|
152
|
+
* // → '/app/utils.ts'
|
|
153
|
+
* ```
|
|
154
|
+
*
|
|
155
|
+
* Note: Symbolic links are followed by existsSync(). Assumes all paths
|
|
156
|
+
* are within the project workspace as determined by discovery phase.
|
|
157
|
+
*/
|
|
158
|
+
export function resolveModulePath(
|
|
159
|
+
basePath: string,
|
|
160
|
+
options?: ModuleResolutionOptions
|
|
161
|
+
): string | null {
|
|
162
|
+
const useFilesystem = options?.useFilesystem ?? true;
|
|
163
|
+
const fileIndex = options?.fileIndex;
|
|
164
|
+
const extensions = options?.extensions ?? DEFAULT_EXTENSIONS;
|
|
165
|
+
const indexFiles = options?.indexFiles ?? DEFAULT_INDEX_FILES;
|
|
166
|
+
|
|
167
|
+
// Validation: fail fast if misconfigured
|
|
168
|
+
if (!useFilesystem && !fileIndex) {
|
|
169
|
+
throw new Error('fileIndex is required when useFilesystem=false');
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// Handle empty path gracefully
|
|
173
|
+
if (!basePath) {
|
|
174
|
+
return null;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
// Normalize path (remove trailing slash)
|
|
178
|
+
const normalizedPath = basePath.endsWith('/') ? basePath.slice(0, -1) : basePath;
|
|
179
|
+
|
|
180
|
+
// Try extensions (including '' for exact match)
|
|
181
|
+
for (const ext of extensions) {
|
|
182
|
+
const testPath = normalizedPath + ext;
|
|
183
|
+
if (pathExists(testPath, useFilesystem, fileIndex)) {
|
|
184
|
+
// In filesystem mode, don't return directories
|
|
185
|
+
if (useFilesystem && ext === '' && isDirectory(testPath, useFilesystem)) {
|
|
186
|
+
// It's a directory, skip to index files
|
|
187
|
+
continue;
|
|
188
|
+
}
|
|
189
|
+
return testPath;
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
// TypeScript extension redirect (REG-426):
|
|
194
|
+
// import './foo.js' → try ./foo.ts when ./foo.js doesn't exist
|
|
195
|
+
const ext = extname(normalizedPath);
|
|
196
|
+
const tsAlternatives = TS_EXTENSION_REDIRECTS[ext];
|
|
197
|
+
if (tsAlternatives) {
|
|
198
|
+
const withoutExt = normalizedPath.slice(0, -ext.length);
|
|
199
|
+
for (const tsExt of tsAlternatives) {
|
|
200
|
+
const testPath = withoutExt + tsExt;
|
|
201
|
+
if (pathExists(testPath, useFilesystem, fileIndex)) {
|
|
202
|
+
return testPath;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Try index files in directory
|
|
208
|
+
for (const indexFile of indexFiles) {
|
|
209
|
+
const testPath = join(normalizedPath, indexFile);
|
|
210
|
+
if (pathExists(testPath, useFilesystem, fileIndex)) {
|
|
211
|
+
return testPath;
|
|
212
|
+
}
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
return null;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
/**
|
|
219
|
+
* Check if import specifier is a relative import.
|
|
220
|
+
*
|
|
221
|
+
* @param specifier - The import specifier (e.g., './utils', 'lodash')
|
|
222
|
+
* @returns true if relative import (./ or ../), false otherwise
|
|
223
|
+
*
|
|
224
|
+
* @example
|
|
225
|
+
* ```ts
|
|
226
|
+
* isRelativeImport('./utils') // true
|
|
227
|
+
* isRelativeImport('../shared') // true
|
|
228
|
+
* isRelativeImport('lodash') // false
|
|
229
|
+
* isRelativeImport('@scope/pkg') // false
|
|
230
|
+
* isRelativeImport('node:fs') // false
|
|
231
|
+
* ```
|
|
232
|
+
*/
|
|
233
|
+
export function isRelativeImport(specifier: string): boolean {
|
|
234
|
+
return specifier.startsWith('./') || specifier.startsWith('../');
|
|
235
|
+
}
|
|
236
|
+
|
|
237
|
+
/**
|
|
238
|
+
* Resolve relative import specifier to actual file path.
|
|
239
|
+
*
|
|
240
|
+
* Combines relative path resolution with module path resolution.
|
|
241
|
+
* Returns null for non-relative specifiers (bare modules, scoped packages).
|
|
242
|
+
*
|
|
243
|
+
* @param specifier - The import specifier (e.g., './utils', '../shared')
|
|
244
|
+
* @param containingFile - The file containing the import
|
|
245
|
+
* @param options - Resolution options
|
|
246
|
+
* @returns Resolved file path or null if not found or not relative
|
|
247
|
+
*
|
|
248
|
+
* @example
|
|
249
|
+
* ```ts
|
|
250
|
+
* // From /project/src/main.js, import './utils'
|
|
251
|
+
* resolveRelativeSpecifier('./utils', '/project/src/main.js')
|
|
252
|
+
* // → '/project/src/utils.js' (if exists)
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export function resolveRelativeSpecifier(
|
|
256
|
+
specifier: string,
|
|
257
|
+
containingFile: string,
|
|
258
|
+
options?: ModuleResolutionOptions
|
|
259
|
+
): string | null {
|
|
260
|
+
// Only handle relative imports
|
|
261
|
+
if (!isRelativeImport(specifier)) {
|
|
262
|
+
return null;
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
// Resolve relative path to absolute base path
|
|
266
|
+
const dir = dirname(containingFile);
|
|
267
|
+
const basePath = resolve(dir, specifier);
|
|
268
|
+
|
|
269
|
+
// Use main resolution function
|
|
270
|
+
return resolveModulePath(basePath, options);
|
|
271
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve a node's file path to an absolute path.
|
|
3
|
+
*
|
|
4
|
+
* After REG-408, node.file stores paths relative to projectPath.
|
|
5
|
+
* This utility resolves them back to absolute for file system access.
|
|
6
|
+
* Also handles legacy absolute paths for backward compatibility.
|
|
7
|
+
*
|
|
8
|
+
* @param nodeFile - The file field from a graph node (relative or absolute)
|
|
9
|
+
* @param projectPath - The absolute project root path
|
|
10
|
+
* @returns Absolute file path
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { isAbsolute, join } from 'path';
|
|
14
|
+
|
|
15
|
+
export function resolveNodeFile(nodeFile: string, projectPath: string): string {
|
|
16
|
+
if (isAbsolute(nodeFile)) return nodeFile;
|
|
17
|
+
return join(projectPath, nodeFile);
|
|
18
|
+
}
|
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared utility for starting rfdb-server
|
|
3
|
+
*
|
|
4
|
+
* Single authoritative function for spawning rfdb-server. All spawn sites
|
|
5
|
+
* (RFDBServerBackend, CLI server command, ParallelAnalysisRunner) delegate here.
|
|
6
|
+
*
|
|
7
|
+
* If pidPath is provided, checks for an existing server via PID file before
|
|
8
|
+
* spawning. Returns null when an existing server is detected (caller should
|
|
9
|
+
* not kill it).
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { existsSync, readFileSync, unlinkSync, writeFileSync } from 'fs';
|
|
13
|
+
import { dirname } from 'path';
|
|
14
|
+
import { spawn, type ChildProcess } from 'child_process';
|
|
15
|
+
import { setTimeout as sleep } from 'timers/promises';
|
|
16
|
+
import { findRfdbBinary } from './findRfdbBinary.js';
|
|
17
|
+
|
|
18
|
+
export interface StartRfdbServerOptions {
|
|
19
|
+
dbPath: string;
|
|
20
|
+
socketPath: string;
|
|
21
|
+
/** Override binary path; if absent, findRfdbBinary() is called */
|
|
22
|
+
binaryPath?: string;
|
|
23
|
+
/** If provided, PID file is written after spawn and checked before spawn */
|
|
24
|
+
pidPath?: string;
|
|
25
|
+
/** Socket poll timeout in ms (default: 5000) */
|
|
26
|
+
waitTimeoutMs?: number;
|
|
27
|
+
/** Optional logger for debug messages */
|
|
28
|
+
logger?: { debug(msg: string): void };
|
|
29
|
+
/** Internal: dependency injection for testing */
|
|
30
|
+
_deps?: {
|
|
31
|
+
spawn?: typeof spawn;
|
|
32
|
+
findRfdbBinary?: () => string | null;
|
|
33
|
+
existsSync?: (path: string) => boolean;
|
|
34
|
+
unlinkSync?: (path: string) => void;
|
|
35
|
+
writeFileSync?: (path: string, data: string) => void;
|
|
36
|
+
readFileSync?: (path: string, encoding: 'utf8') => string;
|
|
37
|
+
killProcess?: (pid: number, signal: number) => boolean;
|
|
38
|
+
};
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
/**
|
|
42
|
+
* Check if an existing server is running based on PID file.
|
|
43
|
+
*
|
|
44
|
+
* Returns:
|
|
45
|
+
* - 'alive' — PID file exists, process is alive, socket is present
|
|
46
|
+
* - 'stale' — PID file exists but process is dead or PID is invalid
|
|
47
|
+
* - 'none' — no PID file
|
|
48
|
+
*/
|
|
49
|
+
export function checkExistingServer(
|
|
50
|
+
pidPath: string,
|
|
51
|
+
socketPath: string,
|
|
52
|
+
deps: {
|
|
53
|
+
existsSync: (path: string) => boolean;
|
|
54
|
+
readFileSync: (path: string, encoding: 'utf8') => string;
|
|
55
|
+
killProcess: (pid: number, signal: number) => boolean;
|
|
56
|
+
},
|
|
57
|
+
): 'alive' | 'stale' | 'none' {
|
|
58
|
+
if (!deps.existsSync(pidPath)) return 'none';
|
|
59
|
+
|
|
60
|
+
let pidStr: string;
|
|
61
|
+
try {
|
|
62
|
+
pidStr = deps.readFileSync(pidPath, 'utf8').trim();
|
|
63
|
+
} catch {
|
|
64
|
+
return 'stale';
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
const pid = parseInt(pidStr, 10);
|
|
68
|
+
if (isNaN(pid) || pid <= 0) return 'stale';
|
|
69
|
+
|
|
70
|
+
try {
|
|
71
|
+
deps.killProcess(pid, 0);
|
|
72
|
+
// Process is alive — check socket too
|
|
73
|
+
if (deps.existsSync(socketPath)) {
|
|
74
|
+
return 'alive';
|
|
75
|
+
}
|
|
76
|
+
// PID alive but socket gone (server crashed partially)
|
|
77
|
+
return 'stale';
|
|
78
|
+
} catch (err: unknown) {
|
|
79
|
+
if (err && typeof err === 'object' && 'code' in err && (err as { code: string }).code === 'ESRCH') {
|
|
80
|
+
return 'stale';
|
|
81
|
+
}
|
|
82
|
+
// Unexpected error — re-throw rather than silently treating as stale
|
|
83
|
+
throw err;
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
/**
|
|
88
|
+
* Start an rfdb-server process (or detect existing one via PID file).
|
|
89
|
+
*
|
|
90
|
+
* 0. Check PID file for existing server (if pidPath provided)
|
|
91
|
+
* 1. Resolve binary (explicit or via findRfdbBinary)
|
|
92
|
+
* 2. Remove stale socket
|
|
93
|
+
* 3. Spawn detached process
|
|
94
|
+
* 4. Write PID file (if pidPath provided)
|
|
95
|
+
* 5. Poll for socket file up to waitTimeoutMs
|
|
96
|
+
* 6. Return ChildProcess (caller decides whether to kill later)
|
|
97
|
+
*
|
|
98
|
+
* Returns null if an existing server is already running (pidPath + alive PID).
|
|
99
|
+
*/
|
|
100
|
+
export async function startRfdbServer(options: StartRfdbServerOptions): Promise<ChildProcess | null> {
|
|
101
|
+
const {
|
|
102
|
+
dbPath,
|
|
103
|
+
socketPath,
|
|
104
|
+
pidPath,
|
|
105
|
+
waitTimeoutMs = 5000,
|
|
106
|
+
logger,
|
|
107
|
+
_deps,
|
|
108
|
+
} = options;
|
|
109
|
+
|
|
110
|
+
const _spawn = _deps?.spawn ?? spawn;
|
|
111
|
+
const _findRfdbBinary = _deps?.findRfdbBinary ?? findRfdbBinary;
|
|
112
|
+
const _existsSync = _deps?.existsSync ?? existsSync;
|
|
113
|
+
const _unlinkSync = _deps?.unlinkSync ?? unlinkSync;
|
|
114
|
+
const _writeFileSync = _deps?.writeFileSync ?? writeFileSync;
|
|
115
|
+
const _readFileSync = _deps?.readFileSync ?? readFileSync;
|
|
116
|
+
const _killProcess = _deps?.killProcess ?? ((pid: number, signal: number) => process.kill(pid, signal));
|
|
117
|
+
|
|
118
|
+
// 0. Check for existing server via PID file
|
|
119
|
+
if (pidPath) {
|
|
120
|
+
const status = checkExistingServer(pidPath, socketPath, {
|
|
121
|
+
existsSync: _existsSync,
|
|
122
|
+
readFileSync: _readFileSync,
|
|
123
|
+
killProcess: _killProcess,
|
|
124
|
+
});
|
|
125
|
+
if (status === 'alive') {
|
|
126
|
+
logger?.debug(`rfdb-server already running (PID file: ${pidPath}), reusing`);
|
|
127
|
+
return null;
|
|
128
|
+
}
|
|
129
|
+
if (status === 'stale') {
|
|
130
|
+
logger?.debug(`Stale PID file found at ${pidPath}, removing`);
|
|
131
|
+
try { _unlinkSync(pidPath); } catch { /* ignore */ }
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
// 1. Resolve binary
|
|
136
|
+
const binaryPath = options.binaryPath || _findRfdbBinary();
|
|
137
|
+
if (!binaryPath) {
|
|
138
|
+
throw new Error(
|
|
139
|
+
'RFDB server binary not found.\n' +
|
|
140
|
+
'Install @grafema/rfdb: npm install @grafema/rfdb\n' +
|
|
141
|
+
'Or build from source: cargo build --release --bin rfdb-server'
|
|
142
|
+
);
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
// 2. Remove stale socket
|
|
146
|
+
if (_existsSync(socketPath)) {
|
|
147
|
+
_unlinkSync(socketPath);
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
const dataDir = dirname(socketPath);
|
|
151
|
+
logger?.debug(`Starting rfdb-server: ${binaryPath} ${dbPath} --socket ${socketPath} --data-dir ${dataDir}`);
|
|
152
|
+
|
|
153
|
+
// 3. Spawn server (detached, survives parent exit)
|
|
154
|
+
// Mutable container to capture async spawn errors (Dijkstra amendment B)
|
|
155
|
+
const state = { spawnError: null as Error | null };
|
|
156
|
+
|
|
157
|
+
const serverProcess = _spawn(binaryPath, [dbPath, '--socket', socketPath, '--data-dir', dataDir], {
|
|
158
|
+
stdio: ['ignore', 'ignore', process.stderr.isTTY ? 'inherit' : 'ignore'],
|
|
159
|
+
detached: true,
|
|
160
|
+
});
|
|
161
|
+
|
|
162
|
+
serverProcess.unref();
|
|
163
|
+
|
|
164
|
+
// Wire error handler to capture ENOENT and other spawn failures
|
|
165
|
+
serverProcess.on('error', (err: Error) => {
|
|
166
|
+
state.spawnError = err;
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
// 4. Write PID file if requested and pid is available
|
|
170
|
+
if (pidPath && serverProcess.pid) {
|
|
171
|
+
_writeFileSync(pidPath, String(serverProcess.pid));
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
// 5. Poll for socket file
|
|
175
|
+
const maxAttempts = Math.ceil(waitTimeoutMs / 100);
|
|
176
|
+
let attempts = 0;
|
|
177
|
+
while (!_existsSync(socketPath) && attempts < maxAttempts) {
|
|
178
|
+
if (state.spawnError) {
|
|
179
|
+
throw new Error(
|
|
180
|
+
`RFDB server failed to start: ${state.spawnError.message} — check binary: ${binaryPath}`
|
|
181
|
+
);
|
|
182
|
+
}
|
|
183
|
+
await sleep(100);
|
|
184
|
+
attempts++;
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
// 6. Final check
|
|
188
|
+
if (!_existsSync(socketPath)) {
|
|
189
|
+
const detail = state.spawnError ? `: ${state.spawnError.message}` : '';
|
|
190
|
+
throw new Error(
|
|
191
|
+
`RFDB server failed to start after ${waitTimeoutMs}ms${detail} — check binary: ${binaryPath}`
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
logger?.debug(`rfdb-server started on ${socketPath}`);
|
|
196
|
+
return serverProcess;
|
|
197
|
+
}
|