Skip to content

Commit 83503cc

Browse files
committed
fix issues
1 parent c25cafc commit 83503cc

File tree

2 files changed

+100
-6
lines changed

2 files changed

+100
-6
lines changed

server/utils/import-resolver.ts

Lines changed: 94 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,37 @@ function getExtensionPriority(sourceFile: string): string[][] {
103103
return [[], ['.ts', '.js'], ['.d.ts'], ['.json']]
104104
}
105105

106+
/**
107+
* Resolve an alias specifier to the directory path within a file path.
108+
* Supports #, ~, and @ prefixes (e.g. #app, ~/app, @/app).
109+
* The alias must match a path segment exactly (no partial matches).
110+
*/
111+
export function resolveAliasToDir(aliasSpec: string, filePath?: string | null): string | null {
112+
if (
113+
(!aliasSpec.startsWith('#') && !aliasSpec.startsWith('~') && !aliasSpec.startsWith('@')) ||
114+
!filePath
115+
) {
116+
return null
117+
}
118+
119+
// Support #app, #/app, ~app, ~/app, @app, @/app
120+
const alias = aliasSpec.replace(/^[#~@]\/?/, '')
121+
const segments = filePath.split('/')
122+
123+
let lastMatchIndex = -1
124+
for (let i = 0; i < segments.length; i++) {
125+
if (segments[i] === alias) {
126+
lastMatchIndex = i
127+
}
128+
}
129+
130+
if (lastMatchIndex === -1) {
131+
return null
132+
}
133+
134+
return segments.slice(0, lastMatchIndex + 1).join('/')
135+
}
136+
106137
/**
107138
* Get index file extensions to try for directory imports.
108139
*/
@@ -222,6 +253,60 @@ function normalizeInternalImportTarget(target: InternalImportTarget): string | n
222253
return null
223254
}
224255

256+
function guessInternalImportTarget(
257+
imports: InternalImportsMap,
258+
specifier: string,
259+
files: FileSet,
260+
currentFile: string,
261+
): string | null {
262+
for (const [key, value] of Object.entries(imports)) {
263+
if (specifier.startsWith(key)) {
264+
const basePath = resolveAliasToDir(key, normalizeInternalImportTarget(value))
265+
if (!basePath) continue
266+
267+
const suffix = specifier.substring(key.length).trim().replace(/^\//, '')
268+
const pathWithoutExt = suffix ? `${basePath}/${suffix}` : basePath
269+
270+
const toCheckPath = (p: string) => files.has(normalizePath(p)) || files.has(p)
271+
272+
// Path already has an extension-like suffix on the last segment - return as is if exists
273+
const filename = pathWithoutExt.split('/').pop() ?? ''
274+
if (filename.includes('.') && !filename.endsWith('.')) {
275+
if (toCheckPath(pathWithoutExt)) {
276+
return pathWithoutExt.startsWith('./') ? pathWithoutExt : `./${pathWithoutExt}`
277+
}
278+
return null
279+
}
280+
281+
// Try adding extensions based on currentFile type
282+
const extensionGroups = getExtensionPriority(currentFile)
283+
for (const extensions of extensionGroups) {
284+
if (extensions.length === 0) {
285+
if (toCheckPath(pathWithoutExt)) {
286+
return pathWithoutExt.startsWith('./') ? pathWithoutExt : `./${pathWithoutExt}`
287+
}
288+
} else {
289+
for (const ext of extensions) {
290+
const pathWithExt = pathWithoutExt + ext
291+
if (toCheckPath(pathWithExt)) {
292+
return pathWithExt.startsWith('./') ? pathWithExt : `./${pathWithExt}`
293+
}
294+
}
295+
}
296+
}
297+
298+
// Try as directory with index file
299+
for (const indexFile of getIndexExtensions(currentFile)) {
300+
const indexPath = `${pathWithoutExt}/${indexFile}`
301+
if (toCheckPath(indexPath)) {
302+
return indexPath.startsWith('./') ? indexPath : `./${indexPath}`
303+
}
304+
}
305+
}
306+
}
307+
return null
308+
}
309+
225310
/**
226311
* import ... from '#components/Button.vue'
227312
* import ... from '#/components/Button.vue'
@@ -230,6 +315,7 @@ function normalizeInternalImportTarget(target: InternalImportTarget): string | n
230315
*/
231316
export function resolveInternalImport(
232317
specifier: string,
318+
currentFile: string,
233319
imports: InternalImportsMap | undefined,
234320
files: FileSet,
235321
): ResolvedImport | null {
@@ -239,8 +325,12 @@ export function resolveInternalImport(
239325
return null
240326
}
241327

242-
const target = normalizeInternalImportTarget(imports[cleanSpecifier])
243-
console.log('resolved internal import', imports, cleanSpecifier, target)
328+
const importTarget = normalizeInternalImportTarget(imports[cleanSpecifier])
329+
const target =
330+
importTarget != null
331+
? importTarget
332+
: guessInternalImportTarget(imports, cleanSpecifier, files, currentFile)
333+
244334
if (!target || !target.startsWith('./')) {
245335
return null
246336
}
@@ -265,8 +355,8 @@ export function createImportResolver(
265355
): (specifier: string) => string | null {
266356
return (specifier: string) => {
267357
const relativeResolved = resolveRelativeImport(specifier, currentFile, files)
268-
const internalResolved = resolveInternalImport(specifier, internalImports, files)
269-
const resolved = relativeResolved ?? internalResolved
358+
const internalResolved = resolveInternalImport(specifier, currentFile, internalImports, files)
359+
const resolved = relativeResolved != null ? relativeResolved : internalResolved
270360

271361
if (resolved) {
272362
return `/package-code/${packageName}/v/${version}/${resolved.path}`

test/unit/server/utils/import-resolver.spec.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,7 @@ describe('resolveInternalSpecifier', () => {
197197

198198
const resolved = resolveInternalImport(
199199
'#app/nuxt',
200+
'dist/index.js',
200201
{
201202
'#app/nuxt': './dist/app/nuxt.js',
202203
},
@@ -211,6 +212,7 @@ describe('resolveInternalSpecifier', () => {
211212

212213
const resolved = resolveInternalImport(
213214
'#app/nuxt',
215+
'dist/index.js',
214216
{
215217
'#app/nuxt': { import: './dist/app/nuxt.js' },
216218
},
@@ -225,6 +227,7 @@ describe('resolveInternalSpecifier', () => {
225227

226228
const resolved = resolveInternalImport(
227229
'#app/nuxt',
230+
'dist/index.js',
228231
{
229232
'#app/nuxt': './dist/app/nuxt.js',
230233
},
@@ -234,17 +237,18 @@ describe('resolveInternalSpecifier', () => {
234237
expect(resolved).toBeNull()
235238
})
236239

237-
it('returns null for unknown internal specifiers', () => {
240+
it('resolves prefix matches with extension resolution via guessInternalImportTarget', () => {
238241
const files = new Set<string>(['dist/app/nuxt.js'])
239242

240243
const resolved = resolveInternalImport(
241244
'#app/nuxt',
245+
'dist/index.js',
242246
{
243247
'#app': './dist/app/index.js',
244248
},
245249
files,
246250
)
247251

248-
expect(resolved).toBeNull()
252+
expect(resolved?.path).toBe('dist/app/nuxt.js')
249253
})
250254
})

0 commit comments

Comments
 (0)