From eaf193e78b892c622caf7655332343275407eda2 Mon Sep 17 00:00:00 2001 From: "devnexus-automation[bot]" <286661136+devnexus-automation[bot]@users.noreply.github.com> Date: Fri, 22 May 2026 10:14:59 +0200 Subject: [PATCH] Ignore Node built-ins in import graph --- src/typeScriptImportGraphAnalysis.test.ts | 44 +++++++++++++++++++++++ src/typeScriptImportGraphAnalysis.ts | 19 +++++++++- 2 files changed, 62 insertions(+), 1 deletion(-) diff --git a/src/typeScriptImportGraphAnalysis.test.ts b/src/typeScriptImportGraphAnalysis.test.ts index d1b75b7..d5ce715 100644 --- a/src/typeScriptImportGraphAnalysis.test.ts +++ b/src/typeScriptImportGraphAnalysis.test.ts @@ -220,4 +220,48 @@ describe("TypeScript import graph analysis", () => { ]); expect(graph.hubs.map((hub) => hub.filePath)).toEqual(["src/index.ts", "src/real.ts"]); }); + + it("classifies Node built-ins as external imports", () => { + const projectRoot = makeTempProject("node-builtins"); + writeTypeScriptProject(projectRoot, { + "src/index.ts": [ + "import fs from 'node:fs';", + "import path from 'path';", + "export { readFile } from 'node:fs/promises';", + "export const modules = [fs, path];", + "", + ].join("\n"), + }); + + const graph = analyzeTypeScriptImportGraph({ + projectRoot, + include: ["src/**/*.ts"], + }); + + expect(graph.status).toBe("ok"); + expect(graph.summary).toMatchObject({ + moduleCount: 1, + edgeCount: 0, + unresolvedImportCount: 0, + externalImportCount: 3, + }); + expect(graph.unresolvedImports).toEqual([]); + expect(graph.externalImports).toEqual([ + { + from: "src/index.ts", + specifier: "node:fs", + kind: "import", + }, + { + from: "src/index.ts", + specifier: "node:fs/promises", + kind: "export", + }, + { + from: "src/index.ts", + specifier: "path", + kind: "import", + }, + ]); + }); }); diff --git a/src/typeScriptImportGraphAnalysis.ts b/src/typeScriptImportGraphAnalysis.ts index d58d60a..50c5574 100644 --- a/src/typeScriptImportGraphAnalysis.ts +++ b/src/typeScriptImportGraphAnalysis.ts @@ -1,4 +1,4 @@ -import { createRequire } from "node:module"; +import { builtinModules, createRequire } from "node:module"; import path from "node:path"; import type { NexusPluginMcpServerCapability } from "dev-nexus"; import { @@ -25,6 +25,11 @@ const defaultIncludePatterns = [ "src/**/*.cts", ]; +const nodeBuiltinSpecifiers = new Set([ + ...builtinModules, + ...builtinModules.map((moduleName) => `node:${moduleName}`), +]); + export const typeScriptImportGraphToolDescriptors = [ { name: "typescript.importGraph", @@ -466,6 +471,14 @@ function buildImportGraph(input: { moduleResolutionCache, }); if (!resolved) { + if (isNodeBuiltinSpecifier(reference.specifier)) { + externalImports.push({ + from: reference.from, + specifier: reference.specifier, + kind: reference.kind, + }); + continue; + } unresolvedImports.push({ from: reference.from, specifier: reference.specifier, @@ -606,6 +619,10 @@ function resolveImportReference(input: { ); } +function isNodeBuiltinSpecifier(specifier: string): boolean { + return nodeBuiltinSpecifiers.has(specifier); +} + function graphModules( filePaths: string[], edges: TypeScriptImportGraphEdge[],