aboutsummaryrefslogtreecommitdiff
path: root/packages/config/vite/relAlias.ts
blob: 7bafe74690b6e126e6782552ca6219630e303b34 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
import fs from 'node:fs/promises';
import path from 'node:path';
import type { Alias } from 'vite';

const projectPath = path.resolve(__dirname, '../../../');
const pkgJsonCache = new Map();

// /src/ or \src\, depending on platform
const SRC_DIR_PATH = `${path.sep}src${path.sep}`;

const resolver: Alias = {
	find: /^(~\/.+)/,
	replacement: '$1',
	async customResolver(source, importer) {
		let root: null | string = null;

		if (importer)
			importer = path.normalize(importer);

		// source is the path imported on typescript, which always use / as path separator
		const [_, sourcePath] = source.split('~/');

		const relativeImporter = importer?.replace(projectPath, '');
		if (relativeImporter && relativeImporter.includes(SRC_DIR_PATH)) {
			const [pkg] = relativeImporter.split(SRC_DIR_PATH);
			root = path.join(projectPath, pkg, 'src');
		}
		else if (importer) {
			const pathObj = path.parse(importer);

			let parent = pathObj.dir;
			while (parent !== pathObj.root) {
				parent = path.dirname(parent);

				let hasPkgJson = pkgJsonCache.get(parent);

				if (hasPkgJson === undefined) {
					try {
						await fs.stat(path.join(parent, 'package.json'));
						pkgJsonCache.set(parent, (hasPkgJson = true));
					}
					catch {
						pkgJsonCache.set(parent, (hasPkgJson = false));
					}
				}

				if (hasPkgJson) {
					root = parent;
					break;
				}
			}

			if (root === null)
				throw new Error(`Failed to resolve import path ${source} in file ${importer}`);
		}
		else {
			throw new Error(`Failed to resolve import path ${source} in file ${importer}`);
		}

		const absolutePath = path.join(root, sourcePath);

		const folderItems = await fs.readdir(path.join(absolutePath, '..'));

		// sourcePath is derived from the path imported on typescript, which always use / as path separator
		const item = folderItems.find(i => i.startsWith(sourcePath.split('/').at(-1)!))!;

		const fullPath = absolutePath + path.extname(item);

		const stats = await fs.stat(fullPath);

		if (stats.isDirectory()) {
			const directoryItems = await fs.readdir(absolutePath + path.extname(item));

			const indexFile = directoryItems.find(i => i.startsWith('index'));
			if (!indexFile)
				throw new Error(`Failed to resolve import path ${source} in file ${importer}`);

			return path.join(absolutePath, indexFile);
		}
		else {
			return fullPath;
		}
	},
};

export default resolver;