fix: address Nuxt auto-import review follow-ups

This commit is contained in:
Gergo Magyar 2026-06-24 07:18:14 +00:00
parent 83b1246e45
commit 8e42d2dfb4
5 changed files with 55 additions and 11 deletions

View file

@ -271,7 +271,7 @@ async function dirExists(dirPath: string): Promise<boolean> {
}
}
/** Recursively collect `.ts` and `.tsx` files under a directory. */
/** Recursively collect supported TypeScript/JavaScript files under a directory. */
async function collectTsFiles(dir: string): Promise<string[]> {
const results: string[] = [];
let entries: import('fs').Dirent[];
@ -285,13 +285,17 @@ async function collectTsFiles(dir: string): Promise<string[]> {
const full = path.join(dir, entry.name);
if (entry.isDirectory()) {
results.push(...(await collectTsFiles(full)));
} else if (entry.isFile() && (entry.name.endsWith('.ts') || entry.name.endsWith('.tsx'))) {
} else if (entry.isFile() && hasSupportedSourceExtension(entry.name)) {
results.push(full);
}
}
return results;
}
function hasSupportedSourceExtension(fileName: string): boolean {
return FILE_EXTENSIONS.some((ext) => fileName.endsWith(ext));
}
function extractNitroExportNames(content: string): string[] {
const names = new Set<string>();

View file

@ -12,7 +12,7 @@
* ./query.ts (TYPESCRIPT_SCOPE_QUERY constant).
*/
import type { ParsedFile, ScopeId } from 'gitnexus-shared';
import type { NodeLabel, ParsedFile, ScopeId } from 'gitnexus-shared';
import { SupportedLanguages } from 'gitnexus-shared';
import { generateId } from '../../../../lib/utils.js';
import { buildMro, defaultLinearize } from '../../scope-resolution/passes/mro.js';
@ -43,6 +43,16 @@ interface TypescriptResolutionConfig {
readonly nuxtAutoImports: NuxtAutoImportConfig | null;
}
const TYPESCRIPT_TYPE_ONLY_BINDING_TYPES = new Set<NodeLabel>([
'Interface',
'Type',
'TypeAlias',
'Typedef',
'Trait',
'Annotation',
'Decorator',
]);
/**
* Build a `resolveImportTarget` adapter that memoizes the workspace
* file list, the lower-cased file list, and the per-pass `resolveCache`
@ -278,6 +288,9 @@ const typescriptScopeResolver: ScopeResolver = {
},
};
function occupiesTypeScriptValueSpace(type: NodeLabel): boolean {
return !TYPESCRIPT_TYPE_ONLY_BINDING_TYPES.has(type);
}
function hasLocalBindingInScopeChain(
scopeId: ScopeId,
@ -295,7 +308,12 @@ function hasLocalBindingInScopeChain(
const localBindings = scope.bindings.get(name);
if (
localBindings?.some((binding) => binding.origin === 'local' && binding.def.filePath === filePath)
localBindings?.some(
(binding) =>
binding.origin === 'local' &&
binding.def.filePath === filePath &&
occupiesTypeScriptValueSpace(binding.def.type),
)
) {
return true;
}

View file

@ -0,0 +1,7 @@
interface useAuto {
value: string;
}
export function renderTypeOnly() {
return useAuto();
}

View file

@ -1,11 +1,6 @@
import { describe, it, expect, beforeAll } from 'vitest';
import path from 'path';
import {
FIXTURES,
getRelationships,
runPipelineFromRepo,
type PipelineResult,
} from './helpers.js';
import { FIXTURES, getRelationships, runPipelineFromRepo, type PipelineResult } from './helpers.js';
describe('Nuxt/Nitro auto-import scope resolution', () => {
let result: PipelineResult;
@ -17,7 +12,9 @@ describe('Nuxt/Nitro auto-import scope resolution', () => {
}, 60000);
function nuxtCalls() {
return getRelationships(result, 'CALLS').filter((edge) => edge.rel.reason === 'nuxt-auto-import');
return getRelationships(result, 'CALLS').filter(
(edge) => edge.rel.reason === 'nuxt-auto-import',
);
}
it('prefers server/utils over client composables for same-named server calls', () => {
@ -88,6 +85,19 @@ describe('Nuxt/Nitro auto-import scope resolution', () => {
expect(calls.filter((edge) => edge.sourceFilePath.endsWith('pages/noise.ts'))).toHaveLength(0);
});
it('allows type-only local declarations to coexist with value auto-import calls', () => {
const calls = nuxtCalls();
expect(
calls.find(
(edge) =>
edge.sourceFilePath.endsWith('pages/type-only.ts') &&
edge.target === 'useAuto' &&
edge.targetFilePath.endsWith('composables/useAuto.ts'),
),
).toBeDefined();
});
it('suppresses only explicitly imported local names, not every symbol from the same source', () => {
const calls = nuxtCalls();

View file

@ -98,6 +98,7 @@ describe('loadNuxtAutoImports', () => {
'export var delta = () => {};',
].join('\n'),
);
writeFile(root, 'server/utils/jsHelper.js', 'export function jsServerTool() {}');
writeFile(root, 'server/utils/dist/generated.ts', 'export function generatedUtility() {}');
const config = await loadNuxtAutoImports(root);
@ -111,7 +112,11 @@ describe('loadNuxtAutoImports', () => {
'delta',
'fn',
'gamma',
'jsServerTool',
]);
expect(config!.serverByLocalName.get('jsServerTool')).toMatchObject({
sourceFile: 'server/utils/jsHelper.js',
});
});
});