source: trip-planner-front/node_modules/webpack/lib/util/identifier.js@ 6a3a178

Last change on this file since 6a3a178 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 9.6 KB
RevLine 
[6a3a178]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3*/
4
5"use strict";
6
7const path = require("path");
8
9const WINDOWS_ABS_PATH_REGEXP = /^[a-zA-Z]:[\\/]/;
10const SEGMENTS_SPLIT_REGEXP = /([|!])/;
11const WINDOWS_PATH_SEPARATOR_REGEXP = /\\/g;
12
13/**
14 * @typedef {Object} MakeRelativePathsCache
15 * @property {Map<string, Map<string, string>>=} relativePaths
16 */
17
18/**
19 * @param {string} context context for relative path
20 * @param {string} maybeAbsolutePath path to make relative
21 * @returns {string} relative path in request style
22 */
23const absoluteToRequest = (context, maybeAbsolutePath) => {
24 if (maybeAbsolutePath[0] === "/") {
25 if (
26 maybeAbsolutePath.length > 1 &&
27 maybeAbsolutePath[maybeAbsolutePath.length - 1] === "/"
28 ) {
29 // this 'path' is actually a regexp generated by dynamic requires.
30 // Don't treat it as an absolute path.
31 return maybeAbsolutePath;
32 }
33
34 const querySplitPos = maybeAbsolutePath.indexOf("?");
35 let resource =
36 querySplitPos === -1
37 ? maybeAbsolutePath
38 : maybeAbsolutePath.slice(0, querySplitPos);
39 resource = path.posix.relative(context, resource);
40 if (!resource.startsWith("../")) {
41 resource = "./" + resource;
42 }
43 return querySplitPos === -1
44 ? resource
45 : resource + maybeAbsolutePath.slice(querySplitPos);
46 }
47
48 if (WINDOWS_ABS_PATH_REGEXP.test(maybeAbsolutePath)) {
49 const querySplitPos = maybeAbsolutePath.indexOf("?");
50 let resource =
51 querySplitPos === -1
52 ? maybeAbsolutePath
53 : maybeAbsolutePath.slice(0, querySplitPos);
54 resource = path.win32.relative(context, resource);
55 if (!WINDOWS_ABS_PATH_REGEXP.test(resource)) {
56 resource = resource.replace(WINDOWS_PATH_SEPARATOR_REGEXP, "/");
57 if (!resource.startsWith("../")) {
58 resource = "./" + resource;
59 }
60 }
61 return querySplitPos === -1
62 ? resource
63 : resource + maybeAbsolutePath.slice(querySplitPos);
64 }
65
66 // not an absolute path
67 return maybeAbsolutePath;
68};
69
70/**
71 * @param {string} context context for relative path
72 * @param {string} relativePath path
73 * @returns {string} absolute path
74 */
75const requestToAbsolute = (context, relativePath) => {
76 if (relativePath.startsWith("./") || relativePath.startsWith("../"))
77 return path.join(context, relativePath);
78 return relativePath;
79};
80
81const makeCacheable = fn => {
82 /** @type {WeakMap<object, Map<string, Map<string, string>>>} */
83 const cache = new WeakMap();
84
85 /**
86 * @param {string} context context used to create relative path
87 * @param {string} identifier identifier used to create relative path
88 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
89 * @returns {string} the returned relative path
90 */
91 const cachedFn = (context, identifier, associatedObjectForCache) => {
92 if (!associatedObjectForCache) return fn(context, identifier);
93
94 let innerCache = cache.get(associatedObjectForCache);
95 if (innerCache === undefined) {
96 innerCache = new Map();
97 cache.set(associatedObjectForCache, innerCache);
98 }
99
100 let cachedResult;
101 let innerSubCache = innerCache.get(context);
102 if (innerSubCache === undefined) {
103 innerCache.set(context, (innerSubCache = new Map()));
104 } else {
105 cachedResult = innerSubCache.get(identifier);
106 }
107
108 if (cachedResult !== undefined) {
109 return cachedResult;
110 } else {
111 const result = fn(context, identifier);
112 innerSubCache.set(identifier, result);
113 return result;
114 }
115 };
116
117 /**
118 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
119 * @returns {function(string, string): string} cached function
120 */
121 cachedFn.bindCache = associatedObjectForCache => {
122 let innerCache;
123 if (associatedObjectForCache) {
124 innerCache = cache.get(associatedObjectForCache);
125 if (innerCache === undefined) {
126 innerCache = new Map();
127 cache.set(associatedObjectForCache, innerCache);
128 }
129 } else {
130 innerCache = new Map();
131 }
132
133 /**
134 * @param {string} context context used to create relative path
135 * @param {string} identifier identifier used to create relative path
136 * @returns {string} the returned relative path
137 */
138 const boundFn = (context, identifier) => {
139 let cachedResult;
140 let innerSubCache = innerCache.get(context);
141 if (innerSubCache === undefined) {
142 innerCache.set(context, (innerSubCache = new Map()));
143 } else {
144 cachedResult = innerSubCache.get(identifier);
145 }
146
147 if (cachedResult !== undefined) {
148 return cachedResult;
149 } else {
150 const result = fn(context, identifier);
151 innerSubCache.set(identifier, result);
152 return result;
153 }
154 };
155
156 return boundFn;
157 };
158
159 /**
160 * @param {string} context context used to create relative path
161 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
162 * @returns {function(string): string} cached function
163 */
164 cachedFn.bindContextCache = (context, associatedObjectForCache) => {
165 let innerSubCache;
166 if (associatedObjectForCache) {
167 let innerCache = cache.get(associatedObjectForCache);
168 if (innerCache === undefined) {
169 innerCache = new Map();
170 cache.set(associatedObjectForCache, innerCache);
171 }
172
173 innerSubCache = innerCache.get(context);
174 if (innerSubCache === undefined) {
175 innerCache.set(context, (innerSubCache = new Map()));
176 }
177 } else {
178 innerSubCache = new Map();
179 }
180
181 /**
182 * @param {string} identifier identifier used to create relative path
183 * @returns {string} the returned relative path
184 */
185 const boundFn = identifier => {
186 const cachedResult = innerSubCache.get(identifier);
187 if (cachedResult !== undefined) {
188 return cachedResult;
189 } else {
190 const result = fn(context, identifier);
191 innerSubCache.set(identifier, result);
192 return result;
193 }
194 };
195
196 return boundFn;
197 };
198
199 return cachedFn;
200};
201
202/**
203 *
204 * @param {string} context context for relative path
205 * @param {string} identifier identifier for path
206 * @returns {string} a converted relative path
207 */
208const _makePathsRelative = (context, identifier) => {
209 return identifier
210 .split(SEGMENTS_SPLIT_REGEXP)
211 .map(str => absoluteToRequest(context, str))
212 .join("");
213};
214
215exports.makePathsRelative = makeCacheable(_makePathsRelative);
216
217/**
218 * @param {string} context absolute context path
219 * @param {string} request any request string may containing absolute paths, query string, etc.
220 * @returns {string} a new request string avoiding absolute paths when possible
221 */
222const _contextify = (context, request) => {
223 return request
224 .split("!")
225 .map(r => absoluteToRequest(context, r))
226 .join("!");
227};
228
229const contextify = makeCacheable(_contextify);
230exports.contextify = contextify;
231
232/**
233 * @param {string} context absolute context path
234 * @param {string} request any request string
235 * @returns {string} a new request string using absolute paths when possible
236 */
237const _absolutify = (context, request) => {
238 return request
239 .split("!")
240 .map(r => requestToAbsolute(context, r))
241 .join("!");
242};
243
244const absolutify = makeCacheable(_absolutify);
245exports.absolutify = absolutify;
246
247const PATH_QUERY_FRAGMENT_REGEXP =
248 /^((?:\0.|[^?#\0])*)(\?(?:\0.|[^#\0])*)?(#.*)?$/;
249
250/** @typedef {{ resource: string, path: string, query: string, fragment: string }} ParsedResource */
251
252/**
253 * @param {string} str the path with query and fragment
254 * @returns {ParsedResource} parsed parts
255 */
256const _parseResource = str => {
257 const match = PATH_QUERY_FRAGMENT_REGEXP.exec(str);
258 return {
259 resource: str,
260 path: match[1].replace(/\0(.)/g, "$1"),
261 query: match[2] ? match[2].replace(/\0(.)/g, "$1") : "",
262 fragment: match[3] || ""
263 };
264};
265exports.parseResource = (realFn => {
266 /** @type {WeakMap<object, Map<string, ParsedResource>>} */
267 const cache = new WeakMap();
268
269 const getCache = associatedObjectForCache => {
270 const entry = cache.get(associatedObjectForCache);
271 if (entry !== undefined) return entry;
272 /** @type {Map<string, ParsedResource>} */
273 const map = new Map();
274 cache.set(associatedObjectForCache, map);
275 return map;
276 };
277
278 /**
279 * @param {string} str the path with query and fragment
280 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
281 * @returns {ParsedResource} parsed parts
282 */
283 const fn = (str, associatedObjectForCache) => {
284 if (!associatedObjectForCache) return realFn(str);
285 const cache = getCache(associatedObjectForCache);
286 const entry = cache.get(str);
287 if (entry !== undefined) return entry;
288 const result = realFn(str);
289 cache.set(str, result);
290 return result;
291 };
292
293 fn.bindCache = associatedObjectForCache => {
294 const cache = getCache(associatedObjectForCache);
295 return str => {
296 const entry = cache.get(str);
297 if (entry !== undefined) return entry;
298 const result = realFn(str);
299 cache.set(str, result);
300 return result;
301 };
302 };
303
304 return fn;
305})(_parseResource);
306
307/**
308 * @param {string} filename the filename which should be undone
309 * @param {string} outputPath the output path that is restored (only relevant when filename contains "..")
310 * @param {boolean} enforceRelative true returns ./ for empty paths
311 * @returns {string} repeated ../ to leave the directory of the provided filename to be back on output dir
312 */
313exports.getUndoPath = (filename, outputPath, enforceRelative) => {
314 let depth = -1;
315 let append = "";
316 outputPath = outputPath.replace(/[\\/]$/, "");
317 for (const part of filename.split(/[/\\]+/)) {
318 if (part === "..") {
319 if (depth > -1) {
320 depth--;
321 } else {
322 const i = outputPath.lastIndexOf("/");
323 const j = outputPath.lastIndexOf("\\");
324 const pos = i < 0 ? j : j < 0 ? i : Math.max(i, j);
325 if (pos < 0) return outputPath + "/";
326 append = outputPath.slice(pos + 1) + "/" + append;
327 outputPath = outputPath.slice(0, pos);
328 }
329 } else if (part !== ".") {
330 depth++;
331 }
332 }
333 return depth > 0
334 ? `${"../".repeat(depth)}${append}`
335 : enforceRelative
336 ? `./${append}`
337 : append;
338};
Note: See TracBrowser for help on using the repository browser.