1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const Resolver = require("./Resolver");
|
8 |
|
9 | const SyncAsyncFileSystemDecorator = require("./SyncAsyncFileSystemDecorator");
|
10 |
|
11 | const ParsePlugin = require("./ParsePlugin");
|
12 | const DescriptionFilePlugin = require("./DescriptionFilePlugin");
|
13 | const NextPlugin = require("./NextPlugin");
|
14 | const TryNextPlugin = require("./TryNextPlugin");
|
15 | const ModuleKindPlugin = require("./ModuleKindPlugin");
|
16 | const FileKindPlugin = require("./FileKindPlugin");
|
17 | const JoinRequestPlugin = require("./JoinRequestPlugin");
|
18 | const ModulesInHierachicDirectoriesPlugin = require("./ModulesInHierachicDirectoriesPlugin");
|
19 | const ModulesInRootPlugin = require("./ModulesInRootPlugin");
|
20 | const AliasPlugin = require("./AliasPlugin");
|
21 | const AliasFieldPlugin = require("./AliasFieldPlugin");
|
22 | const ConcordExtensionsPlugin = require("./ConcordExtensionsPlugin");
|
23 | const ConcordMainPlugin = require("./ConcordMainPlugin");
|
24 | const ConcordModulesPlugin = require("./ConcordModulesPlugin");
|
25 | const DirectoryExistsPlugin = require("./DirectoryExistsPlugin");
|
26 | const FileExistsPlugin = require("./FileExistsPlugin");
|
27 | const SymlinkPlugin = require("./SymlinkPlugin");
|
28 | const MainFieldPlugin = require("./MainFieldPlugin");
|
29 | const UseFilePlugin = require("./UseFilePlugin");
|
30 | const AppendPlugin = require("./AppendPlugin");
|
31 | const ResultPlugin = require("./ResultPlugin");
|
32 | const ModuleAppendPlugin = require("./ModuleAppendPlugin");
|
33 | const UnsafeCachePlugin = require("./UnsafeCachePlugin");
|
34 |
|
35 | exports.createResolver = function(options) {
|
36 |
|
37 |
|
38 |
|
39 |
|
40 | let modules = options.modules || ["node_modules"];
|
41 |
|
42 |
|
43 | const descriptionFiles = options.descriptionFiles || ["package.json"];
|
44 |
|
45 |
|
46 |
|
47 |
|
48 | const plugins = (options.plugins && options.plugins.slice()) || [];
|
49 |
|
50 |
|
51 | let mainFields = options.mainFields || ["main"];
|
52 |
|
53 |
|
54 | const aliasFields = options.aliasFields || [];
|
55 |
|
56 |
|
57 | const mainFiles = options.mainFiles || ["index"];
|
58 |
|
59 |
|
60 | let extensions = options.extensions || [".js", ".json", ".node"];
|
61 |
|
62 |
|
63 | const enforceExtension = options.enforceExtension || false;
|
64 |
|
65 |
|
66 | let moduleExtensions = options.moduleExtensions || [];
|
67 |
|
68 |
|
69 | const enforceModuleExtension = options.enforceModuleExtension || false;
|
70 |
|
71 |
|
72 | let alias = options.alias || [];
|
73 |
|
74 |
|
75 | const symlinks = typeof options.symlinks !== "undefined" ? options.symlinks : true;
|
76 |
|
77 |
|
78 | const resolveToContext = options.resolveToContext || false;
|
79 |
|
80 |
|
81 | let unsafeCache = options.unsafeCache || false;
|
82 |
|
83 |
|
84 | const cacheWithContext = typeof options.cacheWithContext !== "undefined" ? options.cacheWithContext : true;
|
85 |
|
86 |
|
87 | const enableConcord = options.concord || false;
|
88 |
|
89 |
|
90 |
|
91 | const cachePredicate = options.cachePredicate || function() {
|
92 | return true;
|
93 | };
|
94 |
|
95 |
|
96 | const fileSystem = options.fileSystem;
|
97 |
|
98 |
|
99 | const useSyncFileSystemCalls = options.useSyncFileSystemCalls;
|
100 |
|
101 |
|
102 | let resolver = options.resolver;
|
103 |
|
104 |
|
105 |
|
106 | if(!resolver) {
|
107 | resolver = new Resolver(useSyncFileSystemCalls ? new SyncAsyncFileSystemDecorator(fileSystem) : fileSystem);
|
108 | }
|
109 |
|
110 | extensions = [].concat(extensions);
|
111 | moduleExtensions = [].concat(moduleExtensions);
|
112 |
|
113 | modules = mergeFilteredToArray([].concat(modules), item => {
|
114 | return !isAbsolutePath(item);
|
115 | });
|
116 |
|
117 | mainFields = mainFields.map(item => {
|
118 | if(typeof item === "string" || Array.isArray(item)) {
|
119 | item = {
|
120 | name: item,
|
121 | forceRelative: true
|
122 | };
|
123 | }
|
124 | return item;
|
125 | });
|
126 |
|
127 | if(typeof alias === "object" && !Array.isArray(alias)) {
|
128 | alias = Object.keys(alias).map(key => {
|
129 | let onlyModule = false;
|
130 | let obj = alias[key];
|
131 | if(/\$$/.test(key)) {
|
132 | onlyModule = true;
|
133 | key = key.substr(0, key.length - 1);
|
134 | }
|
135 | if(typeof obj === "string") {
|
136 | obj = {
|
137 | alias: obj
|
138 | };
|
139 | }
|
140 | obj = Object.assign({
|
141 | name: key,
|
142 | onlyModule: onlyModule
|
143 | }, obj);
|
144 | return obj;
|
145 | });
|
146 | }
|
147 |
|
148 | if(unsafeCache && typeof unsafeCache !== "object") {
|
149 | unsafeCache = {};
|
150 | }
|
151 |
|
152 |
|
153 |
|
154 | resolver.ensureHook("resolve");
|
155 | resolver.ensureHook("parsedResolve");
|
156 | resolver.ensureHook("describedResolve");
|
157 | resolver.ensureHook("rawModule");
|
158 | resolver.ensureHook("module");
|
159 | resolver.ensureHook("relative");
|
160 | resolver.ensureHook("describedRelative");
|
161 | resolver.ensureHook("directory");
|
162 | resolver.ensureHook("existingDirectory");
|
163 | resolver.ensureHook("undescribedRawFile");
|
164 | resolver.ensureHook("rawFile");
|
165 | resolver.ensureHook("file");
|
166 | resolver.ensureHook("existingFile");
|
167 | resolver.ensureHook("resolved");
|
168 |
|
169 |
|
170 | if(unsafeCache) {
|
171 | plugins.push(new UnsafeCachePlugin("resolve", cachePredicate, unsafeCache, cacheWithContext, "new-resolve"));
|
172 | plugins.push(new ParsePlugin("new-resolve", "parsed-resolve"));
|
173 | } else {
|
174 | plugins.push(new ParsePlugin("resolve", "parsed-resolve"));
|
175 | }
|
176 |
|
177 |
|
178 | plugins.push(new DescriptionFilePlugin("parsed-resolve", descriptionFiles, "described-resolve"));
|
179 | plugins.push(new NextPlugin("after-parsed-resolve", "described-resolve"));
|
180 |
|
181 |
|
182 | if(alias.length > 0)
|
183 | plugins.push(new AliasPlugin("described-resolve", alias, "resolve"));
|
184 | if(enableConcord) {
|
185 | plugins.push(new ConcordModulesPlugin("described-resolve", {}, "resolve"));
|
186 | }
|
187 | aliasFields.forEach(item => {
|
188 | plugins.push(new AliasFieldPlugin("described-resolve", item, "resolve"));
|
189 | });
|
190 | plugins.push(new ModuleKindPlugin("after-described-resolve", "raw-module"));
|
191 | plugins.push(new JoinRequestPlugin("after-described-resolve", "relative"));
|
192 |
|
193 |
|
194 | moduleExtensions.forEach(item => {
|
195 | plugins.push(new ModuleAppendPlugin("raw-module", item, "module"));
|
196 | });
|
197 | if(!enforceModuleExtension)
|
198 | plugins.push(new TryNextPlugin("raw-module", null, "module"));
|
199 |
|
200 |
|
201 | modules.forEach(item => {
|
202 | if(Array.isArray(item))
|
203 | plugins.push(new ModulesInHierachicDirectoriesPlugin("module", item, "resolve"));
|
204 | else
|
205 | plugins.push(new ModulesInRootPlugin("module", item, "resolve"));
|
206 | });
|
207 |
|
208 |
|
209 | plugins.push(new DescriptionFilePlugin("relative", descriptionFiles, "described-relative"));
|
210 | plugins.push(new NextPlugin("after-relative", "described-relative"));
|
211 |
|
212 |
|
213 | plugins.push(new FileKindPlugin("described-relative", "raw-file"));
|
214 | plugins.push(new TryNextPlugin("described-relative", "as directory", "directory"));
|
215 |
|
216 |
|
217 | plugins.push(new DirectoryExistsPlugin("directory", "existing-directory"));
|
218 |
|
219 | if(resolveToContext) {
|
220 |
|
221 |
|
222 | plugins.push(new NextPlugin("existing-directory", "resolved"));
|
223 |
|
224 | } else {
|
225 |
|
226 |
|
227 | if(enableConcord) {
|
228 | plugins.push(new ConcordMainPlugin("existing-directory", {}, "resolve"));
|
229 | }
|
230 | mainFields.forEach(item => {
|
231 | plugins.push(new MainFieldPlugin("existing-directory", item, "resolve"));
|
232 | });
|
233 | mainFiles.forEach(item => {
|
234 | plugins.push(new UseFilePlugin("existing-directory", item, "undescribed-raw-file"));
|
235 | });
|
236 |
|
237 |
|
238 | plugins.push(new DescriptionFilePlugin("undescribed-raw-file", descriptionFiles, "raw-file"));
|
239 | plugins.push(new NextPlugin("after-undescribed-raw-file", "raw-file"));
|
240 |
|
241 |
|
242 | if(!enforceExtension) {
|
243 | plugins.push(new TryNextPlugin("raw-file", "no extension", "file"));
|
244 | }
|
245 | if(enableConcord) {
|
246 | plugins.push(new ConcordExtensionsPlugin("raw-file", {}, "file"));
|
247 | }
|
248 | extensions.forEach(item => {
|
249 | plugins.push(new AppendPlugin("raw-file", item, "file"));
|
250 | });
|
251 |
|
252 |
|
253 | if(alias.length > 0)
|
254 | plugins.push(new AliasPlugin("file", alias, "resolve"));
|
255 | if(enableConcord) {
|
256 | plugins.push(new ConcordModulesPlugin("file", {}, "resolve"));
|
257 | }
|
258 | aliasFields.forEach(item => {
|
259 | plugins.push(new AliasFieldPlugin("file", item, "resolve"));
|
260 | });
|
261 | if(symlinks)
|
262 | plugins.push(new SymlinkPlugin("file", "relative"));
|
263 | plugins.push(new FileExistsPlugin("file", "existing-file"));
|
264 |
|
265 |
|
266 | plugins.push(new NextPlugin("existing-file", "resolved"));
|
267 |
|
268 | }
|
269 |
|
270 |
|
271 | plugins.push(new ResultPlugin(resolver.hooks.resolved));
|
272 |
|
273 |
|
274 |
|
275 | plugins.forEach(plugin => {
|
276 | plugin.apply(resolver);
|
277 | });
|
278 |
|
279 | return resolver;
|
280 | };
|
281 |
|
282 | function mergeFilteredToArray(array, filter) {
|
283 | return array.reduce((array, item) => {
|
284 | if(filter(item)) {
|
285 | const lastElement = array[array.length - 1];
|
286 | if(Array.isArray(lastElement)) {
|
287 | lastElement.push(item);
|
288 | } else {
|
289 | array.push([item]);
|
290 | }
|
291 | return array;
|
292 | } else {
|
293 | array.push(item);
|
294 | return array;
|
295 | }
|
296 | }, []);
|
297 | }
|
298 |
|
299 | function isAbsolutePath(path) {
|
300 | return /^[A-Z]:|^\//.test(path);
|
301 | }
|