1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const path = require("path");
|
8 |
|
9 | const WINDOWS_ABS_PATH_REGEXP = /^[a-zA-Z]:[\\/]/;
|
10 | const SEGMENTS_SPLIT_REGEXP = /([|!])/;
|
11 | const WINDOWS_PATH_SEPARATOR_REGEXP = /\\/g;
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 |
|
18 | const relativePathToRequest = relativePath => {
|
19 | if (relativePath === "") return "./.";
|
20 | if (relativePath === "..") return "../.";
|
21 | if (relativePath.startsWith("../")) return relativePath;
|
22 | return `./${relativePath}`;
|
23 | };
|
24 |
|
25 |
|
26 |
|
27 |
|
28 |
|
29 |
|
30 | const absoluteToRequest = (context, maybeAbsolutePath) => {
|
31 | if (maybeAbsolutePath[0] === "/") {
|
32 | if (
|
33 | maybeAbsolutePath.length > 1 &&
|
34 | maybeAbsolutePath[maybeAbsolutePath.length - 1] === "/"
|
35 | ) {
|
36 |
|
37 |
|
38 | return maybeAbsolutePath;
|
39 | }
|
40 |
|
41 | const querySplitPos = maybeAbsolutePath.indexOf("?");
|
42 | let resource =
|
43 | querySplitPos === -1
|
44 | ? maybeAbsolutePath
|
45 | : maybeAbsolutePath.slice(0, querySplitPos);
|
46 | resource = relativePathToRequest(path.posix.relative(context, resource));
|
47 | return querySplitPos === -1
|
48 | ? resource
|
49 | : resource + maybeAbsolutePath.slice(querySplitPos);
|
50 | }
|
51 |
|
52 | if (WINDOWS_ABS_PATH_REGEXP.test(maybeAbsolutePath)) {
|
53 | const querySplitPos = maybeAbsolutePath.indexOf("?");
|
54 | let resource =
|
55 | querySplitPos === -1
|
56 | ? maybeAbsolutePath
|
57 | : maybeAbsolutePath.slice(0, querySplitPos);
|
58 | resource = path.win32.relative(context, resource);
|
59 | if (!WINDOWS_ABS_PATH_REGEXP.test(resource)) {
|
60 | resource = relativePathToRequest(
|
61 | resource.replace(WINDOWS_PATH_SEPARATOR_REGEXP, "/")
|
62 | );
|
63 | }
|
64 | return querySplitPos === -1
|
65 | ? resource
|
66 | : resource + maybeAbsolutePath.slice(querySplitPos);
|
67 | }
|
68 |
|
69 |
|
70 | return maybeAbsolutePath;
|
71 | };
|
72 |
|
73 |
|
74 |
|
75 |
|
76 |
|
77 |
|
78 | const requestToAbsolute = (context, relativePath) => {
|
79 | if (relativePath.startsWith("./") || relativePath.startsWith("../"))
|
80 | return path.join(context, relativePath);
|
81 | return relativePath;
|
82 | };
|
83 |
|
84 | const makeCacheable = realFn => {
|
85 |
|
86 | const cache = new WeakMap();
|
87 |
|
88 | const getCache = associatedObjectForCache => {
|
89 | const entry = cache.get(associatedObjectForCache);
|
90 | if (entry !== undefined) return entry;
|
91 |
|
92 | const map = new Map();
|
93 | cache.set(associatedObjectForCache, map);
|
94 | return map;
|
95 | };
|
96 |
|
97 | |
98 |
|
99 |
|
100 |
|
101 |
|
102 | const fn = (str, associatedObjectForCache) => {
|
103 | if (!associatedObjectForCache) return realFn(str);
|
104 | const cache = getCache(associatedObjectForCache);
|
105 | const entry = cache.get(str);
|
106 | if (entry !== undefined) return entry;
|
107 | const result = realFn(str);
|
108 | cache.set(str, result);
|
109 | return result;
|
110 | };
|
111 |
|
112 | fn.bindCache = associatedObjectForCache => {
|
113 | const cache = getCache(associatedObjectForCache);
|
114 | return str => {
|
115 | const entry = cache.get(str);
|
116 | if (entry !== undefined) return entry;
|
117 | const result = realFn(str);
|
118 | cache.set(str, result);
|
119 | return result;
|
120 | };
|
121 | };
|
122 |
|
123 | return fn;
|
124 | };
|
125 |
|
126 | const makeCacheableWithContext = fn => {
|
127 |
|
128 | const cache = new WeakMap();
|
129 |
|
130 | |
131 |
|
132 |
|
133 |
|
134 |
|
135 |
|
136 | const cachedFn = (context, identifier, associatedObjectForCache) => {
|
137 | if (!associatedObjectForCache) return fn(context, identifier);
|
138 |
|
139 | let innerCache = cache.get(associatedObjectForCache);
|
140 | if (innerCache === undefined) {
|
141 | innerCache = new Map();
|
142 | cache.set(associatedObjectForCache, innerCache);
|
143 | }
|
144 |
|
145 | let cachedResult;
|
146 | let innerSubCache = innerCache.get(context);
|
147 | if (innerSubCache === undefined) {
|
148 | innerCache.set(context, (innerSubCache = new Map()));
|
149 | } else {
|
150 | cachedResult = innerSubCache.get(identifier);
|
151 | }
|
152 |
|
153 | if (cachedResult !== undefined) {
|
154 | return cachedResult;
|
155 | } else {
|
156 | const result = fn(context, identifier);
|
157 | innerSubCache.set(identifier, result);
|
158 | return result;
|
159 | }
|
160 | };
|
161 |
|
162 | |
163 |
|
164 |
|
165 |
|
166 | cachedFn.bindCache = associatedObjectForCache => {
|
167 | let innerCache;
|
168 | if (associatedObjectForCache) {
|
169 | innerCache = cache.get(associatedObjectForCache);
|
170 | if (innerCache === undefined) {
|
171 | innerCache = new Map();
|
172 | cache.set(associatedObjectForCache, innerCache);
|
173 | }
|
174 | } else {
|
175 | innerCache = new Map();
|
176 | }
|
177 |
|
178 | |
179 |
|
180 |
|
181 |
|
182 |
|
183 | const boundFn = (context, identifier) => {
|
184 | let cachedResult;
|
185 | let innerSubCache = innerCache.get(context);
|
186 | if (innerSubCache === undefined) {
|
187 | innerCache.set(context, (innerSubCache = new Map()));
|
188 | } else {
|
189 | cachedResult = innerSubCache.get(identifier);
|
190 | }
|
191 |
|
192 | if (cachedResult !== undefined) {
|
193 | return cachedResult;
|
194 | } else {
|
195 | const result = fn(context, identifier);
|
196 | innerSubCache.set(identifier, result);
|
197 | return result;
|
198 | }
|
199 | };
|
200 |
|
201 | return boundFn;
|
202 | };
|
203 |
|
204 | |
205 |
|
206 |
|
207 |
|
208 |
|
209 | cachedFn.bindContextCache = (context, associatedObjectForCache) => {
|
210 | let innerSubCache;
|
211 | if (associatedObjectForCache) {
|
212 | let innerCache = cache.get(associatedObjectForCache);
|
213 | if (innerCache === undefined) {
|
214 | innerCache = new Map();
|
215 | cache.set(associatedObjectForCache, innerCache);
|
216 | }
|
217 |
|
218 | innerSubCache = innerCache.get(context);
|
219 | if (innerSubCache === undefined) {
|
220 | innerCache.set(context, (innerSubCache = new Map()));
|
221 | }
|
222 | } else {
|
223 | innerSubCache = new Map();
|
224 | }
|
225 |
|
226 | |
227 |
|
228 |
|
229 |
|
230 | const boundFn = identifier => {
|
231 | const cachedResult = innerSubCache.get(identifier);
|
232 | if (cachedResult !== undefined) {
|
233 | return cachedResult;
|
234 | } else {
|
235 | const result = fn(context, identifier);
|
236 | innerSubCache.set(identifier, result);
|
237 | return result;
|
238 | }
|
239 | };
|
240 |
|
241 | return boundFn;
|
242 | };
|
243 |
|
244 | return cachedFn;
|
245 | };
|
246 |
|
247 |
|
248 |
|
249 |
|
250 |
|
251 |
|
252 |
|
253 | const _makePathsRelative = (context, identifier) => {
|
254 | return identifier
|
255 | .split(SEGMENTS_SPLIT_REGEXP)
|
256 | .map(str => absoluteToRequest(context, str))
|
257 | .join("");
|
258 | };
|
259 |
|
260 | exports.makePathsRelative = makeCacheableWithContext(_makePathsRelative);
|
261 |
|
262 |
|
263 |
|
264 |
|
265 |
|
266 |
|
267 |
|
268 | const _makePathsAbsolute = (context, identifier) => {
|
269 | return identifier
|
270 | .split(SEGMENTS_SPLIT_REGEXP)
|
271 | .map(str => requestToAbsolute(context, str))
|
272 | .join("");
|
273 | };
|
274 |
|
275 | exports.makePathsAbsolute = makeCacheableWithContext(_makePathsAbsolute);
|
276 |
|
277 |
|
278 |
|
279 |
|
280 |
|
281 |
|
282 | const _contextify = (context, request) => {
|
283 | return request
|
284 | .split("!")
|
285 | .map(r => absoluteToRequest(context, r))
|
286 | .join("!");
|
287 | };
|
288 |
|
289 | const contextify = makeCacheableWithContext(_contextify);
|
290 | exports.contextify = contextify;
|
291 |
|
292 |
|
293 |
|
294 |
|
295 |
|
296 |
|
297 | const _absolutify = (context, request) => {
|
298 | return request
|
299 | .split("!")
|
300 | .map(r => requestToAbsolute(context, r))
|
301 | .join("!");
|
302 | };
|
303 |
|
304 | const absolutify = makeCacheableWithContext(_absolutify);
|
305 | exports.absolutify = absolutify;
|
306 |
|
307 | const PATH_QUERY_FRAGMENT_REGEXP =
|
308 | /^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
|
309 | const PATH_QUERY_REGEXP = /^((?:\0.|[^?\0])*)(\?.*)?$/;
|
310 |
|
311 |
|
312 |
|
313 |
|
314 |
|
315 |
|
316 |
|
317 |
|
318 | const _parseResource = str => {
|
319 | const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
|
320 | return {
|
321 | resource: str,
|
322 | path: match[1].replace(/\0(.)/g, "$1"),
|
323 | query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
|
324 | fragment: match[3] || ""
|
325 | };
|
326 | };
|
327 | exports.parseResource = makeCacheable(_parseResource);
|
328 |
|
329 |
|
330 |
|
331 |
|
332 |
|
333 |
|
334 | const _parseResourceWithoutFragment = str => {
|
335 | const match = PATH_QUERY_REGEXP.exec(str);
|
336 | return {
|
337 | resource: str,
|
338 | path: match[1].replace(/\0(.)/g, "$1"),
|
339 | query: match[2] ? match[2].replace(/\0(.)/g, "$1") : ""
|
340 | };
|
341 | };
|
342 | exports.parseResourceWithoutFragment = makeCacheable(
|
343 | _parseResourceWithoutFragment
|
344 | );
|
345 |
|
346 |
|
347 |
|
348 |
|
349 |
|
350 |
|
351 |
|
352 | exports.getUndoPath = (filename, outputPath, enforceRelative) => {
|
353 | let depth = -1;
|
354 | let append = "";
|
355 | outputPath = outputPath.replace(/[\\/]$/, "");
|
356 | for (const part of filename.split(/[/\\]+/)) {
|
357 | if (part === "..") {
|
358 | if (depth > -1) {
|
359 | depth--;
|
360 | } else {
|
361 | const i = outputPath.lastIndexOf("/");
|
362 | const j = outputPath.lastIndexOf("\\");
|
363 | const pos = i < 0 ? j : j < 0 ? i : Math.max(i, j);
|
364 | if (pos < 0) return outputPath + "/";
|
365 | append = outputPath.slice(pos + 1) + "/" + append;
|
366 | outputPath = outputPath.slice(0, pos);
|
367 | }
|
368 | } else if (part !== ".") {
|
369 | depth++;
|
370 | }
|
371 | }
|
372 | return depth > 0
|
373 | ? `${"../".repeat(depth)}${append}`
|
374 | : enforceRelative
|
375 | ? `./${append}`
|
376 | : append;
|
377 | };
|