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 = fn => {
|
85 |
|
86 | const cache = new WeakMap();
|
87 |
|
88 | |
89 |
|
90 |
|
91 |
|
92 |
|
93 |
|
94 | const cachedFn = (context, identifier, associatedObjectForCache) => {
|
95 | if (!associatedObjectForCache) return fn(context, identifier);
|
96 |
|
97 | let innerCache = cache.get(associatedObjectForCache);
|
98 | if (innerCache === undefined) {
|
99 | innerCache = new Map();
|
100 | cache.set(associatedObjectForCache, innerCache);
|
101 | }
|
102 |
|
103 | let cachedResult;
|
104 | let innerSubCache = innerCache.get(context);
|
105 | if (innerSubCache === undefined) {
|
106 | innerCache.set(context, (innerSubCache = new Map()));
|
107 | } else {
|
108 | cachedResult = innerSubCache.get(identifier);
|
109 | }
|
110 |
|
111 | if (cachedResult !== undefined) {
|
112 | return cachedResult;
|
113 | } else {
|
114 | const result = fn(context, identifier);
|
115 | innerSubCache.set(identifier, result);
|
116 | return result;
|
117 | }
|
118 | };
|
119 |
|
120 | |
121 |
|
122 |
|
123 |
|
124 | cachedFn.bindCache = associatedObjectForCache => {
|
125 | let innerCache;
|
126 | if (associatedObjectForCache) {
|
127 | innerCache = cache.get(associatedObjectForCache);
|
128 | if (innerCache === undefined) {
|
129 | innerCache = new Map();
|
130 | cache.set(associatedObjectForCache, innerCache);
|
131 | }
|
132 | } else {
|
133 | innerCache = new Map();
|
134 | }
|
135 |
|
136 | |
137 |
|
138 |
|
139 |
|
140 |
|
141 | const boundFn = (context, identifier) => {
|
142 | let cachedResult;
|
143 | let innerSubCache = innerCache.get(context);
|
144 | if (innerSubCache === undefined) {
|
145 | innerCache.set(context, (innerSubCache = new Map()));
|
146 | } else {
|
147 | cachedResult = innerSubCache.get(identifier);
|
148 | }
|
149 |
|
150 | if (cachedResult !== undefined) {
|
151 | return cachedResult;
|
152 | } else {
|
153 | const result = fn(context, identifier);
|
154 | innerSubCache.set(identifier, result);
|
155 | return result;
|
156 | }
|
157 | };
|
158 |
|
159 | return boundFn;
|
160 | };
|
161 |
|
162 | |
163 |
|
164 |
|
165 |
|
166 |
|
167 | cachedFn.bindContextCache = (context, associatedObjectForCache) => {
|
168 | let innerSubCache;
|
169 | if (associatedObjectForCache) {
|
170 | let innerCache = cache.get(associatedObjectForCache);
|
171 | if (innerCache === undefined) {
|
172 | innerCache = new Map();
|
173 | cache.set(associatedObjectForCache, innerCache);
|
174 | }
|
175 |
|
176 | innerSubCache = innerCache.get(context);
|
177 | if (innerSubCache === undefined) {
|
178 | innerCache.set(context, (innerSubCache = new Map()));
|
179 | }
|
180 | } else {
|
181 | innerSubCache = new Map();
|
182 | }
|
183 |
|
184 | |
185 |
|
186 |
|
187 |
|
188 | const boundFn = identifier => {
|
189 | const cachedResult = innerSubCache.get(identifier);
|
190 | if (cachedResult !== undefined) {
|
191 | return cachedResult;
|
192 | } else {
|
193 | const result = fn(context, identifier);
|
194 | innerSubCache.set(identifier, result);
|
195 | return result;
|
196 | }
|
197 | };
|
198 |
|
199 | return boundFn;
|
200 | };
|
201 |
|
202 | return cachedFn;
|
203 | };
|
204 |
|
205 |
|
206 |
|
207 |
|
208 |
|
209 |
|
210 |
|
211 | const _makePathsRelative = (context, identifier) => {
|
212 | return identifier
|
213 | .split(SEGMENTS_SPLIT_REGEXP)
|
214 | .map(str => absoluteToRequest(context, str))
|
215 | .join("");
|
216 | };
|
217 |
|
218 | exports.makePathsRelative = makeCacheable(_makePathsRelative);
|
219 |
|
220 |
|
221 |
|
222 |
|
223 |
|
224 |
|
225 |
|
226 | const _makePathsAbsolute = (context, identifier) => {
|
227 | return identifier
|
228 | .split(SEGMENTS_SPLIT_REGEXP)
|
229 | .map(str => requestToAbsolute(context, str))
|
230 | .join("");
|
231 | };
|
232 |
|
233 | exports.makePathsAbsolute = makeCacheable(_makePathsAbsolute);
|
234 |
|
235 |
|
236 |
|
237 |
|
238 |
|
239 |
|
240 | const _contextify = (context, request) => {
|
241 | return request
|
242 | .split("!")
|
243 | .map(r => absoluteToRequest(context, r))
|
244 | .join("!");
|
245 | };
|
246 |
|
247 | const contextify = makeCacheable(_contextify);
|
248 | exports.contextify = contextify;
|
249 |
|
250 |
|
251 |
|
252 |
|
253 |
|
254 |
|
255 | const _absolutify = (context, request) => {
|
256 | return request
|
257 | .split("!")
|
258 | .map(r => requestToAbsolute(context, r))
|
259 | .join("!");
|
260 | };
|
261 |
|
262 | const absolutify = makeCacheable(_absolutify);
|
263 | exports.absolutify = absolutify;
|
264 |
|
265 | const PATH_QUERY_FRAGMENT_REGEXP =
|
266 | /^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
|
267 |
|
268 |
|
269 |
|
270 |
|
271 |
|
272 |
|
273 |
|
274 | const _parseResource = str => {
|
275 | const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
|
276 | return {
|
277 | resource: str,
|
278 | path: match[1].replace(/\0(.)/g, "$1"),
|
279 | query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
|
280 | fragment: match[3] || ""
|
281 | };
|
282 | };
|
283 | exports.parseResource = (realFn => {
|
284 |
|
285 | const cache = new WeakMap();
|
286 |
|
287 | const getCache = associatedObjectForCache => {
|
288 | const entry = cache.get(associatedObjectForCache);
|
289 | if (entry !== undefined) return entry;
|
290 |
|
291 | const map = new Map();
|
292 | cache.set(associatedObjectForCache, map);
|
293 | return map;
|
294 | };
|
295 |
|
296 | |
297 |
|
298 |
|
299 |
|
300 |
|
301 | const fn = (str, associatedObjectForCache) => {
|
302 | if (!associatedObjectForCache) return realFn(str);
|
303 | const cache = getCache(associatedObjectForCache);
|
304 | const entry = cache.get(str);
|
305 | if (entry !== undefined) return entry;
|
306 | const result = realFn(str);
|
307 | cache.set(str, result);
|
308 | return result;
|
309 | };
|
310 |
|
311 | fn.bindCache = associatedObjectForCache => {
|
312 | const cache = getCache(associatedObjectForCache);
|
313 | return str => {
|
314 | const entry = cache.get(str);
|
315 | if (entry !== undefined) return entry;
|
316 | const result = realFn(str);
|
317 | cache.set(str, result);
|
318 | return result;
|
319 | };
|
320 | };
|
321 |
|
322 | return fn;
|
323 | })(_parseResource);
|
324 |
|
325 |
|
326 |
|
327 |
|
328 |
|
329 |
|
330 |
|
331 | exports.getUndoPath = (filename, outputPath, enforceRelative) => {
|
332 | let depth = -1;
|
333 | let append = "";
|
334 | outputPath = outputPath.replace(/[\\/]$/, "");
|
335 | for (const part of filename.split(/[/\\]+/)) {
|
336 | if (part === "..") {
|
337 | if (depth > -1) {
|
338 | depth--;
|
339 | } else {
|
340 | const i = outputPath.lastIndexOf("/");
|
341 | const j = outputPath.lastIndexOf("\\");
|
342 | const pos = i < 0 ? j : j < 0 ? i : Math.max(i, j);
|
343 | if (pos < 0) return outputPath + "/";
|
344 | append = outputPath.slice(pos + 1) + "/" + append;
|
345 | outputPath = outputPath.slice(0, pos);
|
346 | }
|
347 | } else if (part !== ".") {
|
348 | depth++;
|
349 | }
|
350 | }
|
351 | return depth > 0
|
352 | ? `${"../".repeat(depth)}${append}`
|
353 | : enforceRelative
|
354 | ? `./${append}`
|
355 | : append;
|
356 | };
|