mirror of
https://github.com/Egonex-AI/Understand-Anything.git
synced 2026-06-22 10:58:03 +08:00
Merge pull request #227 from ZebangCheng/fix/tsconfig-path-leading-dot-slash
fix(extract-import-map): normalize tsconfig path-alias candidates with leading "./" (#214)
This commit is contained in:
@@ -237,6 +237,111 @@ describe('extract-import-map.mjs — TypeScript / JavaScript resolver', () => {
|
||||
'packages/foo/src/y.ts',
|
||||
);
|
||||
});
|
||||
|
||||
// ── Issue #214: tsconfig path-alias targets with leading "./" ───────────
|
||||
// create-next-app ships `"@/*": ["./*"]` as the default. With a root
|
||||
// tsconfig the candidate would stay as "./lib/thing" while ctx.fileSet
|
||||
// stores normalized "lib/thing", silently dropping every cross-module
|
||||
// import edge. Three originally broken cases plus one regression guard
|
||||
// for the already working `["*"]` form.
|
||||
|
||||
it('resolves tsconfig paths with leading "./" target and no baseUrl (#214)', () => {
|
||||
projectRoot = setupTree({
|
||||
'tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
paths: { '@/*': ['./*'] },
|
||||
},
|
||||
}),
|
||||
'src/app.ts': `import { x } from '@/lib/thing';\nconst _ = x;\n`,
|
||||
'lib/thing.ts': `export const x = 1;\n`,
|
||||
});
|
||||
|
||||
const result = runScript(projectRoot, {
|
||||
projectRoot,
|
||||
files: [
|
||||
{ path: 'tsconfig.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'src/app.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'lib/thing.ts', language: 'typescript', fileCategory: 'code' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.output.importMap['src/app.ts']).toContain('lib/thing.ts');
|
||||
});
|
||||
|
||||
it('resolves tsconfig paths with leading "./" target and baseUrl "." (#214)', () => {
|
||||
projectRoot = setupTree({
|
||||
'tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
baseUrl: '.',
|
||||
paths: { '@/*': ['./*'] },
|
||||
},
|
||||
}),
|
||||
'src/app.ts': `import { x } from '@/lib/thing';\nconst _ = x;\n`,
|
||||
'lib/thing.ts': `export const x = 1;\n`,
|
||||
});
|
||||
|
||||
const result = runScript(projectRoot, {
|
||||
projectRoot,
|
||||
files: [
|
||||
{ path: 'tsconfig.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'src/app.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'lib/thing.ts', language: 'typescript', fileCategory: 'code' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.output.importMap['src/app.ts']).toContain('lib/thing.ts');
|
||||
});
|
||||
|
||||
it('resolves tsconfig paths with leading "./" target and baseUrl "src" (#214)', () => {
|
||||
projectRoot = setupTree({
|
||||
'tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
baseUrl: 'src',
|
||||
paths: { '@/*': ['./*'] },
|
||||
},
|
||||
}),
|
||||
'src/app.ts': `import { x } from '@/thing';\nconst _ = x;\n`,
|
||||
'src/thing.ts': `export const x = 1;\n`,
|
||||
});
|
||||
|
||||
const result = runScript(projectRoot, {
|
||||
projectRoot,
|
||||
files: [
|
||||
{ path: 'tsconfig.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'src/app.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'src/thing.ts', language: 'typescript', fileCategory: 'code' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.output.importMap['src/app.ts']).toContain('src/thing.ts');
|
||||
});
|
||||
|
||||
it('keeps resolving tsconfig paths with bare "*" target (#214 regression guard)', () => {
|
||||
projectRoot = setupTree({
|
||||
'tsconfig.json': JSON.stringify({
|
||||
compilerOptions: {
|
||||
paths: { '@/*': ['*'] },
|
||||
},
|
||||
}),
|
||||
'src/app.ts': `import { x } from '@/lib/thing';\nconst _ = x;\n`,
|
||||
'lib/thing.ts': `export const x = 1;\n`,
|
||||
});
|
||||
|
||||
const result = runScript(projectRoot, {
|
||||
projectRoot,
|
||||
files: [
|
||||
{ path: 'tsconfig.json', language: 'json', fileCategory: 'config' },
|
||||
{ path: 'src/app.ts', language: 'typescript', fileCategory: 'code' },
|
||||
{ path: 'lib/thing.ts', language: 'typescript', fileCategory: 'code' },
|
||||
],
|
||||
});
|
||||
|
||||
expect(result.status).toBe(0);
|
||||
expect(result.output.importMap['src/app.ts']).toContain('lib/thing.ts');
|
||||
});
|
||||
});
|
||||
|
||||
describe('extract-import-map.mjs — Python resolver', () => {
|
||||
|
||||
@@ -430,9 +430,18 @@ export function resolveTsJsImport(rawImport, file, ctx) {
|
||||
const relativeToConfig = normalizedBase
|
||||
? posix.join(normalizedBase, mapped)
|
||||
: mapped;
|
||||
const candidate = tsConfigDir
|
||||
? posix.join(tsConfigDir, relativeToConfig)
|
||||
: relativeToConfig;
|
||||
// posix.normalize strips a leading "./" left over when both
|
||||
// tsConfigDir and normalizedBase are empty (root tsconfig with
|
||||
// `"@/*": ["./*"]`, the create-next-app default). Without this the
|
||||
// candidate stays as "./foo" while ctx.fileSet stores "foo", and
|
||||
// probeWithExtensions silently drops every cross-module edge.
|
||||
const candidate = posix.normalize(
|
||||
tsConfigDir
|
||||
? posix.join(tsConfigDir, relativeToConfig)
|
||||
: relativeToConfig,
|
||||
);
|
||||
// Defensive: tsconfig targets shouldn't escape the project root.
|
||||
if (candidate.startsWith('..')) continue;
|
||||
const probed = probeWithExtensions(candidate, ctx.fileSet);
|
||||
if (probed) return probed;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user