UNPKG

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