UNPKG

3.25 kBJavaScriptView Raw
1import fs from 'fs';
2import { platform } from 'os';
3import path, { posix } from 'path';
4import slash from 'slash';
5
6const VOLUME = /^([A-Z]:)/i;
7const IS_WINDOWS = platform() === 'win32';
8
9// Helper functions
10const noop = () => null;
11const matches = (pattern, importee) => {
12 if (pattern instanceof RegExp) {
13 return pattern.test(importee);
14 }
15 if (importee.length < pattern.length) {
16 return false;
17 }
18 if (importee === pattern) {
19 return true;
20 }
21 const importeeStartsWithKey = importee.indexOf(pattern) === 0;
22 const importeeHasSlashAfterKey = importee.substring(pattern.length)[0] === '/';
23 return importeeStartsWithKey && importeeHasSlashAfterKey;
24};
25const endsWith = (needle, haystack) => haystack.slice(-needle.length) === needle;
26const isFilePath = (id) => /^\.?\//.test(id);
27const exists = (uri) => {
28 try {
29 return fs.statSync(uri).isFile();
30 } catch (e) {
31 return false;
32 }
33};
34
35const normalizeId = (id) => {
36 if ((IS_WINDOWS && typeof id === 'string') || VOLUME.test(id)) {
37 return slash(id.replace(VOLUME, ''));
38 }
39 return id;
40};
41
42const getEntries = ({ entries }) => {
43 if (!entries) {
44 return [];
45 }
46
47 if (Array.isArray(entries)) {
48 return entries;
49 }
50
51 return Object.keys(entries).map((key) => {
52 return { find: key, replacement: entries[key] };
53 });
54};
55
56function alias(options = {}) {
57 const resolve = Array.isArray(options.resolve) ? options.resolve : ['.js'];
58 const entries = getEntries(options);
59
60 // No aliases?
61 if (entries.length === 0) {
62 return {
63 resolveId: noop
64 };
65 }
66
67 return {
68 resolveId(importee, importer) {
69 const importeeId = normalizeId(importee);
70 const importerId = normalizeId(importer);
71
72 // First match is supposed to be the correct one
73 const matchedEntry = entries.find((entry) => matches(entry.find, importeeId));
74 if (!matchedEntry || !importerId) {
75 return null;
76 }
77
78 let updatedId = normalizeId(importeeId.replace(matchedEntry.find, matchedEntry.replacement));
79
80 if (isFilePath(updatedId)) {
81 const directory = posix.dirname(importerId);
82
83 // Resolve file names
84 const filePath = posix.resolve(directory, updatedId);
85 const match = resolve
86 .map((ext) => (endsWith(ext, filePath) ? filePath : `${filePath}${ext}`))
87 .find(exists);
88
89 if (match) {
90 updatedId = match;
91 // To keep the previous behaviour we simply return the file path
92 // with extension
93 } else if (endsWith('.js', filePath)) {
94 updatedId = filePath;
95 } else {
96 const indexFilePath = posix.resolve(directory, `${updatedId}/index`);
97 const defaultMatch = resolve.map((ext) => `${indexFilePath}${ext}`).find(exists);
98 if (defaultMatch) {
99 updatedId = defaultMatch;
100 } else {
101 updatedId = `${filePath}.js`;
102 }
103 }
104 }
105
106 // if alias is windows absoulate path return resolved path or
107 // rollup on windows will throw:
108 // [TypeError: Cannot read property 'specifier' of undefined]
109 if (VOLUME.test(matchedEntry.replacement)) {
110 return path.resolve(updatedId);
111 }
112 return updatedId;
113 }
114 };
115}
116
117export default alias;