UNPKG

3.22 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 => ({ find: key, replacement: entries[key] }));
52};
53
54function alias(options = {}) {
55 const resolve = Array.isArray(options.resolve) ? options.resolve : ['.js'];
56 const entries = getEntries(options);
57
58 // No aliases?
59 if (entries.length === 0) {
60 return {
61 resolveId: noop,
62 };
63 }
64
65 return {
66 resolveId(importee, importer) {
67 const importeeId = normalizeId(importee);
68 const importerId = normalizeId(importer);
69
70 // First match is supposed to be the correct one
71 const matchedEntry = entries.find(entry => matches(entry.find, importeeId));
72 if (!matchedEntry || !importerId) {
73 return null;
74 }
75
76 let updatedId = normalizeId(importeeId.replace(matchedEntry.find, matchedEntry.replacement));
77
78 if (isFilePath(updatedId)) {
79 const directory = posix.dirname(importerId);
80
81 // Resolve file names
82 const filePath = posix.resolve(directory, updatedId);
83 const match = resolve.map(ext => (endsWith(ext, filePath) ? filePath : `${filePath}${ext}`))
84 .find(exists);
85
86 if (match) {
87 updatedId = match;
88 // To keep the previous behaviour we simply return the file path
89 // with extension
90 } else if (endsWith('.js', filePath)) {
91 updatedId = filePath;
92 } else {
93 const indexFilePath = posix.resolve(directory, `${updatedId}/index`);
94 const defaultMatch = resolve.map(ext => `${indexFilePath}${ext}`).find(exists);
95 if (defaultMatch) {
96 updatedId = defaultMatch;
97 } else {
98 updatedId = filePath + '.js';
99 }
100 }
101 }
102
103 // if alias is windows absoulate path return resolved path or
104 // rollup on windows will throw:
105 // [TypeError: Cannot read property 'specifier' of undefined]
106 if (VOLUME.test(matchedEntry.replacement)) {
107 return path.resolve(updatedId);
108 }
109 return updatedId;
110 },
111 };
112}
113
114export default alias;