From 63bed79e9895ebb5c82426606683f098da68344a Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Tue, 27 Aug 2024 20:52:11 -0400 Subject: [PATCH 1/6] test(transform): add failing integration test for transformCode --- tests/transform.spec.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/tests/transform.spec.ts b/tests/transform.spec.ts index 2ff8fa3..7bcd646 100644 --- a/tests/transform.spec.ts +++ b/tests/transform.spec.ts @@ -2,6 +2,7 @@ import { resolve } from 'node:path' import { describe, expect, it } from 'vitest' import { hasExportDefault, normalizeGlob, transformCode } from '../src/transform' +import { parseTsAliases } from '../src/utils' import type { Alias } from 'vite' @@ -140,6 +141,35 @@ describe('transform tests', () => { ).toEqual("function d(param: import('./test').E): import('./test').F") }) + it('test: transformCode (integration test)', () => { + const tsPaths = { + '@/*': ['src/*'], + '@components/*': ['src/components/*'], + '@src': ['src'], + '*': ['src/utils/*'] + } + + const aliases = parseTsAliases(resolve(__dirname), tsPaths) + + const options = (content: string) => ({ + content, + filePath: resolve(__dirname, './src/index.ts'), + aliases, + aliasesExclude: [], + staticImport: true, + clearPureImport: true, + cleanVueFileName: true + }) + + expect(transformCode(options('import { TestBase } from "@/test";')).content).toEqual( + "import { TestBase } from './test';\n" + ) + + expect(transformCode(options('import { TestNested } from "@/nested/test";')).content).toEqual( + "import { TestNested } from './nested/test';\n" + ) + }) + it('test: transformCode (remove pure imports)', () => { const options = (content: string) => ({ content, From 29f8a7951d50d0cf84aa486ec8fc90c0c32c6d76 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Tue, 27 Aug 2024 20:55:16 -0400 Subject: [PATCH 2/6] fix(utils): correct issue with failing integration test --- src/utils.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/utils.ts b/src/utils.ts index b8e33fd..c4ddf30 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -442,7 +442,7 @@ export function parseTsAliases(basePath: string, paths: ts.MapLike) { for (const [pathWithAsterisk, replacements] of Object.entries(paths)) { const find = new RegExp( - `^${pathWithAsterisk.replace(regexpSymbolRE, '\\$1').replace(asteriskRE, '([^\\/]+)')}$` + `^${pathWithAsterisk.replace(regexpSymbolRE, '\\$1').replace(asteriskRE, '(.+)')}$` ) let index = 1 From ab9b5c1739b7d5bc0cc46198f7023fc1543b8c38 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Tue, 27 Aug 2024 21:04:13 -0400 Subject: [PATCH 3/6] test(utils): add tests for parseTsAliases --- tests/utils.spec.ts | 82 +++++++++++++++++++++++++++++++++++++++------ 1 file changed, 71 insertions(+), 11 deletions(-) diff --git a/tests/utils.spec.ts b/tests/utils.spec.ts index 3f53653..6b82636 100644 --- a/tests/utils.spec.ts +++ b/tests/utils.spec.ts @@ -1,6 +1,3 @@ -/* eslint-disable prefer-regex-literals */ -/* eslint-disable promise/param-names */ - import { normalize, resolve } from 'node:path' import { existsSync } from 'node:fs' import { describe, expect, it } from 'vitest' @@ -15,6 +12,7 @@ import { isRegExp, mergeObjects, normalizePath, + parseTsAliases, queryPublicPath, toCapitalCase, unwrapPromise @@ -160,6 +158,74 @@ describe('utils tests', () => { } }) + it('test: parseTsAliases', () => { + expect( + parseTsAliases('/tmp/fake/project/root', { + '@/*': ['./at/*'] + }) + ).toStrictEqual([ + { + find: /^@\/(.+)$/, + replacement: '/tmp/fake/project/root/at/$1' + } + ]) + + expect(parseTsAliases('/tmp/fake/project/root', { '~/*': ['./tilde/*'] })).toStrictEqual([ + { + find: /^~\/(.+)$/, + replacement: '/tmp/fake/project/root/tilde/$1' + } + ]) + + expect( + parseTsAliases('/tmp/fake/project/root', { '@/no-dot-prefix/*': ['no-dot-prefix/*'] }) + ).toStrictEqual([ + { + find: /^@\/no-dot-prefix\/(.+)$/, + replacement: '/tmp/fake/project/root/no-dot-prefix/$1' + } + ]) + + expect( + parseTsAliases('/tmp/fake/project/root', { '@/components/*': ['./at/components/*'] }) + ).toStrictEqual([ + { + find: /^@\/components\/(.+)$/, + replacement: '/tmp/fake/project/root/at/components/$1' + } + ]) + + expect(parseTsAliases('/tmp/fake/project/root', { 'top/*': ['./top/*'] })).toStrictEqual([ + { + find: /^top\/(.+)$/, + replacement: '/tmp/fake/project/root/top/$1' + } + ]) + + expect(parseTsAliases('/tmp/fake/project/root', { '@src': ['./src'] })).toStrictEqual([ + { + find: /^@src$/, + replacement: '/tmp/fake/project/root/src' + } + ]) + + // https://github.com/qmhc/vite-plugin-dts/issues/330 + expect(parseTsAliases('/tmp/fake/project/root', { '*': ['./src/*'] })).toStrictEqual([ + { + find: /^(.+)$/, + replacement: '/tmp/fake/project/root/src/$1' + } + ]) + + // https://github.com/qmhc/vite-plugin-dts/issues/290#issuecomment-1872495764 + expect(parseTsAliases('/tmp/fake/project/root', { '#*': ['./hashed/*'] })).toStrictEqual([ + { + find: /^#(.+)$/, + replacement: '/tmp/fake/project/root/hashed/$1' + } + ]) + }) + it('test: toCapitalCase', () => { expect(toCapitalCase('abc')).toEqual('Abc') expect(toCapitalCase('aa-bb-cc')).toEqual('AaBbCc') @@ -178,14 +244,8 @@ describe('utils tests', () => { const root = normalizePath(resolve(__dirname, '..')) const entryRoot = resolve(root, 'src') - expect( - getTsLibFolder({ root, entryRoot }) - ).toMatch(/node_modules\/typescript$/) + expect(getTsLibFolder({ root, entryRoot })).toMatch(/node_modules\/typescript$/) - expect( - existsSync( - getTsLibFolder({ root, entryRoot }) || '' - ) - ).toBe(true) + expect(existsSync(getTsLibFolder({ root, entryRoot }) || '')).toBe(true) }) }) From 8a0c1406a97e217c1ccdfc0addf69351294eb934 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Tue, 27 Aug 2024 21:08:14 -0400 Subject: [PATCH 4/6] test(transform): refactor process aliases test with helper and descriptions, add more cases --- tests/transform.spec.ts | 120 ++++++++++++++++++++++++++-------------- 1 file changed, 78 insertions(+), 42 deletions(-) diff --git a/tests/transform.spec.ts b/tests/transform.spec.ts index 7bcd646..a9fe7a2 100644 --- a/tests/transform.spec.ts +++ b/tests/transform.spec.ts @@ -89,56 +89,92 @@ describe('transform tests', () => { { find: '$src', replacement: resolve(__dirname, '../src') } ] const filePath = resolve(__dirname, '../src/index.ts') - const options = (content: string) => ({ + + const options = ( + content: string, + optFilePath: string = filePath, + optAliases: Alias[] = aliases + ) => ({ content, - filePath, - aliases, + filePath: optFilePath, + aliases: optAliases, aliasesExclude: [], staticImport: false, clearPureImport: false, cleanVueFileName: false }) - expect(transformCode(options('import type { TestBase } from "@/src/test";')).content).toEqual( - "import { TestBase } from './test';\n" - ) - - expect(transformCode(options('import("@/components/test").Test;')).content).toEqual( - "import('../components/test').Test;" - ) - expect( - transformCode(options('import type { TestBase } from "@/components/test";')).content - ).toEqual("import { TestBase } from '../components/test';\n") - - expect(transformCode(options('import("@/components/test").Test;\n')).content).toEqual( - "import('../components/test').Test;\n" - ) - - expect( - transformCode( - options('import VContainer from "@components/layout/container/VContainer.vue";') - ).content - ).toEqual( - "import { default as VContainer } from './components/layout/container/VContainer.vue';\n" - ) - - expect(transformCode(options('import type { TestBase } from "~/test";')).content).toEqual( - "import { TestBase } from './test';\n" - ) - - expect(transformCode(options('import type { TestBase } from "$src/test";')).content).toEqual( - "import { TestBase } from './test';\n" - ) - - expect( - transformCode( - options("const a: import('~/test').A<{ b: import('~/test').B }>") - ).content - ).toEqual("const a: import('./test').A<{ b: import('./test').B }>") + const tests: Array<{ + description: string, + content: string, + output: string, + filePath?: string, + aliases?: Alias[] + }> = [ + { + description: 'type import alias at root level', + content: 'import type { TestBase } from "@/src/test";', + output: "import { TestBase } from './test';\n" + }, + { + description: 'dynamic import inside subfolder with alias at root level', + content: 'import("@/components/test").Test;', + output: "import('../components/test').Test;" + }, + { + description: 'import inside folder with named alias at subfolder', + content: 'import type { TestBase } from "@/components/test";', + output: "import { TestBase } from '../components/test';\n" + }, + { + description: 'dynamic import inside subfolder with alias at root level', + content: 'import("@/components/test").Test;\n', + output: "import('../components/test').Test;\n" + }, + { + description: 'named alias in subfolder with default import', + content: 'import VContainer from "@components/layout/container/VContainer.vue";', + output: + "import { default as VContainer } from './components/layout/container/VContainer.vue';\n" + }, + { + description: 'alias at root level with tilde and no asterisk', + content: 'import { TestBase } from "~/test";', + output: "import { TestBase } from './test';\n" + }, + { + description: 'named alias at root with tilde and no asterisk', + content: 'import type { TestBase } from "$src/test";', + output: "import { TestBase } from './test';\n" + }, + { + description: 'type imports with alias at root level', + content: "const a: import('~/test').A<{ b: import('~/test').B }>", + output: "const a: import('./test').A<{ b: import('./test').B }>" + }, + { + description: 'function param and return type imports with alias at root level', + content: "function d(param: import('~/test').E): import('~/test').F", + output: "function d(param: import('./test').E): import('./test').F" + }, + { + description: 'import inside subfolder with alias at root level', + content: 'import { NestedBase } from "@/test/nested";', + output: "import { NestedBase } from '../test/nested';\n" + }, + { + description: 'alias at root level, file nested', + filePath: './src/child/folder/test.ts', + content: 'import { utilFunction } from "@/utils/test";', + output: "import { utilFunction } from '../../../utils/test';\n" + } + ] - expect( - transformCode(options("function d(param: import('~/test').E): import('~/test').F")).content - ).toEqual("function d(param: import('./test').E): import('./test').F") + tests.forEach(({ description, content, filePath, aliases, output }) => { + expect(transformCode(options(content, filePath, aliases)).content, description).toEqual( + output + ) + }) }) it('test: transformCode (integration test)', () => { From 06550ea5cf836c027ce2ce85d33949f05997e059 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Tue, 27 Aug 2024 21:39:32 -0400 Subject: [PATCH 5/6] test: adds test cases from issue and fixes #330 --- tests/transform.spec.ts | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/tests/transform.spec.ts b/tests/transform.spec.ts index a9fe7a2..a33ee1f 100644 --- a/tests/transform.spec.ts +++ b/tests/transform.spec.ts @@ -167,6 +167,12 @@ describe('transform tests', () => { filePath: './src/child/folder/test.ts', content: 'import { utilFunction } from "@/utils/test";', output: "import { utilFunction } from '../../../utils/test';\n" + }, + { + description: 'alias as everything, relative import', + aliases: [{ find: /^(.+)$/, replacement: resolve(__dirname, '../src/$1') }], + content: 'import { TestBase } from "test";', + output: "import { TestBase } from './test';\n" } ] @@ -204,6 +210,10 @@ describe('transform tests', () => { expect(transformCode(options('import { TestNested } from "@/nested/test";')).content).toEqual( "import { TestNested } from './nested/test';\n" ) + + expect(transformCode(options('import { TestBase } from "./test";')).content).toEqual( + "import { TestBase } from './utils/test';\n" + ) }) it('test: transformCode (remove pure imports)', () => { From 1a684ae52c1893d9129ffa873a905cd003374b66 Mon Sep 17 00:00:00 2001 From: Lachlan Heywood Date: Thu, 29 Aug 2024 20:04:52 -0400 Subject: [PATCH 6/6] test(utils): handle windows path --- tests/utils.spec.ts | 23 +++++++++++++++-------- 1 file changed, 15 insertions(+), 8 deletions(-) diff --git a/tests/utils.spec.ts b/tests/utils.spec.ts index 6b82636..40c849d 100644 --- a/tests/utils.spec.ts +++ b/tests/utils.spec.ts @@ -159,6 +159,9 @@ describe('utils tests', () => { }) it('test: parseTsAliases', () => { + const maybeWindowsPath = (path: string) => + new RegExp('^([a-zA-Z]:)?' + path.replace('$', '\\$')) + expect( parseTsAliases('/tmp/fake/project/root', { '@/*': ['./at/*'] @@ -166,14 +169,14 @@ describe('utils tests', () => { ).toStrictEqual([ { find: /^@\/(.+)$/, - replacement: '/tmp/fake/project/root/at/$1' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/at/$1')) } ]) expect(parseTsAliases('/tmp/fake/project/root', { '~/*': ['./tilde/*'] })).toStrictEqual([ { find: /^~\/(.+)$/, - replacement: '/tmp/fake/project/root/tilde/$1' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/tilde/$1')) } ]) @@ -182,7 +185,9 @@ describe('utils tests', () => { ).toStrictEqual([ { find: /^@\/no-dot-prefix\/(.+)$/, - replacement: '/tmp/fake/project/root/no-dot-prefix/$1' + replacement: expect.stringMatching( + maybeWindowsPath('/tmp/fake/project/root/no-dot-prefix/$1') + ) } ]) @@ -191,21 +196,23 @@ describe('utils tests', () => { ).toStrictEqual([ { find: /^@\/components\/(.+)$/, - replacement: '/tmp/fake/project/root/at/components/$1' + replacement: expect.stringMatching( + maybeWindowsPath('/tmp/fake/project/root/at/components/$1') + ) } ]) expect(parseTsAliases('/tmp/fake/project/root', { 'top/*': ['./top/*'] })).toStrictEqual([ { find: /^top\/(.+)$/, - replacement: '/tmp/fake/project/root/top/$1' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/top/$1')) } ]) expect(parseTsAliases('/tmp/fake/project/root', { '@src': ['./src'] })).toStrictEqual([ { find: /^@src$/, - replacement: '/tmp/fake/project/root/src' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/src')) } ]) @@ -213,7 +220,7 @@ describe('utils tests', () => { expect(parseTsAliases('/tmp/fake/project/root', { '*': ['./src/*'] })).toStrictEqual([ { find: /^(.+)$/, - replacement: '/tmp/fake/project/root/src/$1' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/src/$1')) } ]) @@ -221,7 +228,7 @@ describe('utils tests', () => { expect(parseTsAliases('/tmp/fake/project/root', { '#*': ['./hashed/*'] })).toStrictEqual([ { find: /^#(.+)$/, - replacement: '/tmp/fake/project/root/hashed/$1' + replacement: expect.stringMatching(maybeWindowsPath('/tmp/fake/project/root/hashed/$1')) } ]) })