From bb4650d0f2fc39982822dfeb8fd4197e706b8e55 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Mon, 16 Dec 2024 21:40:56 -0500 Subject: [PATCH] feat: resolve file if wildcard element is used (#396) * test: correct path relative to configured filePath * test: add failing test * fix: add resolution step if alias is wildcard at root. Closes #330 --- src/transform.ts | 10 ++++-- src/utils.ts | 35 +++++++++++++++++++++ tests/__fixtures__/resolvePath.ts | 1 + tests/__fixtures__/test.resolvePath.ts | 1 + tests/__fixtures__/utils/test.data.ts | 1 + tests/transform.spec.ts | 42 ++++++++++++++++++-------- 6 files changed, 75 insertions(+), 15 deletions(-) create mode 100644 tests/__fixtures__/resolvePath.ts create mode 100644 tests/__fixtures__/test.resolvePath.ts create mode 100644 tests/__fixtures__/utils/test.data.ts diff --git a/src/transform.ts b/src/transform.ts index a5bdf8a..afdc7d8 100644 --- a/src/transform.ts +++ b/src/transform.ts @@ -2,7 +2,7 @@ import { dirname, isAbsolute, relative, resolve } from 'node:path' import MagicString from 'magic-string' import ts from 'typescript' -import { isRegExp, normalizePath } from './utils' +import { importResolves, isAliasGlobal, isRegExp, normalizePath } from './utils' import type { Alias } from 'vite' @@ -71,9 +71,13 @@ function transformAlias( matchedAlias.find, replacement + (endsWithSlash ? '/' : '') ) - const normalizedPath = normalizePath(relative(dir, resolve(dir, truthPath))) - return normalizedPath.startsWith('.') ? normalizedPath : `./${normalizedPath}` + const absolutePath = resolve(dir, truthPath) + const normalizedPath = normalizePath(relative(dir, absolutePath)) + const resultPath = normalizedPath.startsWith('.') ? normalizedPath : `./${normalizedPath}` + + if (!isAliasGlobal(matchedAlias)) return resultPath + if (importResolves(absolutePath)) return resultPath } } diff --git a/src/utils.ts b/src/utils.ts index 2c8fb47..e598821 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -442,6 +442,41 @@ export function parseTsAliases(basePath: string, paths: ts.MapLike) { return result } +const rootAsteriskImportRE = /^(?!\.{1,2}\/)([^*]+)$/ +export function isAliasGlobal(alias: Alias) { + return alias.find.toString() === rootAsteriskImportRE.toString() +} + +export function importResolves(path: string) { + const files = [ + // js + '.js', + '.jsx', + '.mjs', + '.cjs', + // ts + '.ts', + '.tsx', + '.mts', + '.cts', + '.d.ts', + // json + '.json', + // vue + '.vue', + '.vue.d.ts', + // svelte + '.svelte' + ] + + for (const ext of files) { + if (existsSync(path + ext)) { + return true + } + } + return false +} + export function tryGetPackageInfo(name: string) { if (process.versions.pnp) { const targetRequire = createRequire(import.meta.url) diff --git a/tests/__fixtures__/resolvePath.ts b/tests/__fixtures__/resolvePath.ts new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/tests/__fixtures__/resolvePath.ts @@ -0,0 +1 @@ +export {} diff --git a/tests/__fixtures__/test.resolvePath.ts b/tests/__fixtures__/test.resolvePath.ts new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/tests/__fixtures__/test.resolvePath.ts @@ -0,0 +1 @@ +export {} diff --git a/tests/__fixtures__/utils/test.data.ts b/tests/__fixtures__/utils/test.data.ts new file mode 100644 index 0000000..336ce12 --- /dev/null +++ b/tests/__fixtures__/utils/test.data.ts @@ -0,0 +1 @@ +export {} diff --git a/tests/transform.spec.ts b/tests/transform.spec.ts index c5d8691..17bd686 100644 --- a/tests/transform.spec.ts +++ b/tests/transform.spec.ts @@ -83,14 +83,22 @@ describe('transform tests', () => { it('test: transformCode (process aliases)', () => { const aliases: Alias[] = [ + // '@/*' -> '/*' { find: /^@\/(?!\.{1,2}\/)([^*]+)/, replacement: resolve(__dirname, '../$1') }, + // '@components/*' -> '/src/components/*' { find: /^@components\/(?!\.{1,2}\/)([^*]+)/, replacement: resolve(__dirname, '../src/components/$1') }, + // '~/*' -> '/src/*' { find: /^~\//, replacement: resolve(__dirname, '../src/') }, + // '$src/*' -> '/src/*' { find: '$src', replacement: resolve(__dirname, '../src') }, - { find: /^(?!\.{1,2}\/)([^*]+)/, replacement: resolve(__dirname, '../src/$1') } + // '*' -> '/tests/__fixtures__/*' (needs real path here to test if local file exists) + { + find: /^(?!\.{1,2}\/)([^*]+)$/, + replacement: resolve(__dirname, '../tests/__fixtures__/$1') + } ] const filePath = resolve(__dirname, '../src/index.ts') @@ -148,7 +156,7 @@ describe('transform tests', () => { description: 'wildcard alias at root level with relative import and dot in name', filePath: './src/components/Sample/index.ts', content: 'import { Sample } from "utils/test.data";', - output: "import { Sample } from '../../utils/test.data';\n" + output: "import { Sample } from '../../../tests/__fixtures__/utils/test.data';\n" }, { description: 'import inside folder with named alias at subfolder', @@ -198,9 +206,15 @@ describe('transform tests', () => { output: "import { utilFunction } from '../../../utils/test';\n" }, { - description: 'alias as everything, relative import', - content: 'import { TestBase } from "test";', - output: "import { TestBase } from './test';\n" + description: 'wildcard alias at root, relative import', + filePath: './tests/__fixtures__/index.ts', + content: 'import { TestBase } from "resolvePath";', + output: "import { TestBase } from './resolvePath';\n" + }, + { + description: 'wildcard alias at root, import is likely installed dependency', + content: 'import { nothingReal } from "someDependency";', + output: "import { nothingReal } from 'someDependency';\n" } ] @@ -216,14 +230,14 @@ describe('transform tests', () => { '@/*': ['src/*'], '@components/*': ['src/components/*'], '@src': ['src'], - '*': ['src/utils/*'] + '*': ['tests/__fixtures__/*'] } - const aliases = parseTsAliases(resolve(__dirname), tsPaths) + const aliases = parseTsAliases(resolve(__dirname, '..'), tsPaths) const options = (content: string) => ({ content, - filePath: resolve(__dirname, './src/index.ts'), + filePath: resolve(__dirname, '../src/index.ts'), aliases, aliasesExclude: [], staticImport: true, @@ -243,12 +257,12 @@ describe('transform tests', () => { "import { TestBase } from './test';\n" ) - expect(transformCode(options('import { TestBase } from "test";')).content).toEqual( - "import { TestBase } from './utils/test';\n" + expect(transformCode(options('import { TestBase } from "resolvePath";')).content).toEqual( + "import { TestBase } from '../tests/__fixtures__/resolvePath';\n" ) - expect(transformCode(options('import { TestBase } from "test.path";')).content).toEqual( - "import { TestBase } from './utils/test.path';\n" + expect(transformCode(options('import { TestBase } from "test.resolvePath";')).content).toEqual( + "import { TestBase } from '../tests/__fixtures__/test.resolvePath';\n" ) expect(transformCode(options('import { TestBase } from "./test.path";')).content).toEqual( @@ -258,6 +272,10 @@ describe('transform tests', () => { expect(transformCode(options('import { TestBase } from "../test.path";')).content).toEqual( "import { TestBase } from '../test.path';\n" ) + + expect( + transformCode(options('import { someFutureImport } from "installedDependency";')).content + ).toEqual("import { someFutureImport } from 'installedDependency';\n") }) it('test: transformCode (remove pure imports)', () => {