source: trip-planner-front/node_modules/webpack/lib/ids/IdHelpers.js@ 8d391a1

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

initial commit

  • Property mode set to 100644
File size: 11.6 KB
Line 
1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8const createHash = require("../util/createHash");
9const { makePathsRelative } = require("../util/identifier");
10const numberHash = require("../util/numberHash");
11
12/** @typedef {import("../Chunk")} Chunk */
13/** @typedef {import("../ChunkGraph")} ChunkGraph */
14/** @typedef {import("../Compilation")} Compilation */
15/** @typedef {import("../Module")} Module */
16
17/**
18 * @param {string} str string to hash
19 * @param {number} len max length of the hash
20 * @returns {string} hash
21 */
22const getHash = (str, len) => {
23 const hash = createHash("md4");
24 hash.update(str);
25 const digest = /** @type {string} */ (hash.digest("hex"));
26 return digest.substr(0, len);
27};
28
29/**
30 * @param {string} str the string
31 * @returns {string} string prefixed by an underscore if it is a number
32 */
33const avoidNumber = str => {
34 // max length of a number is 21 chars, bigger numbers a written as "...e+xx"
35 if (str.length > 21) return str;
36 const firstChar = str.charCodeAt(0);
37 // skip everything that doesn't look like a number
38 // charCodes: "-": 45, "1": 49, "9": 57
39 if (firstChar < 49) {
40 if (firstChar !== 45) return str;
41 } else if (firstChar > 57) {
42 return str;
43 }
44 if (str === +str + "") {
45 return `_${str}`;
46 }
47 return str;
48};
49
50/**
51 * @param {string} request the request
52 * @returns {string} id representation
53 */
54const requestToId = request => {
55 return request
56 .replace(/^(\.\.?\/)+/, "")
57 .replace(/(^[.-]|[^a-zA-Z0-9_-])+/g, "_");
58};
59exports.requestToId = requestToId;
60
61/**
62 * @param {string} string the string
63 * @param {string} delimiter separator for string and hash
64 * @returns {string} string with limited max length to 100 chars
65 */
66const shortenLongString = (string, delimiter) => {
67 if (string.length < 100) return string;
68 return (
69 string.slice(0, 100 - 6 - delimiter.length) + delimiter + getHash(string, 6)
70 );
71};
72
73/**
74 * @param {Module} module the module
75 * @param {string} context context directory
76 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
77 * @returns {string} short module name
78 */
79const getShortModuleName = (module, context, associatedObjectForCache) => {
80 const libIdent = module.libIdent({ context, associatedObjectForCache });
81 if (libIdent) return avoidNumber(libIdent);
82 const nameForCondition = module.nameForCondition();
83 if (nameForCondition)
84 return avoidNumber(
85 makePathsRelative(context, nameForCondition, associatedObjectForCache)
86 );
87 return "";
88};
89exports.getShortModuleName = getShortModuleName;
90
91/**
92 * @param {string} shortName the short name
93 * @param {Module} module the module
94 * @param {string} context context directory
95 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
96 * @returns {string} long module name
97 */
98const getLongModuleName = (
99 shortName,
100 module,
101 context,
102 associatedObjectForCache
103) => {
104 const fullName = getFullModuleName(module, context, associatedObjectForCache);
105 return `${shortName}?${getHash(fullName, 4)}`;
106};
107exports.getLongModuleName = getLongModuleName;
108
109/**
110 * @param {Module} module the module
111 * @param {string} context context directory
112 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
113 * @returns {string} full module name
114 */
115const getFullModuleName = (module, context, associatedObjectForCache) => {
116 return makePathsRelative(
117 context,
118 module.identifier(),
119 associatedObjectForCache
120 );
121};
122exports.getFullModuleName = getFullModuleName;
123
124/**
125 * @param {Chunk} chunk the chunk
126 * @param {ChunkGraph} chunkGraph the chunk graph
127 * @param {string} context context directory
128 * @param {string} delimiter delimiter for names
129 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
130 * @returns {string} short chunk name
131 */
132const getShortChunkName = (
133 chunk,
134 chunkGraph,
135 context,
136 delimiter,
137 associatedObjectForCache
138) => {
139 const modules = chunkGraph.getChunkRootModules(chunk);
140 const shortModuleNames = modules.map(m =>
141 requestToId(getShortModuleName(m, context, associatedObjectForCache))
142 );
143 chunk.idNameHints.sort();
144 const chunkName = Array.from(chunk.idNameHints)
145 .concat(shortModuleNames)
146 .filter(Boolean)
147 .join(delimiter);
148 return shortenLongString(chunkName, delimiter);
149};
150exports.getShortChunkName = getShortChunkName;
151
152/**
153 * @param {Chunk} chunk the chunk
154 * @param {ChunkGraph} chunkGraph the chunk graph
155 * @param {string} context context directory
156 * @param {string} delimiter delimiter for names
157 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
158 * @returns {string} short chunk name
159 */
160const getLongChunkName = (
161 chunk,
162 chunkGraph,
163 context,
164 delimiter,
165 associatedObjectForCache
166) => {
167 const modules = chunkGraph.getChunkRootModules(chunk);
168 const shortModuleNames = modules.map(m =>
169 requestToId(getShortModuleName(m, context, associatedObjectForCache))
170 );
171 const longModuleNames = modules.map(m =>
172 requestToId(getLongModuleName("", m, context, associatedObjectForCache))
173 );
174 chunk.idNameHints.sort();
175 const chunkName = Array.from(chunk.idNameHints)
176 .concat(shortModuleNames, longModuleNames)
177 .filter(Boolean)
178 .join(delimiter);
179 return shortenLongString(chunkName, delimiter);
180};
181exports.getLongChunkName = getLongChunkName;
182
183/**
184 * @param {Chunk} chunk the chunk
185 * @param {ChunkGraph} chunkGraph the chunk graph
186 * @param {string} context context directory
187 * @param {Object=} associatedObjectForCache an object to which the cache will be attached
188 * @returns {string} full chunk name
189 */
190const getFullChunkName = (
191 chunk,
192 chunkGraph,
193 context,
194 associatedObjectForCache
195) => {
196 if (chunk.name) return chunk.name;
197 const modules = chunkGraph.getChunkRootModules(chunk);
198 const fullModuleNames = modules.map(m =>
199 makePathsRelative(context, m.identifier(), associatedObjectForCache)
200 );
201 return fullModuleNames.join();
202};
203exports.getFullChunkName = getFullChunkName;
204
205/**
206 * @template K
207 * @template V
208 * @param {Map<K, V[]>} map a map from key to values
209 * @param {K} key key
210 * @param {V} value value
211 * @returns {void}
212 */
213const addToMapOfItems = (map, key, value) => {
214 let array = map.get(key);
215 if (array === undefined) {
216 array = [];
217 map.set(key, array);
218 }
219 array.push(value);
220};
221
222/**
223 * @param {Compilation} compilation the compilation
224 * @returns {Set<string>} used module ids as strings
225 */
226const getUsedModuleIds = compilation => {
227 const chunkGraph = compilation.chunkGraph;
228
229 /** @type {Set<string>} */
230 const usedIds = new Set();
231 if (compilation.usedModuleIds) {
232 for (const id of compilation.usedModuleIds) {
233 usedIds.add(id + "");
234 }
235 }
236
237 for (const module of compilation.modules) {
238 const moduleId = chunkGraph.getModuleId(module);
239 if (moduleId !== null) {
240 usedIds.add(moduleId + "");
241 }
242 }
243
244 return usedIds;
245};
246exports.getUsedModuleIds = getUsedModuleIds;
247
248/**
249 * @param {Compilation} compilation the compilation
250 * @returns {Set<string>} used chunk ids as strings
251 */
252const getUsedChunkIds = compilation => {
253 /** @type {Set<string>} */
254 const usedIds = new Set();
255 if (compilation.usedChunkIds) {
256 for (const id of compilation.usedChunkIds) {
257 usedIds.add(id + "");
258 }
259 }
260
261 for (const chunk of compilation.chunks) {
262 const chunkId = chunk.id;
263 if (chunkId !== null) {
264 usedIds.add(chunkId + "");
265 }
266 }
267
268 return usedIds;
269};
270exports.getUsedChunkIds = getUsedChunkIds;
271
272/**
273 * @template T
274 * @param {Iterable<T>} items list of items to be named
275 * @param {function(T): string} getShortName get a short name for an item
276 * @param {function(T, string): string} getLongName get a long name for an item
277 * @param {function(T, T): -1|0|1} comparator order of items
278 * @param {Set<string>} usedIds already used ids, will not be assigned
279 * @param {function(T, string): void} assignName assign a name to an item
280 * @returns {T[]} list of items without a name
281 */
282const assignNames = (
283 items,
284 getShortName,
285 getLongName,
286 comparator,
287 usedIds,
288 assignName
289) => {
290 /** @type {Map<string, T[]>} */
291 const nameToItems = new Map();
292
293 for (const item of items) {
294 const name = getShortName(item);
295 addToMapOfItems(nameToItems, name, item);
296 }
297
298 /** @type {Map<string, T[]>} */
299 const nameToItems2 = new Map();
300
301 for (const [name, items] of nameToItems) {
302 if (items.length > 1 || !name) {
303 for (const item of items) {
304 const longName = getLongName(item, name);
305 addToMapOfItems(nameToItems2, longName, item);
306 }
307 } else {
308 addToMapOfItems(nameToItems2, name, items[0]);
309 }
310 }
311
312 /** @type {T[]} */
313 const unnamedItems = [];
314
315 for (const [name, items] of nameToItems2) {
316 if (!name) {
317 for (const item of items) {
318 unnamedItems.push(item);
319 }
320 } else if (items.length === 1 && !usedIds.has(name)) {
321 assignName(items[0], name);
322 usedIds.add(name);
323 } else {
324 items.sort(comparator);
325 let i = 0;
326 for (const item of items) {
327 while (nameToItems2.has(name + i) && usedIds.has(name + i)) i++;
328 assignName(item, name + i);
329 usedIds.add(name + i);
330 i++;
331 }
332 }
333 }
334
335 unnamedItems.sort(comparator);
336 return unnamedItems;
337};
338exports.assignNames = assignNames;
339
340/**
341 * @template T
342 * @param {T[]} items list of items to be named
343 * @param {function(T): string} getName get a name for an item
344 * @param {function(T, T): -1|0|1} comparator order of items
345 * @param {function(T, number): boolean} assignId assign an id to an item
346 * @param {number[]} ranges usable ranges for ids
347 * @param {number} expandFactor factor to create more ranges
348 * @param {number} extraSpace extra space to allocate, i. e. when some ids are already used
349 * @returns {void}
350 */
351const assignDeterministicIds = (
352 items,
353 getName,
354 comparator,
355 assignId,
356 ranges = [10],
357 expandFactor = 10,
358 extraSpace = 0
359) => {
360 items.sort(comparator);
361
362 // max 5% fill rate
363 const optimalRange = Math.min(
364 Math.ceil(items.length * 20) + extraSpace,
365 Number.MAX_SAFE_INTEGER
366 );
367
368 let i = 0;
369 let range = ranges[i];
370 while (range < optimalRange) {
371 i++;
372 if (i < ranges.length) {
373 range = Math.min(ranges[i], Number.MAX_SAFE_INTEGER);
374 } else {
375 range = Math.min(range * expandFactor, Number.MAX_SAFE_INTEGER);
376 }
377 }
378
379 for (const item of items) {
380 const ident = getName(item);
381 let id;
382 let i = 0;
383 do {
384 id = numberHash(ident + i++, range);
385 } while (!assignId(item, id));
386 }
387};
388exports.assignDeterministicIds = assignDeterministicIds;
389
390/**
391 * @param {Iterable<Module>} modules the modules
392 * @param {Compilation} compilation the compilation
393 * @returns {void}
394 */
395const assignAscendingModuleIds = (modules, compilation) => {
396 const chunkGraph = compilation.chunkGraph;
397
398 const usedIds = getUsedModuleIds(compilation);
399
400 let nextId = 0;
401 let assignId;
402 if (usedIds.size > 0) {
403 assignId = module => {
404 if (chunkGraph.getModuleId(module) === null) {
405 while (usedIds.has(nextId + "")) nextId++;
406 chunkGraph.setModuleId(module, nextId++);
407 }
408 };
409 } else {
410 assignId = module => {
411 if (chunkGraph.getModuleId(module) === null) {
412 chunkGraph.setModuleId(module, nextId++);
413 }
414 };
415 }
416 for (const module of modules) {
417 assignId(module);
418 }
419};
420exports.assignAscendingModuleIds = assignAscendingModuleIds;
421
422/**
423 * @param {Iterable<Chunk>} chunks the chunks
424 * @param {Compilation} compilation the compilation
425 * @returns {void}
426 */
427const assignAscendingChunkIds = (chunks, compilation) => {
428 const usedIds = getUsedChunkIds(compilation);
429
430 let nextId = 0;
431 if (usedIds.size > 0) {
432 for (const chunk of chunks) {
433 if (chunk.id === null) {
434 while (usedIds.has(nextId + "")) nextId++;
435 chunk.id = nextId;
436 chunk.ids = [nextId];
437 nextId++;
438 }
439 }
440 } else {
441 for (const chunk of chunks) {
442 if (chunk.id === null) {
443 chunk.id = nextId;
444 chunk.ids = [nextId];
445 nextId++;
446 }
447 }
448 }
449};
450exports.assignAscendingChunkIds = assignAscendingChunkIds;
Note: See TracBrowser for help on using the repository browser.