grepmind-core 0.1.0-alpha
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/config/types.d.ts +174 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +137 -0
- package/dist/config/types.js.map +1 -0
- package/dist/git.d.ts +98 -0
- package/dist/git.d.ts.map +1 -0
- package/dist/git.js +298 -0
- package/dist/git.js.map +1 -0
- package/dist/git.test.d.ts +7 -0
- package/dist/git.test.d.ts.map +1 -0
- package/dist/git.test.js +242 -0
- package/dist/git.test.js.map +1 -0
- package/dist/index.d.ts +44 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +67 -0
- package/dist/index.js.map +1 -0
- package/dist/indexer/branch.d.ts +121 -0
- package/dist/indexer/branch.d.ts.map +1 -0
- package/dist/indexer/branch.js +451 -0
- package/dist/indexer/branch.js.map +1 -0
- package/dist/indexer/chunker.d.ts +9 -0
- package/dist/indexer/chunker.d.ts.map +1 -0
- package/dist/indexer/chunker.js +70 -0
- package/dist/indexer/chunker.js.map +1 -0
- package/dist/indexer/chunker.test.d.ts +2 -0
- package/dist/indexer/chunker.test.d.ts.map +1 -0
- package/dist/indexer/chunker.test.js +180 -0
- package/dist/indexer/chunker.test.js.map +1 -0
- package/dist/indexer/code/branch.d.ts +155 -0
- package/dist/indexer/code/branch.d.ts.map +1 -0
- package/dist/indexer/code/branch.js +550 -0
- package/dist/indexer/code/branch.js.map +1 -0
- package/dist/indexer/code/branch.test.d.ts +7 -0
- package/dist/indexer/code/branch.test.d.ts.map +1 -0
- package/dist/indexer/code/branch.test.js +241 -0
- package/dist/indexer/code/branch.test.js.map +1 -0
- package/dist/indexer/code/chunker.d.ts +61 -0
- package/dist/indexer/code/chunker.d.ts.map +1 -0
- package/dist/indexer/code/chunker.js +311 -0
- package/dist/indexer/code/chunker.js.map +1 -0
- package/dist/indexer/code/chunker.test.d.ts +2 -0
- package/dist/indexer/code/chunker.test.d.ts.map +1 -0
- package/dist/indexer/code/chunker.test.js +552 -0
- package/dist/indexer/code/chunker.test.js.map +1 -0
- package/dist/indexer/code/fts.test.d.ts +2 -0
- package/dist/indexer/code/fts.test.d.ts.map +1 -0
- package/dist/indexer/code/fts.test.js +14 -0
- package/dist/indexer/code/fts.test.js.map +1 -0
- package/dist/indexer/code/graph/embedded.d.ts +11 -0
- package/dist/indexer/code/graph/embedded.d.ts.map +1 -0
- package/dist/indexer/code/graph/embedded.js +152 -0
- package/dist/indexer/code/graph/embedded.js.map +1 -0
- package/dist/indexer/code/graph/embedded.test.d.ts +2 -0
- package/dist/indexer/code/graph/embedded.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/embedded.test.js +105 -0
- package/dist/indexer/code/graph/embedded.test.js.map +1 -0
- package/dist/indexer/code/graph/facts.d.ts +11 -0
- package/dist/indexer/code/graph/facts.d.ts.map +1 -0
- package/dist/indexer/code/graph/facts.js +456 -0
- package/dist/indexer/code/graph/facts.js.map +1 -0
- package/dist/indexer/code/graph/facts.test.d.ts +2 -0
- package/dist/indexer/code/graph/facts.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/facts.test.js +181 -0
- package/dist/indexer/code/graph/facts.test.js.map +1 -0
- package/dist/indexer/code/graph/id.d.ts +14 -0
- package/dist/indexer/code/graph/id.d.ts.map +1 -0
- package/dist/indexer/code/graph/id.js +40 -0
- package/dist/indexer/code/graph/id.js.map +1 -0
- package/dist/indexer/code/graph/id.test.d.ts +2 -0
- package/dist/indexer/code/graph/id.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/id.test.js +86 -0
- package/dist/indexer/code/graph/id.test.js.map +1 -0
- package/dist/indexer/code/graph/index.d.ts +133 -0
- package/dist/indexer/code/graph/index.d.ts.map +1 -0
- package/dist/indexer/code/graph/index.js +1876 -0
- package/dist/indexer/code/graph/index.js.map +1 -0
- package/dist/indexer/code/graph/index.test.d.ts +2 -0
- package/dist/indexer/code/graph/index.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/index.test.js +210 -0
- package/dist/indexer/code/graph/index.test.js.map +1 -0
- package/dist/indexer/code/graph/queries.d.ts +22 -0
- package/dist/indexer/code/graph/queries.d.ts.map +1 -0
- package/dist/indexer/code/graph/queries.js +79 -0
- package/dist/indexer/code/graph/queries.js.map +1 -0
- package/dist/indexer/code/graph/queries.test.d.ts +2 -0
- package/dist/indexer/code/graph/queries.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/queries.test.js +108 -0
- package/dist/indexer/code/graph/queries.test.js.map +1 -0
- package/dist/indexer/code/graph/resolver.d.ts +136 -0
- package/dist/indexer/code/graph/resolver.d.ts.map +1 -0
- package/dist/indexer/code/graph/resolver.js +839 -0
- package/dist/indexer/code/graph/resolver.js.map +1 -0
- package/dist/indexer/code/graph/resolver.test.d.ts +2 -0
- package/dist/indexer/code/graph/resolver.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/resolver.test.js +482 -0
- package/dist/indexer/code/graph/resolver.test.js.map +1 -0
- package/dist/indexer/code/graph/semantic.d.ts +33 -0
- package/dist/indexer/code/graph/semantic.d.ts.map +1 -0
- package/dist/indexer/code/graph/semantic.js +279 -0
- package/dist/indexer/code/graph/semantic.js.map +1 -0
- package/dist/indexer/code/graph/semantic.test.d.ts +2 -0
- package/dist/indexer/code/graph/semantic.test.d.ts.map +1 -0
- package/dist/indexer/code/graph/semantic.test.js +127 -0
- package/dist/indexer/code/graph/semantic.test.js.map +1 -0
- package/dist/indexer/code/index.d.ts +404 -0
- package/dist/indexer/code/index.d.ts.map +1 -0
- package/dist/indexer/code/index.js +2070 -0
- package/dist/indexer/code/index.js.map +1 -0
- package/dist/indexer/code/languages/bash.d.ts +14 -0
- package/dist/indexer/code/languages/bash.d.ts.map +1 -0
- package/dist/indexer/code/languages/bash.js +125 -0
- package/dist/indexer/code/languages/bash.js.map +1 -0
- package/dist/indexer/code/languages/css.d.ts +16 -0
- package/dist/indexer/code/languages/css.d.ts.map +1 -0
- package/dist/indexer/code/languages/css.js +204 -0
- package/dist/indexer/code/languages/css.js.map +1 -0
- package/dist/indexer/code/languages/generic.d.ts +61 -0
- package/dist/indexer/code/languages/generic.d.ts.map +1 -0
- package/dist/indexer/code/languages/generic.js +150 -0
- package/dist/indexer/code/languages/generic.js.map +1 -0
- package/dist/indexer/code/languages/graphql.d.ts +13 -0
- package/dist/indexer/code/languages/graphql.d.ts.map +1 -0
- package/dist/indexer/code/languages/graphql.js +180 -0
- package/dist/indexer/code/languages/graphql.js.map +1 -0
- package/dist/indexer/code/languages/html.d.ts +16 -0
- package/dist/indexer/code/languages/html.d.ts.map +1 -0
- package/dist/indexer/code/languages/html.js +138 -0
- package/dist/indexer/code/languages/html.js.map +1 -0
- package/dist/indexer/code/languages/index.d.ts +9 -0
- package/dist/indexer/code/languages/index.d.ts.map +1 -0
- package/dist/indexer/code/languages/index.js +12 -0
- package/dist/indexer/code/languages/index.js.map +1 -0
- package/dist/indexer/code/languages/json.d.ts +12 -0
- package/dist/indexer/code/languages/json.d.ts.map +1 -0
- package/dist/indexer/code/languages/json.js +66 -0
- package/dist/indexer/code/languages/json.js.map +1 -0
- package/dist/indexer/code/languages/registry.d.ts +78 -0
- package/dist/indexer/code/languages/registry.d.ts.map +1 -0
- package/dist/indexer/code/languages/registry.js +72 -0
- package/dist/indexer/code/languages/registry.js.map +1 -0
- package/dist/indexer/code/languages/typescript.d.ts +39 -0
- package/dist/indexer/code/languages/typescript.d.ts.map +1 -0
- package/dist/indexer/code/languages/typescript.js +300 -0
- package/dist/indexer/code/languages/typescript.js.map +1 -0
- package/dist/indexer/code/languages/yaml.d.ts +13 -0
- package/dist/indexer/code/languages/yaml.d.ts.map +1 -0
- package/dist/indexer/code/languages/yaml.js +90 -0
- package/dist/indexer/code/languages/yaml.js.map +1 -0
- package/dist/indexer/code/parser.d.ts +26 -0
- package/dist/indexer/code/parser.d.ts.map +1 -0
- package/dist/indexer/code/parser.js +332 -0
- package/dist/indexer/code/parser.js.map +1 -0
- package/dist/indexer/code/retry.d.ts +58 -0
- package/dist/indexer/code/retry.d.ts.map +1 -0
- package/dist/indexer/code/retry.js +192 -0
- package/dist/indexer/code/retry.js.map +1 -0
- package/dist/indexer/code/tree/builder.d.ts +30 -0
- package/dist/indexer/code/tree/builder.d.ts.map +1 -0
- package/dist/indexer/code/tree/builder.js +132 -0
- package/dist/indexer/code/tree/builder.js.map +1 -0
- package/dist/indexer/code/tree/builder.test.d.ts +2 -0
- package/dist/indexer/code/tree/builder.test.d.ts.map +1 -0
- package/dist/indexer/code/tree/builder.test.js +31 -0
- package/dist/indexer/code/tree/builder.test.js.map +1 -0
- package/dist/indexer/code/tree/cache.d.ts +22 -0
- package/dist/indexer/code/tree/cache.d.ts.map +1 -0
- package/dist/indexer/code/tree/cache.js +85 -0
- package/dist/indexer/code/tree/cache.js.map +1 -0
- package/dist/indexer/code/tree/context.d.ts +32 -0
- package/dist/indexer/code/tree/context.d.ts.map +1 -0
- package/dist/indexer/code/tree/context.js +78 -0
- package/dist/indexer/code/tree/context.js.map +1 -0
- package/dist/indexer/code/tree/embedding.d.ts +9 -0
- package/dist/indexer/code/tree/embedding.d.ts.map +1 -0
- package/dist/indexer/code/tree/embedding.js +53 -0
- package/dist/indexer/code/tree/embedding.js.map +1 -0
- package/dist/indexer/code/tree/embedding.test.d.ts +2 -0
- package/dist/indexer/code/tree/embedding.test.d.ts.map +1 -0
- package/dist/indexer/code/tree/embedding.test.js +57 -0
- package/dist/indexer/code/tree/embedding.test.js.map +1 -0
- package/dist/indexer/code/tree/id.d.ts +3 -0
- package/dist/indexer/code/tree/id.d.ts.map +1 -0
- package/dist/indexer/code/tree/id.js +8 -0
- package/dist/indexer/code/tree/id.js.map +1 -0
- package/dist/indexer/code/tree/index.d.ts +113 -0
- package/dist/indexer/code/tree/index.d.ts.map +1 -0
- package/dist/indexer/code/tree/index.js +1146 -0
- package/dist/indexer/code/tree/index.js.map +1 -0
- package/dist/indexer/code/tree/rename.d.ts +13 -0
- package/dist/indexer/code/tree/rename.d.ts.map +1 -0
- package/dist/indexer/code/tree/rename.js +46 -0
- package/dist/indexer/code/tree/rename.js.map +1 -0
- package/dist/indexer/code/tree/repomap.d.ts +29 -0
- package/dist/indexer/code/tree/repomap.d.ts.map +1 -0
- package/dist/indexer/code/tree/repomap.js +95 -0
- package/dist/indexer/code/tree/repomap.js.map +1 -0
- package/dist/indexer/code/tree/repomap.test.d.ts +2 -0
- package/dist/indexer/code/tree/repomap.test.d.ts.map +1 -0
- package/dist/indexer/code/tree/repomap.test.js +93 -0
- package/dist/indexer/code/tree/repomap.test.js.map +1 -0
- package/dist/indexer/code/tree/stats.d.ts +26 -0
- package/dist/indexer/code/tree/stats.d.ts.map +1 -0
- package/dist/indexer/code/tree/stats.js +49 -0
- package/dist/indexer/code/tree/stats.js.map +1 -0
- package/dist/indexer/code/tree/types.d.ts +186 -0
- package/dist/indexer/code/tree/types.d.ts.map +1 -0
- package/dist/indexer/code/tree/types.js +10 -0
- package/dist/indexer/code/tree/types.js.map +1 -0
- package/dist/indexer/code/wal.d.ts +144 -0
- package/dist/indexer/code/wal.d.ts.map +1 -0
- package/dist/indexer/code/wal.js +283 -0
- package/dist/indexer/code/wal.js.map +1 -0
- package/dist/indexer/embeddings.d.ts +113 -0
- package/dist/indexer/embeddings.d.ts.map +1 -0
- package/dist/indexer/embeddings.js +477 -0
- package/dist/indexer/embeddings.js.map +1 -0
- package/dist/indexer/git-sync.d.ts +117 -0
- package/dist/indexer/git-sync.d.ts.map +1 -0
- package/dist/indexer/git-sync.js +398 -0
- package/dist/indexer/git-sync.js.map +1 -0
- package/dist/indexer/index.d.ts +175 -0
- package/dist/indexer/index.d.ts.map +1 -0
- package/dist/indexer/index.js +1096 -0
- package/dist/indexer/index.js.map +1 -0
- package/dist/indexer/mocks/mock-reranker.d.ts +12 -0
- package/dist/indexer/mocks/mock-reranker.d.ts.map +1 -0
- package/dist/indexer/mocks/mock-reranker.js +26 -0
- package/dist/indexer/mocks/mock-reranker.js.map +1 -0
- package/dist/indexer/parser.d.ts +8 -0
- package/dist/indexer/parser.d.ts.map +1 -0
- package/dist/indexer/parser.js +44 -0
- package/dist/indexer/parser.js.map +1 -0
- package/dist/indexer/parser.test.d.ts +2 -0
- package/dist/indexer/parser.test.d.ts.map +1 -0
- package/dist/indexer/parser.test.js +197 -0
- package/dist/indexer/parser.test.js.map +1 -0
- package/dist/indexer/reranking.d.ts +71 -0
- package/dist/indexer/reranking.d.ts.map +1 -0
- package/dist/indexer/reranking.integration.test.d.ts +2 -0
- package/dist/indexer/reranking.integration.test.d.ts.map +1 -0
- package/dist/indexer/reranking.integration.test.js +104 -0
- package/dist/indexer/reranking.integration.test.js.map +1 -0
- package/dist/indexer/reranking.js +256 -0
- package/dist/indexer/reranking.js.map +1 -0
- package/dist/indexer/reranking.test.d.ts +2 -0
- package/dist/indexer/reranking.test.d.ts.map +1 -0
- package/dist/indexer/reranking.test.js +130 -0
- package/dist/indexer/reranking.test.js.map +1 -0
- package/dist/indexer/wal/file-storage.d.ts +60 -0
- package/dist/indexer/wal/file-storage.d.ts.map +1 -0
- package/dist/indexer/wal/file-storage.js +277 -0
- package/dist/indexer/wal/file-storage.js.map +1 -0
- package/dist/indexer/wal/file-storage.test.d.ts +8 -0
- package/dist/indexer/wal/file-storage.test.d.ts.map +1 -0
- package/dist/indexer/wal/file-storage.test.js +444 -0
- package/dist/indexer/wal/file-storage.test.js.map +1 -0
- package/dist/indexer/wal/index.d.ts +41 -0
- package/dist/indexer/wal/index.d.ts.map +1 -0
- package/dist/indexer/wal/index.js +61 -0
- package/dist/indexer/wal/index.js.map +1 -0
- package/dist/indexer/wal/integration.test.d.ts +11 -0
- package/dist/indexer/wal/integration.test.d.ts.map +1 -0
- package/dist/indexer/wal/integration.test.js +378 -0
- package/dist/indexer/wal/integration.test.js.map +1 -0
- package/dist/indexer/wal/lancedb-storage.d.ts +72 -0
- package/dist/indexer/wal/lancedb-storage.d.ts.map +1 -0
- package/dist/indexer/wal/lancedb-storage.js +462 -0
- package/dist/indexer/wal/lancedb-storage.js.map +1 -0
- package/dist/indexer/wal/lancedb-storage.test.d.ts +8 -0
- package/dist/indexer/wal/lancedb-storage.test.d.ts.map +1 -0
- package/dist/indexer/wal/lancedb-storage.test.js +415 -0
- package/dist/indexer/wal/lancedb-storage.test.js.map +1 -0
- package/dist/indexer/wal/sync-wal.d.ts +144 -0
- package/dist/indexer/wal/sync-wal.d.ts.map +1 -0
- package/dist/indexer/wal/sync-wal.js +863 -0
- package/dist/indexer/wal/sync-wal.js.map +1 -0
- package/dist/indexer/wal/sync-wal.test.d.ts +8 -0
- package/dist/indexer/wal/sync-wal.test.d.ts.map +1 -0
- package/dist/indexer/wal/sync-wal.test.js +752 -0
- package/dist/indexer/wal/sync-wal.test.js.map +1 -0
- package/dist/indexer/wal/types.d.ts +167 -0
- package/dist/indexer/wal/types.d.ts.map +1 -0
- package/dist/indexer/wal/types.js +12 -0
- package/dist/indexer/wal/types.js.map +1 -0
- package/dist/indexer/watcher.d.ts +36 -0
- package/dist/indexer/watcher.d.ts.map +1 -0
- package/dist/indexer/watcher.js +110 -0
- package/dist/indexer/watcher.js.map +1 -0
- package/dist/search/explore.d.ts +62 -0
- package/dist/search/explore.d.ts.map +1 -0
- package/dist/search/explore.js +111 -0
- package/dist/search/explore.js.map +1 -0
- package/dist/search/fts.d.ts +23 -0
- package/dist/search/fts.d.ts.map +1 -0
- package/dist/search/fts.js +64 -0
- package/dist/search/fts.js.map +1 -0
- package/dist/search/fts.test.d.ts +2 -0
- package/dist/search/fts.test.d.ts.map +1 -0
- package/dist/search/fts.test.js +27 -0
- package/dist/search/fts.test.js.map +1 -0
- package/dist/search/grep.d.ts +75 -0
- package/dist/search/grep.d.ts.map +1 -0
- package/dist/search/grep.js +96 -0
- package/dist/search/grep.js.map +1 -0
- package/dist/search/grep.test.d.ts +2 -0
- package/dist/search/grep.test.d.ts.map +1 -0
- package/dist/search/grep.test.js +178 -0
- package/dist/search/grep.test.js.map +1 -0
- package/dist/search/hybrid-grep.d.ts +43 -0
- package/dist/search/hybrid-grep.d.ts.map +1 -0
- package/dist/search/hybrid-grep.js +130 -0
- package/dist/search/hybrid-grep.js.map +1 -0
- package/dist/search/hybrid-grep.test.d.ts +2 -0
- package/dist/search/hybrid-grep.test.d.ts.map +1 -0
- package/dist/search/hybrid-grep.test.js +133 -0
- package/dist/search/hybrid-grep.test.js.map +1 -0
- package/dist/search/rg-executor.d.ts +63 -0
- package/dist/search/rg-executor.d.ts.map +1 -0
- package/dist/search/rg-executor.js +146 -0
- package/dist/search/rg-executor.js.map +1 -0
- package/dist/search/rg-executor.test.d.ts +2 -0
- package/dist/search/rg-executor.test.d.ts.map +1 -0
- package/dist/search/rg-executor.test.js +104 -0
- package/dist/search/rg-executor.test.js.map +1 -0
- package/dist/search/rg-parser/extractor.d.ts +14 -0
- package/dist/search/rg-parser/extractor.d.ts.map +1 -0
- package/dist/search/rg-parser/extractor.js +82 -0
- package/dist/search/rg-parser/extractor.js.map +1 -0
- package/dist/search/rg-parser/extractor.test.d.ts +2 -0
- package/dist/search/rg-parser/extractor.test.d.ts.map +1 -0
- package/dist/search/rg-parser/extractor.test.js +35 -0
- package/dist/search/rg-parser/extractor.test.js.map +1 -0
- package/dist/search/rg-parser/fts-builder.d.ts +7 -0
- package/dist/search/rg-parser/fts-builder.d.ts.map +1 -0
- package/dist/search/rg-parser/fts-builder.js +18 -0
- package/dist/search/rg-parser/fts-builder.js.map +1 -0
- package/dist/search/rg-parser/fts-builder.test.d.ts +2 -0
- package/dist/search/rg-parser/fts-builder.test.d.ts.map +1 -0
- package/dist/search/rg-parser/fts-builder.test.js +26 -0
- package/dist/search/rg-parser/fts-builder.test.js.map +1 -0
- package/dist/search/rg-parser/index.d.ts +36 -0
- package/dist/search/rg-parser/index.d.ts.map +1 -0
- package/dist/search/rg-parser/index.js +83 -0
- package/dist/search/rg-parser/index.js.map +1 -0
- package/dist/search/rg-parser/index.test.d.ts +2 -0
- package/dist/search/rg-parser/index.test.d.ts.map +1 -0
- package/dist/search/rg-parser/index.test.js +34 -0
- package/dist/search/rg-parser/index.test.js.map +1 -0
- package/dist/search/rg-parser/strategy.d.ts +14 -0
- package/dist/search/rg-parser/strategy.d.ts.map +1 -0
- package/dist/search/rg-parser/strategy.js +31 -0
- package/dist/search/rg-parser/strategy.js.map +1 -0
- package/dist/search/rg-parser/strategy.test.d.ts +2 -0
- package/dist/search/rg-parser/strategy.test.d.ts.map +1 -0
- package/dist/search/rg-parser/strategy.test.js +29 -0
- package/dist/search/rg-parser/strategy.test.js.map +1 -0
- package/dist/types.d.ts +345 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +7 -0
- package/dist/types.js.map +1 -0
- package/dist/utils/vault.d.ts +84 -0
- package/dist/utils/vault.d.ts.map +1 -0
- package/dist/utils/vault.js +138 -0
- package/dist/utils/vault.js.map +1 -0
- package/dist/utils/vault.test.d.ts +2 -0
- package/dist/utils/vault.test.d.ts.map +1 -0
- package/dist/utils/vault.test.js +153 -0
- package/dist/utils/vault.test.js.map +1 -0
- package/package.json +69 -0
|
@@ -0,0 +1,839 @@
|
|
|
1
|
+
import fs from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { builtinModules, createRequire } from 'node:module';
|
|
4
|
+
import { pathToFileURL } from 'node:url';
|
|
5
|
+
const EXTENSIONS = ['.ts', '.tsx', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
6
|
+
const TS_COMPAT_EXTENSIONS = ['.ts', '.tsx', '.mts', '.cts', '.js', '.jsx', '.mjs', '.cjs', '.json'];
|
|
7
|
+
const BUILTIN_SET = new Set([
|
|
8
|
+
...builtinModules,
|
|
9
|
+
...builtinModules.map((m) => `node:${m}`),
|
|
10
|
+
]);
|
|
11
|
+
/**
|
|
12
|
+
* File system cache for resolver operations.
|
|
13
|
+
* Caches access and stat results to avoid redundant I/O during graph building.
|
|
14
|
+
*/
|
|
15
|
+
class FSCache {
|
|
16
|
+
accessCache = new Map();
|
|
17
|
+
statCache = new Map();
|
|
18
|
+
realpathCache = new Map();
|
|
19
|
+
pendingAccess = new Map();
|
|
20
|
+
pendingStat = new Map();
|
|
21
|
+
pendingRealpath = new Map();
|
|
22
|
+
async access(filePath) {
|
|
23
|
+
if (this.accessCache.has(filePath)) {
|
|
24
|
+
return this.accessCache.get(filePath);
|
|
25
|
+
}
|
|
26
|
+
// Deduplicate concurrent requests for the same path
|
|
27
|
+
if (this.pendingAccess.has(filePath)) {
|
|
28
|
+
return this.pendingAccess.get(filePath);
|
|
29
|
+
}
|
|
30
|
+
const promise = (async () => {
|
|
31
|
+
try {
|
|
32
|
+
await fs.access(filePath);
|
|
33
|
+
this.accessCache.set(filePath, true);
|
|
34
|
+
return true;
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
this.accessCache.set(filePath, false);
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
finally {
|
|
41
|
+
this.pendingAccess.delete(filePath);
|
|
42
|
+
}
|
|
43
|
+
})();
|
|
44
|
+
this.pendingAccess.set(filePath, promise);
|
|
45
|
+
return promise;
|
|
46
|
+
}
|
|
47
|
+
async stat(filePath) {
|
|
48
|
+
if (this.statCache.has(filePath)) {
|
|
49
|
+
return this.statCache.get(filePath);
|
|
50
|
+
}
|
|
51
|
+
if (this.pendingStat.has(filePath)) {
|
|
52
|
+
return this.pendingStat.get(filePath);
|
|
53
|
+
}
|
|
54
|
+
const promise = (async () => {
|
|
55
|
+
try {
|
|
56
|
+
const result = await fs.stat(filePath);
|
|
57
|
+
this.statCache.set(filePath, result);
|
|
58
|
+
return result;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
this.statCache.set(filePath, null);
|
|
62
|
+
return null;
|
|
63
|
+
}
|
|
64
|
+
finally {
|
|
65
|
+
this.pendingStat.delete(filePath);
|
|
66
|
+
}
|
|
67
|
+
})();
|
|
68
|
+
this.pendingStat.set(filePath, promise);
|
|
69
|
+
return promise;
|
|
70
|
+
}
|
|
71
|
+
async realpath(filePath) {
|
|
72
|
+
if (this.realpathCache.has(filePath)) {
|
|
73
|
+
return this.realpathCache.get(filePath);
|
|
74
|
+
}
|
|
75
|
+
if (this.pendingRealpath.has(filePath)) {
|
|
76
|
+
return this.pendingRealpath.get(filePath);
|
|
77
|
+
}
|
|
78
|
+
const promise = (async () => {
|
|
79
|
+
try {
|
|
80
|
+
const result = await fs.realpath(filePath);
|
|
81
|
+
this.realpathCache.set(filePath, result);
|
|
82
|
+
return result;
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
this.realpathCache.set(filePath, null);
|
|
86
|
+
return null;
|
|
87
|
+
}
|
|
88
|
+
finally {
|
|
89
|
+
this.pendingRealpath.delete(filePath);
|
|
90
|
+
}
|
|
91
|
+
})();
|
|
92
|
+
this.pendingRealpath.set(filePath, promise);
|
|
93
|
+
return promise;
|
|
94
|
+
}
|
|
95
|
+
clear() {
|
|
96
|
+
this.accessCache.clear();
|
|
97
|
+
this.statCache.clear();
|
|
98
|
+
this.realpathCache.clear();
|
|
99
|
+
this.pendingAccess.clear();
|
|
100
|
+
this.pendingStat.clear();
|
|
101
|
+
this.pendingRealpath.clear();
|
|
102
|
+
}
|
|
103
|
+
get size() {
|
|
104
|
+
return this.accessCache.size + this.statCache.size + this.realpathCache.size;
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
// Global FS cache instance for resolver operations
|
|
108
|
+
const fsCache = new FSCache();
|
|
109
|
+
/**
|
|
110
|
+
* Clear the resolver file system cache.
|
|
111
|
+
* Call this between indexing runs or when files may have changed.
|
|
112
|
+
*/
|
|
113
|
+
export function clearResolverCache() {
|
|
114
|
+
fsCache.clear();
|
|
115
|
+
}
|
|
116
|
+
/**
|
|
117
|
+
* Resolves workspace package imports to source files.
|
|
118
|
+
* Works with npm/yarn/pnpm workspaces by detecting symlinks in node_modules.
|
|
119
|
+
*/
|
|
120
|
+
export class WorkspaceResolver {
|
|
121
|
+
workspaces = new Map();
|
|
122
|
+
rootPath;
|
|
123
|
+
workspaceRoot = null;
|
|
124
|
+
discovered = false;
|
|
125
|
+
constructor(rootPath) {
|
|
126
|
+
this.rootPath = rootPath;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Get the workspace root directory (where package.json with workspaces is located).
|
|
130
|
+
*/
|
|
131
|
+
getWorkspaceRoot() {
|
|
132
|
+
return this.workspaceRoot;
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Get the root directory path for a workspace package.
|
|
136
|
+
* @param packageName - Package name (e.g., grepmind-config)
|
|
137
|
+
* @returns Relative path to package root (e.g., packages/config) or null
|
|
138
|
+
*/
|
|
139
|
+
getPackagePath(packageName) {
|
|
140
|
+
const ws = this.workspaces.get(packageName);
|
|
141
|
+
return ws?.rootDir ?? null;
|
|
142
|
+
}
|
|
143
|
+
/**
|
|
144
|
+
* Discover all workspace packages in the project.
|
|
145
|
+
* Walks up from rootPath to find workspace root, then discovers all packages.
|
|
146
|
+
*/
|
|
147
|
+
async discover() {
|
|
148
|
+
if (this.discovered)
|
|
149
|
+
return;
|
|
150
|
+
this.discovered = true;
|
|
151
|
+
// Find workspace root by walking up the directory tree
|
|
152
|
+
this.workspaceRoot = await this.findWorkspaceRoot();
|
|
153
|
+
if (!this.workspaceRoot)
|
|
154
|
+
return;
|
|
155
|
+
const patterns = await this.getWorkspacePatterns();
|
|
156
|
+
if (patterns.length === 0)
|
|
157
|
+
return;
|
|
158
|
+
// Import glob dynamically to avoid circular dependencies
|
|
159
|
+
const { glob } = await import('glob');
|
|
160
|
+
for (const pattern of patterns) {
|
|
161
|
+
// Glob for package.json files inside workspace patterns
|
|
162
|
+
const pkgJsonPattern = `${pattern}/package.json`;
|
|
163
|
+
const pkgJsonFiles = await glob(pkgJsonPattern, {
|
|
164
|
+
cwd: this.workspaceRoot,
|
|
165
|
+
absolute: false,
|
|
166
|
+
nodir: true,
|
|
167
|
+
});
|
|
168
|
+
for (const pkgJsonPath of pkgJsonFiles) {
|
|
169
|
+
// Extract directory from package.json path
|
|
170
|
+
const dir = path.dirname(pkgJsonPath);
|
|
171
|
+
await this.registerWorkspace(dir);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
/**
|
|
176
|
+
* Check if rootPath is a workspace root.
|
|
177
|
+
* Returns rootPath if it contains package.json with workspaces or pnpm-workspace.yaml.
|
|
178
|
+
* Does NOT walk up the tree — rootPath is the config root and nothing above it should be indexed.
|
|
179
|
+
*/
|
|
180
|
+
async findWorkspaceRoot() {
|
|
181
|
+
// Check for npm/yarn workspaces in package.json
|
|
182
|
+
try {
|
|
183
|
+
const pkgPath = path.join(this.rootPath, 'package.json');
|
|
184
|
+
const content = await fs.readFile(pkgPath, 'utf-8');
|
|
185
|
+
const pkg = JSON.parse(content);
|
|
186
|
+
if (Array.isArray(pkg.workspaces)) {
|
|
187
|
+
return this.rootPath;
|
|
188
|
+
}
|
|
189
|
+
if (typeof pkg.workspaces === 'object' && pkg.workspaces !== null) {
|
|
190
|
+
const ws = pkg.workspaces;
|
|
191
|
+
if (Array.isArray(ws.packages)) {
|
|
192
|
+
return this.rootPath;
|
|
193
|
+
}
|
|
194
|
+
}
|
|
195
|
+
}
|
|
196
|
+
catch {
|
|
197
|
+
// No package.json or invalid
|
|
198
|
+
}
|
|
199
|
+
// Check for pnpm-workspace.yaml
|
|
200
|
+
try {
|
|
201
|
+
const yamlPath = path.join(this.rootPath, 'pnpm-workspace.yaml');
|
|
202
|
+
await fs.access(yamlPath);
|
|
203
|
+
return this.rootPath;
|
|
204
|
+
}
|
|
205
|
+
catch {
|
|
206
|
+
// No pnpm-workspace.yaml
|
|
207
|
+
}
|
|
208
|
+
return null;
|
|
209
|
+
}
|
|
210
|
+
/**
|
|
211
|
+
* Get workspace patterns from package.json or pnpm-workspace.yaml
|
|
212
|
+
*/
|
|
213
|
+
async getWorkspacePatterns() {
|
|
214
|
+
if (!this.workspaceRoot)
|
|
215
|
+
return [];
|
|
216
|
+
// Try package.json first (npm/yarn workspaces)
|
|
217
|
+
try {
|
|
218
|
+
const pkgPath = path.join(this.workspaceRoot, 'package.json');
|
|
219
|
+
const content = await fs.readFile(pkgPath, 'utf-8');
|
|
220
|
+
const pkg = JSON.parse(content);
|
|
221
|
+
// npm/yarn: workspaces: ["packages/*"]
|
|
222
|
+
if (Array.isArray(pkg.workspaces)) {
|
|
223
|
+
return pkg.workspaces;
|
|
224
|
+
}
|
|
225
|
+
// yarn: workspaces.packages: ["packages/*"]
|
|
226
|
+
if (typeof pkg.workspaces === 'object' && pkg.workspaces !== null) {
|
|
227
|
+
const ws = pkg.workspaces;
|
|
228
|
+
if (Array.isArray(ws.packages)) {
|
|
229
|
+
return ws.packages;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
}
|
|
233
|
+
catch {
|
|
234
|
+
// No package.json or invalid
|
|
235
|
+
}
|
|
236
|
+
// Try pnpm-workspace.yaml
|
|
237
|
+
try {
|
|
238
|
+
const yamlPath = path.join(this.workspaceRoot, 'pnpm-workspace.yaml');
|
|
239
|
+
const content = await fs.readFile(yamlPath, 'utf-8');
|
|
240
|
+
// Simple YAML parsing for packages array
|
|
241
|
+
const match = content.match(/packages:\s*\n((?:\s+-\s+.+\n?)+)/);
|
|
242
|
+
if (match) {
|
|
243
|
+
const lines = match[1].split('\n');
|
|
244
|
+
return lines
|
|
245
|
+
.map(line => line.replace(/^\s*-\s*['"]?/, '').replace(/['"]?\s*$/, ''))
|
|
246
|
+
.filter(Boolean);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
catch {
|
|
250
|
+
// No pnpm-workspace.yaml
|
|
251
|
+
}
|
|
252
|
+
return [];
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Register a workspace package directory.
|
|
256
|
+
*/
|
|
257
|
+
async registerWorkspace(dir) {
|
|
258
|
+
if (!this.workspaceRoot)
|
|
259
|
+
return;
|
|
260
|
+
const pkgPath = path.join(this.workspaceRoot, dir, 'package.json');
|
|
261
|
+
try {
|
|
262
|
+
const content = await fs.readFile(pkgPath, 'utf-8');
|
|
263
|
+
const pkg = JSON.parse(content);
|
|
264
|
+
const name = pkg.name;
|
|
265
|
+
if (!name)
|
|
266
|
+
return;
|
|
267
|
+
// Load tsconfig to get src/dist directories
|
|
268
|
+
const tsconfig = await loadTSConfig(path.join(this.workspaceRoot, dir));
|
|
269
|
+
// Normalize paths: remove leading ./
|
|
270
|
+
const srcDir = (tsconfig?.compilerOptions?.rootDir ?? 'src').replace(/^\.\//, '');
|
|
271
|
+
const distDir = (tsconfig?.compilerOptions?.outDir ?? 'dist').replace(/^\.\//, '');
|
|
272
|
+
// Parse exports field
|
|
273
|
+
let exports = null;
|
|
274
|
+
if (typeof pkg.exports === 'object' && pkg.exports !== null) {
|
|
275
|
+
exports = this.normalizeExports(pkg.exports);
|
|
276
|
+
}
|
|
277
|
+
this.workspaces.set(name, {
|
|
278
|
+
name,
|
|
279
|
+
rootDir: dir,
|
|
280
|
+
srcDir,
|
|
281
|
+
distDir,
|
|
282
|
+
exports,
|
|
283
|
+
});
|
|
284
|
+
}
|
|
285
|
+
catch {
|
|
286
|
+
// Skip invalid packages
|
|
287
|
+
}
|
|
288
|
+
}
|
|
289
|
+
/**
|
|
290
|
+
* Normalize package.json exports to a simple path map.
|
|
291
|
+
*/
|
|
292
|
+
normalizeExports(exports) {
|
|
293
|
+
const result = {};
|
|
294
|
+
for (const [key, value] of Object.entries(exports)) {
|
|
295
|
+
if (typeof value === 'string') {
|
|
296
|
+
result[key] = value;
|
|
297
|
+
}
|
|
298
|
+
else if (typeof value === 'object' && value !== null) {
|
|
299
|
+
// Handle conditional exports: { import: "./dist/index.js", types: "..." }
|
|
300
|
+
const cond = value;
|
|
301
|
+
const importPath = cond.import ?? cond.require ?? cond.default;
|
|
302
|
+
if (typeof importPath === 'string') {
|
|
303
|
+
result[key] = importPath;
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
return result;
|
|
308
|
+
}
|
|
309
|
+
/**
|
|
310
|
+
* Check if a package name is a workspace package.
|
|
311
|
+
*/
|
|
312
|
+
isWorkspacePackage(packageName) {
|
|
313
|
+
return this.workspaces.has(packageName);
|
|
314
|
+
}
|
|
315
|
+
/**
|
|
316
|
+
* Resolve a workspace package import to source file path.
|
|
317
|
+
* Returns ABSOLUTE path to source file, or null if not resolvable.
|
|
318
|
+
*
|
|
319
|
+
* @param packageName - Package name (e.g., grepmind-config)
|
|
320
|
+
* @param subpath - Optional subpath (e.g., utils for grepmind-config/utils)
|
|
321
|
+
*/
|
|
322
|
+
resolveToSource(packageName, subpath) {
|
|
323
|
+
const ws = this.workspaces.get(packageName);
|
|
324
|
+
if (!ws || !this.workspaceRoot)
|
|
325
|
+
return null;
|
|
326
|
+
// Resolve through exports field if available
|
|
327
|
+
let distPath;
|
|
328
|
+
if (ws.exports) {
|
|
329
|
+
const exportKey = subpath ? `./${subpath}` : '.';
|
|
330
|
+
const exportPath = ws.exports[exportKey];
|
|
331
|
+
if (exportPath) {
|
|
332
|
+
// Remove leading ./ from export path
|
|
333
|
+
distPath = exportPath.replace(/^\.\//, '');
|
|
334
|
+
}
|
|
335
|
+
else {
|
|
336
|
+
// Fallback: assume direct subpath mapping
|
|
337
|
+
distPath = subpath
|
|
338
|
+
? `${ws.distDir}/${subpath}`
|
|
339
|
+
: `${ws.distDir}/index.js`;
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
else {
|
|
343
|
+
distPath = subpath
|
|
344
|
+
? `${ws.distDir}/${subpath}`
|
|
345
|
+
: `${ws.distDir}/index.js`;
|
|
346
|
+
}
|
|
347
|
+
// Map dist → src, .js → .ts
|
|
348
|
+
// Escape regex special chars in distDir (e.g., if distDir contains dots)
|
|
349
|
+
const escapedDistDir = ws.distDir.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
350
|
+
const srcPath = distPath
|
|
351
|
+
.replace(new RegExp(`^${escapedDistDir}/`), `${ws.srcDir}/`)
|
|
352
|
+
.replace(/\.js$/, '.ts')
|
|
353
|
+
.replace(/\.mjs$/, '.mts')
|
|
354
|
+
.replace(/\.cjs$/, '.cts');
|
|
355
|
+
// Return absolute path
|
|
356
|
+
return path.join(this.workspaceRoot, ws.rootDir, srcPath);
|
|
357
|
+
}
|
|
358
|
+
/**
|
|
359
|
+
* Get all discovered workspace packages.
|
|
360
|
+
*/
|
|
361
|
+
getWorkspaces() {
|
|
362
|
+
return this.workspaces;
|
|
363
|
+
}
|
|
364
|
+
/**
|
|
365
|
+
* Clear discovered workspaces (for testing or re-discovery).
|
|
366
|
+
*/
|
|
367
|
+
clear() {
|
|
368
|
+
this.workspaces.clear();
|
|
369
|
+
this.discovered = false;
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
async function safeAccess(filePath) {
|
|
373
|
+
return fsCache.access(filePath);
|
|
374
|
+
}
|
|
375
|
+
async function safeStat(filePath) {
|
|
376
|
+
return fsCache.stat(filePath);
|
|
377
|
+
}
|
|
378
|
+
function toFileId(rootPath, absolutePath) {
|
|
379
|
+
return path.relative(rootPath, absolutePath).replace(/\\/g, '/');
|
|
380
|
+
}
|
|
381
|
+
async function resolveWithExtensions(basePath) {
|
|
382
|
+
const stat = await safeStat(basePath);
|
|
383
|
+
if (stat?.isFile())
|
|
384
|
+
return basePath;
|
|
385
|
+
// Build all candidates upfront
|
|
386
|
+
const candidates = [];
|
|
387
|
+
for (const ext of EXTENSIONS) {
|
|
388
|
+
candidates.push(`${basePath}${ext}`);
|
|
389
|
+
}
|
|
390
|
+
for (const ext of EXTENSIONS) {
|
|
391
|
+
candidates.push(path.join(basePath, `index${ext}`));
|
|
392
|
+
}
|
|
393
|
+
// Check all candidates in parallel
|
|
394
|
+
const results = await Promise.all(candidates.map(async (candidate) => ({
|
|
395
|
+
candidate,
|
|
396
|
+
exists: await safeAccess(candidate),
|
|
397
|
+
})));
|
|
398
|
+
// Return first existing candidate (preserves priority order)
|
|
399
|
+
for (const { candidate, exists } of results) {
|
|
400
|
+
if (exists)
|
|
401
|
+
return candidate;
|
|
402
|
+
}
|
|
403
|
+
return null;
|
|
404
|
+
}
|
|
405
|
+
async function resolveWithExtensionList(basePath, extensions) {
|
|
406
|
+
const stat = await safeStat(basePath);
|
|
407
|
+
if (stat?.isFile())
|
|
408
|
+
return basePath;
|
|
409
|
+
// Build all candidates upfront
|
|
410
|
+
const candidates = [];
|
|
411
|
+
for (const ext of extensions) {
|
|
412
|
+
candidates.push(`${basePath}${ext}`);
|
|
413
|
+
}
|
|
414
|
+
for (const ext of extensions) {
|
|
415
|
+
candidates.push(path.join(basePath, `index${ext}`));
|
|
416
|
+
}
|
|
417
|
+
// Check all candidates in parallel
|
|
418
|
+
const results = await Promise.all(candidates.map(async (candidate) => ({
|
|
419
|
+
candidate,
|
|
420
|
+
exists: await safeAccess(candidate),
|
|
421
|
+
})));
|
|
422
|
+
// Return first existing candidate (preserves priority order)
|
|
423
|
+
for (const { candidate, exists } of results) {
|
|
424
|
+
if (exists)
|
|
425
|
+
return candidate;
|
|
426
|
+
}
|
|
427
|
+
return null;
|
|
428
|
+
}
|
|
429
|
+
function parsePackageSpec(spec) {
|
|
430
|
+
if (spec.startsWith('@')) {
|
|
431
|
+
const [scope, name, ...rest] = spec.split('/');
|
|
432
|
+
return {
|
|
433
|
+
packageName: `${scope}/${name ?? ''}`,
|
|
434
|
+
subpath: rest.length > 0 ? rest.join('/') : null,
|
|
435
|
+
};
|
|
436
|
+
}
|
|
437
|
+
const [name, ...rest] = spec.split('/');
|
|
438
|
+
return {
|
|
439
|
+
packageName: name,
|
|
440
|
+
subpath: rest.length > 0 ? rest.join('/') : null,
|
|
441
|
+
};
|
|
442
|
+
}
|
|
443
|
+
function tryParseJSON(content) {
|
|
444
|
+
try {
|
|
445
|
+
return JSON.parse(content);
|
|
446
|
+
}
|
|
447
|
+
catch {
|
|
448
|
+
return null;
|
|
449
|
+
}
|
|
450
|
+
}
|
|
451
|
+
function stripJsonComments(input) {
|
|
452
|
+
let out = '';
|
|
453
|
+
let i = 0;
|
|
454
|
+
let inString = false;
|
|
455
|
+
let escaped = false;
|
|
456
|
+
while (i < input.length) {
|
|
457
|
+
const char = input[i];
|
|
458
|
+
const next = input[i + 1];
|
|
459
|
+
if (inString) {
|
|
460
|
+
out += char;
|
|
461
|
+
if (escaped) {
|
|
462
|
+
escaped = false;
|
|
463
|
+
}
|
|
464
|
+
else if (char === '\\') {
|
|
465
|
+
escaped = true;
|
|
466
|
+
}
|
|
467
|
+
else if (char === '"') {
|
|
468
|
+
inString = false;
|
|
469
|
+
}
|
|
470
|
+
i++;
|
|
471
|
+
continue;
|
|
472
|
+
}
|
|
473
|
+
if (char === '"') {
|
|
474
|
+
inString = true;
|
|
475
|
+
out += char;
|
|
476
|
+
i++;
|
|
477
|
+
continue;
|
|
478
|
+
}
|
|
479
|
+
if (char === '/' && next === '/') {
|
|
480
|
+
i += 2;
|
|
481
|
+
while (i < input.length && input[i] !== '\n')
|
|
482
|
+
i++;
|
|
483
|
+
continue;
|
|
484
|
+
}
|
|
485
|
+
if (char === '/' && next === '*') {
|
|
486
|
+
i += 2;
|
|
487
|
+
while (i < input.length - 1 && !(input[i] === '*' && input[i + 1] === '/'))
|
|
488
|
+
i++;
|
|
489
|
+
i = Math.min(i + 2, input.length);
|
|
490
|
+
continue;
|
|
491
|
+
}
|
|
492
|
+
out += char;
|
|
493
|
+
i++;
|
|
494
|
+
}
|
|
495
|
+
return out;
|
|
496
|
+
}
|
|
497
|
+
export async function loadTSConfig(rootPath, tsConfigPath) {
|
|
498
|
+
const configPath = tsConfigPath
|
|
499
|
+
? path.resolve(rootPath, tsConfigPath)
|
|
500
|
+
: path.join(rootPath, 'tsconfig.json');
|
|
501
|
+
try {
|
|
502
|
+
const content = await fs.readFile(configPath, 'utf-8');
|
|
503
|
+
const parsed = tryParseJSON(content) ?? tryParseJSON(stripJsonComments(content));
|
|
504
|
+
if (!parsed)
|
|
505
|
+
return null;
|
|
506
|
+
const compilerOptions = (parsed.compilerOptions ?? {});
|
|
507
|
+
const paths = compilerOptions.paths;
|
|
508
|
+
const baseUrl = compilerOptions.baseUrl;
|
|
509
|
+
const rootDir = compilerOptions.rootDir;
|
|
510
|
+
const outDir = compilerOptions.outDir;
|
|
511
|
+
return {
|
|
512
|
+
compilerOptions: {
|
|
513
|
+
baseUrl,
|
|
514
|
+
paths,
|
|
515
|
+
rootDir,
|
|
516
|
+
outDir,
|
|
517
|
+
},
|
|
518
|
+
};
|
|
519
|
+
}
|
|
520
|
+
catch {
|
|
521
|
+
return null;
|
|
522
|
+
}
|
|
523
|
+
}
|
|
524
|
+
async function resolveRelative(spec, options) {
|
|
525
|
+
const importerDir = path.dirname(path.resolve(options.rootPath, options.basePath));
|
|
526
|
+
const targetBase = path.resolve(importerDir, spec);
|
|
527
|
+
const resolved = await resolveWithExtensions(targetBase);
|
|
528
|
+
if (resolved) {
|
|
529
|
+
return {
|
|
530
|
+
type: 'local',
|
|
531
|
+
fileId: toFileId(options.rootPath, resolved),
|
|
532
|
+
};
|
|
533
|
+
}
|
|
534
|
+
const specExt = path.extname(spec);
|
|
535
|
+
if (specExt === '.js' || specExt === '.jsx' || specExt === '.mjs' || specExt === '.cjs') {
|
|
536
|
+
const targetWithoutExt = targetBase.slice(0, -specExt.length);
|
|
537
|
+
const tsCompatible = await resolveWithExtensionList(targetWithoutExt, TS_COMPAT_EXTENSIONS);
|
|
538
|
+
if (tsCompatible) {
|
|
539
|
+
return {
|
|
540
|
+
type: 'local',
|
|
541
|
+
fileId: toFileId(options.rootPath, tsCompatible),
|
|
542
|
+
};
|
|
543
|
+
}
|
|
544
|
+
}
|
|
545
|
+
return {
|
|
546
|
+
type: 'unresolved',
|
|
547
|
+
error: `Relative module not found: ${spec}`,
|
|
548
|
+
};
|
|
549
|
+
}
|
|
550
|
+
async function resolveTSPaths(spec, options) {
|
|
551
|
+
if (!options.tsConfig?.compilerOptions?.paths || options.respectTSPaths === false) {
|
|
552
|
+
return null;
|
|
553
|
+
}
|
|
554
|
+
const pathsConfig = options.tsConfig.compilerOptions.paths;
|
|
555
|
+
const baseUrl = options.tsConfig.compilerOptions.baseUrl
|
|
556
|
+
? path.resolve(options.rootPath, options.tsConfig.compilerOptions.baseUrl)
|
|
557
|
+
: options.rootPath;
|
|
558
|
+
for (const [pattern, targets] of Object.entries(pathsConfig)) {
|
|
559
|
+
const wildcardIndex = pattern.indexOf('*');
|
|
560
|
+
const isWildcard = wildcardIndex >= 0;
|
|
561
|
+
if (!isWildcard && pattern !== spec) {
|
|
562
|
+
continue;
|
|
563
|
+
}
|
|
564
|
+
if (isWildcard) {
|
|
565
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
566
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
567
|
+
if (!spec.startsWith(prefix) || !spec.endsWith(suffix)) {
|
|
568
|
+
continue;
|
|
569
|
+
}
|
|
570
|
+
}
|
|
571
|
+
for (const targetPattern of targets) {
|
|
572
|
+
let target = targetPattern;
|
|
573
|
+
if (isWildcard) {
|
|
574
|
+
const prefix = pattern.slice(0, wildcardIndex);
|
|
575
|
+
const suffix = pattern.slice(wildcardIndex + 1);
|
|
576
|
+
const matched = spec.slice(prefix.length, spec.length - suffix.length);
|
|
577
|
+
target = targetPattern.replace('*', matched);
|
|
578
|
+
}
|
|
579
|
+
const absoluteTarget = path.resolve(baseUrl, target);
|
|
580
|
+
const resolved = await resolveWithExtensions(absoluteTarget);
|
|
581
|
+
if (resolved) {
|
|
582
|
+
return {
|
|
583
|
+
type: 'local',
|
|
584
|
+
fileId: toFileId(options.rootPath, resolved),
|
|
585
|
+
};
|
|
586
|
+
}
|
|
587
|
+
}
|
|
588
|
+
}
|
|
589
|
+
return null;
|
|
590
|
+
}
|
|
591
|
+
async function resolveNodeModule(spec, options) {
|
|
592
|
+
const { packageName, subpath } = parsePackageSpec(spec);
|
|
593
|
+
const importerPath = path.resolve(options.rootPath, options.basePath || 'index.ts');
|
|
594
|
+
const importerDir = path.dirname(importerPath);
|
|
595
|
+
const isInsideRoot = (absolutePath) => absolutePath === options.rootPath || absolutePath.startsWith(`${options.rootPath}${path.sep}`);
|
|
596
|
+
const nodeModulesCandidates = [];
|
|
597
|
+
if (options.nodeModulesPath) {
|
|
598
|
+
nodeModulesCandidates.push(options.nodeModulesPath);
|
|
599
|
+
}
|
|
600
|
+
let cursor = importerDir;
|
|
601
|
+
while (true) {
|
|
602
|
+
nodeModulesCandidates.push(path.join(cursor, 'node_modules'));
|
|
603
|
+
const parent = path.dirname(cursor);
|
|
604
|
+
if (parent === cursor)
|
|
605
|
+
break;
|
|
606
|
+
cursor = parent;
|
|
607
|
+
}
|
|
608
|
+
let pkgRoot = null;
|
|
609
|
+
for (const nodeModulesPath of nodeModulesCandidates) {
|
|
610
|
+
const candidate = path.join(nodeModulesPath, packageName);
|
|
611
|
+
if (await safeAccess(candidate)) {
|
|
612
|
+
pkgRoot = candidate;
|
|
613
|
+
break;
|
|
614
|
+
}
|
|
615
|
+
}
|
|
616
|
+
if (!pkgRoot) {
|
|
617
|
+
return {
|
|
618
|
+
type: 'unresolved',
|
|
619
|
+
error: `Package not found: ${packageName}`,
|
|
620
|
+
};
|
|
621
|
+
}
|
|
622
|
+
// Check if this is a workspace package (symlink pointing inside workspace root, but NOT in node_modules)
|
|
623
|
+
if (options.workspaceResolver) {
|
|
624
|
+
const workspaceRoot = options.workspaceResolver.getWorkspaceRoot();
|
|
625
|
+
if (workspaceRoot) {
|
|
626
|
+
const realPath = await fsCache.realpath(pkgRoot);
|
|
627
|
+
if (realPath) {
|
|
628
|
+
const relativeToWorkspace = path.relative(workspaceRoot, realPath);
|
|
629
|
+
// If realpath is inside workspace root (not starting with ..) AND not in node_modules = workspace package
|
|
630
|
+
// Workspace packages are symlinks that point to actual source directories, not node_modules
|
|
631
|
+
const isInsideNodeModules = relativeToWorkspace.includes('node_modules');
|
|
632
|
+
if (!relativeToWorkspace.startsWith('..') && !path.isAbsolute(relativeToWorkspace) && !isInsideNodeModules) {
|
|
633
|
+
// Get package path from resolver, fallback to computed relative path
|
|
634
|
+
const packagePath = options.workspaceResolver.getPackagePath(packageName) ?? relativeToWorkspace;
|
|
635
|
+
return {
|
|
636
|
+
type: 'workspace',
|
|
637
|
+
module: packageName,
|
|
638
|
+
subpath: subpath ?? undefined,
|
|
639
|
+
path: packagePath,
|
|
640
|
+
};
|
|
641
|
+
}
|
|
642
|
+
}
|
|
643
|
+
}
|
|
644
|
+
}
|
|
645
|
+
if (subpath) {
|
|
646
|
+
const subpathResolved = await resolveWithExtensions(path.join(pkgRoot, subpath));
|
|
647
|
+
if (subpathResolved) {
|
|
648
|
+
if (isInsideRoot(subpathResolved)) {
|
|
649
|
+
return {
|
|
650
|
+
type: 'local',
|
|
651
|
+
fileId: toFileId(options.rootPath, subpathResolved),
|
|
652
|
+
module: packageName,
|
|
653
|
+
subpath,
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
return {
|
|
657
|
+
type: 'npm',
|
|
658
|
+
module: packageName,
|
|
659
|
+
subpath,
|
|
660
|
+
};
|
|
661
|
+
}
|
|
662
|
+
}
|
|
663
|
+
const packageJsonPath = path.join(pkgRoot, 'package.json');
|
|
664
|
+
if (await safeAccess(packageJsonPath)) {
|
|
665
|
+
try {
|
|
666
|
+
const packageContent = await fs.readFile(packageJsonPath, 'utf-8');
|
|
667
|
+
const packageJson = JSON.parse(packageContent);
|
|
668
|
+
const main = typeof packageJson.module === 'string'
|
|
669
|
+
? packageJson.module
|
|
670
|
+
: typeof packageJson.main === 'string'
|
|
671
|
+
? packageJson.main
|
|
672
|
+
: null;
|
|
673
|
+
if (main) {
|
|
674
|
+
const mainResolved = await resolveWithExtensions(path.join(pkgRoot, main));
|
|
675
|
+
if (mainResolved) {
|
|
676
|
+
if (isInsideRoot(mainResolved)) {
|
|
677
|
+
return {
|
|
678
|
+
type: 'local',
|
|
679
|
+
fileId: toFileId(options.rootPath, mainResolved),
|
|
680
|
+
module: packageName,
|
|
681
|
+
};
|
|
682
|
+
}
|
|
683
|
+
return {
|
|
684
|
+
type: 'npm',
|
|
685
|
+
module: packageName,
|
|
686
|
+
subpath: subpath ?? undefined,
|
|
687
|
+
};
|
|
688
|
+
}
|
|
689
|
+
}
|
|
690
|
+
}
|
|
691
|
+
catch {
|
|
692
|
+
// ignore invalid package.json and try Node resolver below
|
|
693
|
+
}
|
|
694
|
+
}
|
|
695
|
+
// Prefer Node's real resolver first (exports/main + ancestor node_modules lookup).
|
|
696
|
+
try {
|
|
697
|
+
const req = createRequire(pathToFileURL(importerPath).href);
|
|
698
|
+
const resolvedPath = req.resolve(spec);
|
|
699
|
+
if (BUILTIN_SET.has(resolvedPath)) {
|
|
700
|
+
return { type: 'builtin', module: resolvedPath };
|
|
701
|
+
}
|
|
702
|
+
if (isInsideRoot(resolvedPath)) {
|
|
703
|
+
return {
|
|
704
|
+
type: 'local',
|
|
705
|
+
fileId: toFileId(options.rootPath, resolvedPath),
|
|
706
|
+
module: packageName,
|
|
707
|
+
subpath: subpath ?? undefined,
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
return {
|
|
711
|
+
type: 'npm',
|
|
712
|
+
module: packageName,
|
|
713
|
+
subpath: subpath ?? undefined,
|
|
714
|
+
};
|
|
715
|
+
}
|
|
716
|
+
catch {
|
|
717
|
+
// Fall through to conservative fallback below.
|
|
718
|
+
}
|
|
719
|
+
return {
|
|
720
|
+
type: 'npm',
|
|
721
|
+
module: packageName,
|
|
722
|
+
subpath: subpath ?? undefined,
|
|
723
|
+
};
|
|
724
|
+
}
|
|
725
|
+
export async function resolveModule(spec, options) {
|
|
726
|
+
if (spec.startsWith('.')) {
|
|
727
|
+
return resolveRelative(spec, options);
|
|
728
|
+
}
|
|
729
|
+
const tsPathResolved = await resolveTSPaths(spec, options);
|
|
730
|
+
if (tsPathResolved)
|
|
731
|
+
return tsPathResolved;
|
|
732
|
+
if (BUILTIN_SET.has(spec)) {
|
|
733
|
+
return { type: 'builtin', module: spec };
|
|
734
|
+
}
|
|
735
|
+
return resolveNodeModule(spec, options);
|
|
736
|
+
}
|
|
737
|
+
export class ExportMapBuilder {
|
|
738
|
+
exportMap = new Map();
|
|
739
|
+
factsPerFile = new Map();
|
|
740
|
+
options;
|
|
741
|
+
resolveCache = new Map();
|
|
742
|
+
constructor(options) {
|
|
743
|
+
this.options = options;
|
|
744
|
+
}
|
|
745
|
+
async buildExportMap(factsPerFile) {
|
|
746
|
+
this.factsPerFile = factsPerFile;
|
|
747
|
+
this.exportMap.clear();
|
|
748
|
+
for (const [fileId, facts] of factsPerFile) {
|
|
749
|
+
const fileExports = new Map();
|
|
750
|
+
for (const exp of facts.exports) {
|
|
751
|
+
if (exp.kind === 'reexport') {
|
|
752
|
+
if (exp.name === '*') {
|
|
753
|
+
const resolved = await this.resolveReexport(exp, fileId, new Set([fileId]), fileExports);
|
|
754
|
+
if (resolved) {
|
|
755
|
+
fileExports.set('*', resolved);
|
|
756
|
+
}
|
|
757
|
+
continue;
|
|
758
|
+
}
|
|
759
|
+
const resolved = await this.resolveReexport(exp, fileId, new Set([fileId]), fileExports);
|
|
760
|
+
if (resolved) {
|
|
761
|
+
fileExports.set(exp.name, resolved);
|
|
762
|
+
}
|
|
763
|
+
continue;
|
|
764
|
+
}
|
|
765
|
+
fileExports.set(exp.name, exp.symbolId);
|
|
766
|
+
}
|
|
767
|
+
this.exportMap.set(fileId, fileExports);
|
|
768
|
+
}
|
|
769
|
+
}
|
|
770
|
+
async resolveCached(spec, basePath) {
|
|
771
|
+
const cacheKey = `${basePath}::${spec}`;
|
|
772
|
+
const cached = this.resolveCache.get(cacheKey);
|
|
773
|
+
if (cached)
|
|
774
|
+
return cached;
|
|
775
|
+
const resolved = await resolveModule(spec, {
|
|
776
|
+
...this.options,
|
|
777
|
+
basePath,
|
|
778
|
+
});
|
|
779
|
+
this.resolveCache.set(cacheKey, resolved);
|
|
780
|
+
return resolved;
|
|
781
|
+
}
|
|
782
|
+
async resolveReexport(exp, currentFile, visited, targetMap) {
|
|
783
|
+
if (!exp.fromSpec)
|
|
784
|
+
return null;
|
|
785
|
+
const resolved = await this.resolveCached(exp.fromSpec, currentFile);
|
|
786
|
+
if (resolved.type !== 'local' || !resolved.fileId) {
|
|
787
|
+
if (resolved.type === 'npm' || resolved.type === 'builtin' || resolved.type === 'workspace') {
|
|
788
|
+
return `EXTERNAL:${resolved.module ?? exp.fromSpec}#${exp.name}`;
|
|
789
|
+
}
|
|
790
|
+
return null;
|
|
791
|
+
}
|
|
792
|
+
const sourceFile = resolved.fileId;
|
|
793
|
+
if (visited.has(sourceFile)) {
|
|
794
|
+
return null;
|
|
795
|
+
}
|
|
796
|
+
const sourceFacts = this.factsPerFile.get(sourceFile);
|
|
797
|
+
if (!sourceFacts)
|
|
798
|
+
return null;
|
|
799
|
+
if (exp.name === '*') {
|
|
800
|
+
const localExports = this.exportMap.get(sourceFile);
|
|
801
|
+
if (localExports) {
|
|
802
|
+
for (const [name, symbolId] of localExports) {
|
|
803
|
+
targetMap.set(name, symbolId);
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
return `STAR:${sourceFile}`;
|
|
807
|
+
}
|
|
808
|
+
const sourceExport = sourceFacts.exports.find((e) => e.name === exp.name || e.localName === exp.localName);
|
|
809
|
+
if (!sourceExport)
|
|
810
|
+
return null;
|
|
811
|
+
if (sourceExport.kind === 'reexport') {
|
|
812
|
+
return this.resolveReexport(sourceExport, sourceFile, new Set([...visited, sourceFile]), targetMap);
|
|
813
|
+
}
|
|
814
|
+
return sourceExport.symbolId;
|
|
815
|
+
}
|
|
816
|
+
resolveImport(fileId, importedName) {
|
|
817
|
+
const exports = this.exportMap.get(fileId);
|
|
818
|
+
if (!exports)
|
|
819
|
+
return null;
|
|
820
|
+
return exports.get(importedName) ?? exports.get('default') ?? null;
|
|
821
|
+
}
|
|
822
|
+
getExportMap() {
|
|
823
|
+
return this.exportMap;
|
|
824
|
+
}
|
|
825
|
+
/**
|
|
826
|
+
* Get all local files that were resolved during export map building.
|
|
827
|
+
* This includes files from reexport chains.
|
|
828
|
+
*/
|
|
829
|
+
getResolvedLocalFiles() {
|
|
830
|
+
const files = new Set();
|
|
831
|
+
for (const result of this.resolveCache.values()) {
|
|
832
|
+
if (result.type === 'local' && result.fileId) {
|
|
833
|
+
files.add(result.fileId);
|
|
834
|
+
}
|
|
835
|
+
}
|
|
836
|
+
return files;
|
|
837
|
+
}
|
|
838
|
+
}
|
|
839
|
+
//# sourceMappingURL=resolver.js.map
|