diff --git a/gitnexus/src/core/ingestion/languages/typescript/nuxt-auto-imports.ts b/gitnexus/src/core/ingestion/languages/typescript/nuxt-auto-imports.ts index 205d66383..905ddfe63 100644 --- a/gitnexus/src/core/ingestion/languages/typescript/nuxt-auto-imports.ts +++ b/gitnexus/src/core/ingestion/languages/typescript/nuxt-auto-imports.ts @@ -123,7 +123,11 @@ export function getNuxtAutoImportEntry( callerFile: string, ): NuxtAutoImportEntry | undefined { if (isNitroServerRuntimeFile(callerFile)) { - return config.serverByLocalName.get(localName) ?? config.clientByLocalName.get(localName); + // Nitro auto-imports only `server/utils/**` into the server context; app + // `composables/` are Vue-app-only. Server callers therefore resolve the + // server map only — no client fallback, which would emit cross-context + // CALLS edges Nitro never actually creates. + return config.serverByLocalName.get(localName); } return config.clientByLocalName.get(localName); } diff --git a/gitnexus/test/fixtures/lang-resolution/nuxt-auto-imports/app.ts b/gitnexus/test/fixtures/lang-resolution/nuxt-auto-imports/app.ts index 4285d154b..b7082c582 100644 --- a/gitnexus/test/fixtures/lang-resolution/nuxt-auto-imports/app.ts +++ b/gitnexus/test/fixtures/lang-resolution/nuxt-auto-imports/app.ts @@ -1,5 +1,6 @@ export function renderClient() { validate(); useAuto(); + useBarrel(); serverOnly(); } diff --git a/gitnexus/test/integration/resolvers/nuxt-scope.test.ts b/gitnexus/test/integration/resolvers/nuxt-scope.test.ts index 16d9fc69e..9dc453e8a 100644 --- a/gitnexus/test/integration/resolvers/nuxt-scope.test.ts +++ b/gitnexus/test/integration/resolvers/nuxt-scope.test.ts @@ -64,7 +64,7 @@ describe('Nuxt/Nitro auto-import scope resolution', () => { expect( calls.find( (edge) => - edge.sourceFilePath.endsWith('server/api/route.ts') && + edge.sourceFilePath.endsWith('app.ts') && edge.target === 'useBarrel' && edge.targetFilePath.endsWith('composables/group/index.ts'), ), @@ -72,12 +72,35 @@ describe('Nuxt/Nitro auto-import scope resolution', () => { expect( imports.find( (edge) => - edge.sourceFilePath.endsWith('server/api/route.ts') && + edge.sourceFilePath.endsWith('app.ts') && edge.targetFilePath.endsWith('composables/group/index.ts'), ), ).toBeDefined(); }); + it('does not resolve client composables from Nitro server callers (no client fallback)', () => { + const calls = nuxtCalls(); + // server/api/route.ts calls validate() (a real server/util), useAuto() and + // useBarrel() (client-only composables). Only the server/util resolves; + // Nitro does not auto-import composables/ server-side, so no edge is emitted + // to either composable. + const composableEdges = calls.filter( + (edge) => + edge.sourceFilePath.endsWith('server/api/route.ts') && + edge.targetFilePath.includes('/composables/'), + ); + expect(composableEdges).toHaveLength(0); + // The legitimate server/util edge still resolves. + expect( + calls.find( + (edge) => + edge.sourceFilePath.endsWith('server/api/route.ts') && + edge.target === 'validate' && + edge.targetFilePath.endsWith('server/utils/serverValidate.ts'), + ), + ).toBeDefined(); + }); + it('does not emit auto-import edges for local shadowing or lexical noise', () => { const calls = nuxtCalls(); diff --git a/gitnexus/test/unit/scope-resolution/typescript/nuxt-auto-imports.test.ts b/gitnexus/test/unit/scope-resolution/typescript/nuxt-auto-imports.test.ts index 19ac329be..7fd27b4db 100644 --- a/gitnexus/test/unit/scope-resolution/typescript/nuxt-auto-imports.test.ts +++ b/gitnexus/test/unit/scope-resolution/typescript/nuxt-auto-imports.test.ts @@ -68,6 +68,8 @@ describe('loadNuxtAutoImports', () => { expect(getNuxtAutoImportEntry(config!, 'validate', 'app.vue')).toMatchObject({ sourceFile: 'composables/clientValidate.ts', }); + // A Nitro server caller does NOT fall back to a client-only composable. + expect(getNuxtAutoImportEntry(config!, 'useAlias', 'server/api/users.ts')).toBeUndefined(); }); it('resolves extensionless directory imports to index files', async () => {