source: imaps-frontend/node_modules/webpack/lib/ids/IdHelpers.js

main
Last change on this file was 79a0317, checked in by stefan toskovski <stefantoska84@…>, 4 days ago

F4 Finalna Verzija

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