webpack 4.8.2 → 4.9.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +95 -52
- package/bin/webpack.js +128 -43
- package/lib/AmdMainTemplatePlugin.js +10 -0
- package/lib/AsyncDependencyToInitialChunkError.js +12 -2
- package/lib/BannerPlugin.js +115 -101
- package/lib/CaseSensitiveModulesWarning.js +20 -2
- package/lib/Chunk.js +1 -0
- package/lib/ChunkGroup.js +465 -465
- package/lib/ChunkRenderError.js +8 -0
- package/lib/ChunkTemplate.js +71 -71
- package/lib/Compilation.js +1 -1
- package/lib/Compiler.js +2 -1
- package/lib/ContextModule.js +8 -8
- package/lib/DllPlugin.js +3 -1
- package/lib/DllReferencePlugin.js +2 -1
- package/lib/Entrypoint.js +54 -54
- package/lib/EvalSourceMapDevToolModuleTemplatePlugin.js +115 -115
- package/lib/ExportPropertyMainTemplatePlugin.js +13 -0
- package/lib/Generator.js +52 -52
- package/lib/HotModuleReplacement.runtime.js +633 -633
- package/lib/JsonParser.js +2 -1
- package/lib/LibManifestPlugin.js +9 -0
- package/lib/LibraryTemplatePlugin.js +66 -33
- package/lib/MainTemplate.js +468 -468
- package/lib/Module.js +3 -3
- package/lib/ModuleDependencyError.js +12 -2
- package/lib/NormalModuleFactory.js +5 -3
- package/lib/Parser.js +27 -23
- package/lib/ProgressPlugin.js +1 -1
- package/lib/RecordIdsPlugin.js +3 -1
- package/lib/RuntimeTemplate.js +1 -1
- package/lib/SetVarMainTemplatePlugin.js +12 -0
- package/lib/SourceMapDevToolPlugin.js +11 -13
- package/lib/Template.js +289 -290
- package/lib/UmdMainTemplatePlugin.js +67 -32
- package/lib/WebpackError.js +8 -2
- package/lib/compareLocations.js +20 -0
- package/lib/debug/ProfilingPlugin.js +416 -416
- package/lib/dependencies/ContextDependencyHelpers.js +142 -142
- package/lib/dependencies/WebpackMissingModule.js +2 -2
- package/lib/optimize/RemoveEmptyChunksPlugin.js +42 -40
- package/lib/optimize/RuntimeChunkPlugin.js +9 -5
- package/lib/optimize/SplitChunksPlugin.js +195 -124
- package/lib/util/Queue.js +46 -46
- package/lib/util/SetHelpers.js +48 -48
- package/lib/util/SortableSet.js +106 -106
- package/lib/util/StackedSetMap.js +128 -128
- package/lib/util/cachedMerge.js +13 -0
- package/lib/util/identifier.js +5 -0
- package/lib/util/objectToMap.js +16 -16
- package/lib/wasm/WebAssemblyGenerator.js +280 -280
- package/lib/wasm/WebAssemblyParser.js +79 -79
- package/lib/web/JsonpMainTemplatePlugin.js +2 -2
- package/package.json +21 -17
- package/schemas/WebpackOptions.json +12 -1
- package/schemas/plugins/BannerPlugin.json +96 -85
- package/schemas/plugins/DllPlugin.json +4 -0
@@ -10,6 +10,7 @@ const GraphHelpers = require("../GraphHelpers");
|
|
10
10
|
const { isSubset } = require("../util/SetHelpers");
|
11
11
|
|
12
12
|
/** @typedef {import("../Chunk")} Chunk */
|
13
|
+
/** @typedef {import("../Module")} Module */
|
13
14
|
|
14
15
|
const hashFilename = name => {
|
15
16
|
return crypto
|
@@ -310,7 +311,6 @@ module.exports = class SplitChunksPlugin {
|
|
310
311
|
|
311
312
|
// Create a list of possible combinations
|
312
313
|
const combinationsCache = new Map(); // Map<string, Set<Chunk>[]>
|
313
|
-
const selectedChunksCacheByChunksSet = new WeakMap(); // WeakMap<Set<Chunk>, WeakMap<Function, {chunks: Chunk[], key: string}>>
|
314
314
|
|
315
315
|
const getCombinations = key => {
|
316
316
|
const chunksSet = chunkSetsInGraph.get(key);
|
@@ -330,14 +330,36 @@ module.exports = class SplitChunksPlugin {
|
|
330
330
|
return array;
|
331
331
|
};
|
332
332
|
|
333
|
+
/**
|
334
|
+
* @typedef {Object} SelectedChunksResult
|
335
|
+
* @property {Chunk[]} chunks the list of chunks
|
336
|
+
* @property {string} key a key of the list
|
337
|
+
*/
|
338
|
+
|
339
|
+
/**
|
340
|
+
* @typedef {function(Chunk): boolean} ChunkFilterFunction
|
341
|
+
*/
|
342
|
+
|
343
|
+
/** @type {WeakMap<Set<Chunk>, WeakMap<ChunkFilterFunction, SelectedChunksResult>>} */
|
344
|
+
const selectedChunksCacheByChunksSet = new WeakMap();
|
345
|
+
|
346
|
+
/**
|
347
|
+
* get list and key by applying the filter function to the list
|
348
|
+
* It is cached for performance reasons
|
349
|
+
* @param {Set<Chunk>} chunks list of chunks
|
350
|
+
* @param {ChunkFilterFunction} chunkFilter filter function for chunks
|
351
|
+
* @returns {SelectedChunksResult} list and key
|
352
|
+
*/
|
333
353
|
const getSelectedChunks = (chunks, chunkFilter) => {
|
334
354
|
let entry = selectedChunksCacheByChunksSet.get(chunks);
|
335
355
|
if (entry === undefined) {
|
336
|
-
entry = new
|
356
|
+
entry = new WeakMap();
|
337
357
|
selectedChunksCacheByChunksSet.set(chunks, entry);
|
338
358
|
}
|
359
|
+
/** @type {SelectedChunksResult} */
|
339
360
|
let entry2 = entry.get(chunkFilter);
|
340
361
|
if (entry2 === undefined) {
|
362
|
+
/** @type {Chunk[]} */
|
341
363
|
const selectedChunks = [];
|
342
364
|
for (const chunk of chunks) {
|
343
365
|
if (chunkFilter(chunk)) selectedChunks.push(chunk);
|
@@ -351,10 +373,76 @@ module.exports = class SplitChunksPlugin {
|
|
351
373
|
return entry2;
|
352
374
|
};
|
353
375
|
|
376
|
+
/**
|
377
|
+
* @typedef {Object} ChunksInfoItem
|
378
|
+
* @property {SortableSet} modules
|
379
|
+
* @property {TODO} cacheGroup
|
380
|
+
* @property {string} name
|
381
|
+
* @property {number} size
|
382
|
+
* @property {Map<Chunk, number>} chunks
|
383
|
+
* @property {Set<Chunk>} reuseableChunks
|
384
|
+
* @property {Set<string>} chunksKeys
|
385
|
+
*/
|
386
|
+
|
354
387
|
// Map a list of chunks to a list of modules
|
355
388
|
// For the key the chunk "index" is used, the value is a SortableSet of modules
|
389
|
+
/** @type {Map<string, ChunksInfoItem>} */
|
356
390
|
const chunksInfoMap = new Map();
|
357
391
|
|
392
|
+
/**
|
393
|
+
* @param {TODO} cacheGroup the current cache group
|
394
|
+
* @param {Chunk[]} selectedChunks chunks selected for this module
|
395
|
+
* @param {string} selectedChunksKey a key of selectedChunks
|
396
|
+
* @param {Module} module the current module
|
397
|
+
* @returns {void}
|
398
|
+
*/
|
399
|
+
const addModuleToChunksInfoMap = (
|
400
|
+
cacheGroup,
|
401
|
+
selectedChunks,
|
402
|
+
selectedChunksKey,
|
403
|
+
module
|
404
|
+
) => {
|
405
|
+
// Break if minimum number of chunks is not reached
|
406
|
+
if (selectedChunks.length < cacheGroup.minChunks) return;
|
407
|
+
// Determine name for split chunk
|
408
|
+
const name = cacheGroup.getName(
|
409
|
+
module,
|
410
|
+
selectedChunks,
|
411
|
+
cacheGroup.key
|
412
|
+
);
|
413
|
+
// Create key for maps
|
414
|
+
// When it has a name we use the name as key
|
415
|
+
// Elsewise we create the key from chunks and cache group key
|
416
|
+
// This automatically merges equal names
|
417
|
+
const key =
|
418
|
+
(name && `name:${name}`) ||
|
419
|
+
`chunks:${selectedChunksKey} key:${cacheGroup.key}`;
|
420
|
+
// Add module to maps
|
421
|
+
let info = chunksInfoMap.get(key);
|
422
|
+
if (info === undefined) {
|
423
|
+
chunksInfoMap.set(
|
424
|
+
key,
|
425
|
+
(info = {
|
426
|
+
modules: new SortableSet(undefined, sortByIdentifier),
|
427
|
+
cacheGroup,
|
428
|
+
name,
|
429
|
+
size: 0,
|
430
|
+
chunks: new Map(),
|
431
|
+
reuseableChunks: new Set(),
|
432
|
+
chunksKeys: new Set()
|
433
|
+
})
|
434
|
+
);
|
435
|
+
}
|
436
|
+
info.modules.add(module);
|
437
|
+
info.size += module.size();
|
438
|
+
if (!info.chunksKeys.has(selectedChunksKey)) {
|
439
|
+
info.chunksKeys.add(selectedChunksKey);
|
440
|
+
for (const chunk of selectedChunks) {
|
441
|
+
info.chunks.set(chunk, chunk.getNumberOfModules());
|
442
|
+
}
|
443
|
+
}
|
444
|
+
};
|
445
|
+
|
358
446
|
// Walk through all modules
|
359
447
|
for (const module of compilation.modules) {
|
360
448
|
// Get cache group
|
@@ -422,55 +510,17 @@ module.exports = class SplitChunksPlugin {
|
|
422
510
|
chunkCombination,
|
423
511
|
cacheGroup.chunksFilter
|
424
512
|
);
|
425
|
-
|
426
|
-
|
427
|
-
|
428
|
-
const name = cacheGroup.getName(
|
429
|
-
module,
|
513
|
+
|
514
|
+
addModuleToChunksInfoMap(
|
515
|
+
cacheGroup,
|
430
516
|
selectedChunks,
|
431
|
-
|
517
|
+
selectedChunksKey,
|
518
|
+
module
|
432
519
|
);
|
433
|
-
// Create key for maps
|
434
|
-
// When it has a name we use the name as key
|
435
|
-
// Elsewise we create the key from chunks and cache group key
|
436
|
-
// This automatically merges equal names
|
437
|
-
const key =
|
438
|
-
(name && `name:${name}`) ||
|
439
|
-
`chunks:${selectedChunksKey} key:${cacheGroup.key}`;
|
440
|
-
// Add module to maps
|
441
|
-
let info = chunksInfoMap.get(key);
|
442
|
-
if (info === undefined) {
|
443
|
-
chunksInfoMap.set(
|
444
|
-
key,
|
445
|
-
(info = {
|
446
|
-
modules: new SortableSet(undefined, sortByIdentifier),
|
447
|
-
cacheGroup,
|
448
|
-
name,
|
449
|
-
size: 0,
|
450
|
-
chunks: new Map(),
|
451
|
-
reusedableChunks: new Set(),
|
452
|
-
chunksKeys: new Set()
|
453
|
-
})
|
454
|
-
);
|
455
|
-
}
|
456
|
-
info.modules.add(module);
|
457
|
-
info.size += module.size();
|
458
|
-
if (!info.chunksKeys.has(selectedChunksKey)) {
|
459
|
-
info.chunksKeys.add(selectedChunksKey);
|
460
|
-
for (const chunk of selectedChunks) {
|
461
|
-
info.chunks.set(chunk, chunk.getNumberOfModules());
|
462
|
-
}
|
463
|
-
}
|
464
520
|
}
|
465
521
|
}
|
466
522
|
}
|
467
523
|
|
468
|
-
for (const [key, info] of chunksInfoMap) {
|
469
|
-
// Get size of module lists
|
470
|
-
if (info.size < info.cacheGroup.minSize) {
|
471
|
-
chunksInfoMap.delete(key);
|
472
|
-
}
|
473
|
-
}
|
474
524
|
while (chunksInfoMap.size > 0) {
|
475
525
|
// Find best matching entry
|
476
526
|
let bestEntryKey;
|
@@ -478,15 +528,20 @@ module.exports = class SplitChunksPlugin {
|
|
478
528
|
for (const pair of chunksInfoMap) {
|
479
529
|
const key = pair[0];
|
480
530
|
const info = pair[1];
|
481
|
-
if (
|
482
|
-
bestEntry
|
483
|
-
|
484
|
-
|
485
|
-
bestEntry
|
486
|
-
|
531
|
+
if (info.size >= info.cacheGroup.minSize) {
|
532
|
+
if (bestEntry === undefined) {
|
533
|
+
bestEntry = info;
|
534
|
+
bestEntryKey = key;
|
535
|
+
} else if (compareEntries(bestEntry, info) < 0) {
|
536
|
+
bestEntry = info;
|
537
|
+
bestEntryKey = key;
|
538
|
+
}
|
487
539
|
}
|
488
540
|
}
|
489
541
|
|
542
|
+
// No suitable item left
|
543
|
+
if (bestEntry === undefined) break;
|
544
|
+
|
490
545
|
const item = bestEntry;
|
491
546
|
chunksInfoMap.delete(bestEntryKey);
|
492
547
|
|
@@ -517,12 +572,19 @@ module.exports = class SplitChunksPlugin {
|
|
517
572
|
}
|
518
573
|
}
|
519
574
|
}
|
520
|
-
|
521
|
-
|
522
|
-
|
575
|
+
// Check if maxRequests condition can be fullfilled
|
576
|
+
|
577
|
+
const usedChunks = Array.from(item.chunks.keys()).filter(chunk => {
|
523
578
|
// skip if we address ourself
|
524
|
-
|
525
|
-
|
579
|
+
return (
|
580
|
+
(!chunkName || chunk.name !== chunkName) && chunk !== newChunk
|
581
|
+
);
|
582
|
+
});
|
583
|
+
|
584
|
+
// Skip when no chunk selected
|
585
|
+
if (usedChunks.length === 0) continue;
|
586
|
+
|
587
|
+
const chunkInLimit = usedChunks.filter(chunk => {
|
526
588
|
// respect max requests when not enforced
|
527
589
|
const maxRequests = chunk.isOnlyInitial()
|
528
590
|
? item.cacheGroup.maxInitialRequests
|
@@ -532,88 +594,97 @@ module.exports = class SplitChunksPlugin {
|
|
532
594
|
item.cacheGroup.maxAsyncRequests
|
533
595
|
)
|
534
596
|
: item.cacheGroup.maxAsyncRequests;
|
535
|
-
|
536
|
-
|
537
|
-
|
538
|
-
|
539
|
-
|
597
|
+
return !isFinite(maxRequests) || getRequests(chunk) < maxRequests;
|
598
|
+
});
|
599
|
+
|
600
|
+
if (chunkInLimit.length < usedChunks.length) {
|
601
|
+
for (const module of item.modules) {
|
602
|
+
addModuleToChunksInfoMap(
|
603
|
+
item.cacheGroup,
|
604
|
+
chunkInLimit,
|
605
|
+
getKey(chunkInLimit),
|
606
|
+
module
|
607
|
+
);
|
540
608
|
}
|
609
|
+
continue;
|
610
|
+
}
|
611
|
+
|
612
|
+
// Create the new chunk if not reusing one
|
613
|
+
if (!isReused) {
|
614
|
+
newChunk = compilation.addChunk(chunkName);
|
615
|
+
}
|
616
|
+
// Walk through all chunks
|
617
|
+
for (const chunk of usedChunks) {
|
541
618
|
// Add graph connections for splitted chunk
|
542
619
|
chunk.split(newChunk);
|
543
|
-
usedChunks.push(chunk);
|
544
620
|
}
|
545
621
|
|
546
|
-
//
|
547
|
-
|
548
|
-
|
549
|
-
|
550
|
-
|
551
|
-
|
552
|
-
|
553
|
-
|
554
|
-
|
555
|
-
|
622
|
+
// Add a note to the chunk
|
623
|
+
newChunk.chunkReason = isReused
|
624
|
+
? "reused as split chunk"
|
625
|
+
: "split chunk";
|
626
|
+
if (item.cacheGroup.key) {
|
627
|
+
newChunk.chunkReason += ` (cache group: ${item.cacheGroup.key})`;
|
628
|
+
}
|
629
|
+
if (chunkName) {
|
630
|
+
newChunk.chunkReason += ` (name: ${chunkName})`;
|
631
|
+
// If the chosen name is already an entry point we remove the entry point
|
632
|
+
const entrypoint = compilation.entrypoints.get(chunkName);
|
633
|
+
if (entrypoint) {
|
634
|
+
compilation.entrypoints.delete(chunkName);
|
635
|
+
entrypoint.remove();
|
636
|
+
newChunk.entryModule = undefined;
|
637
|
+
}
|
638
|
+
}
|
639
|
+
if (item.cacheGroup.filename) {
|
640
|
+
if (!newChunk.isOnlyInitial()) {
|
641
|
+
throw new Error(
|
642
|
+
"SplitChunksPlugin: You are trying to set a filename for a chunk which is (also) loaded on demand. " +
|
643
|
+
"The runtime can only handle loading of chunks which match the chunkFilename schema. " +
|
644
|
+
"Using a custom filename would fail at runtime. " +
|
645
|
+
`(cache group: ${item.cacheGroup.key})`
|
646
|
+
);
|
556
647
|
}
|
557
|
-
|
558
|
-
|
559
|
-
|
560
|
-
|
561
|
-
|
562
|
-
|
563
|
-
|
564
|
-
|
648
|
+
newChunk.filenameTemplate = item.cacheGroup.filename;
|
649
|
+
}
|
650
|
+
if (!isReused) {
|
651
|
+
// Add all modules to the new chunk
|
652
|
+
for (const module of item.modules) {
|
653
|
+
if (typeof module.chunkCondition === "function") {
|
654
|
+
if (!module.chunkCondition(newChunk)) continue;
|
655
|
+
}
|
656
|
+
// Add module to new chunk
|
657
|
+
GraphHelpers.connectChunkAndModule(newChunk, module);
|
658
|
+
// Remove module from used chunks
|
659
|
+
for (const chunk of usedChunks) {
|
660
|
+
chunk.removeModule(module);
|
661
|
+
module.rewriteChunkInReasons(chunk, [newChunk]);
|
565
662
|
}
|
566
663
|
}
|
567
|
-
|
568
|
-
|
569
|
-
|
570
|
-
|
571
|
-
|
572
|
-
|
573
|
-
`(cache group: ${item.cacheGroup.key})`
|
574
|
-
);
|
664
|
+
} else {
|
665
|
+
// Remove all modules from used chunks
|
666
|
+
for (const module of item.modules) {
|
667
|
+
for (const chunk of usedChunks) {
|
668
|
+
chunk.removeModule(module);
|
669
|
+
module.rewriteChunkInReasons(chunk, [newChunk]);
|
575
670
|
}
|
576
|
-
newChunk.filenameTemplate = item.cacheGroup.filename;
|
577
671
|
}
|
578
|
-
|
579
|
-
|
672
|
+
}
|
673
|
+
// remove all modules from other entries and update size
|
674
|
+
for (const [key, info] of chunksInfoMap) {
|
675
|
+
if (isOverlap(info.chunks, item.chunks)) {
|
676
|
+
const oldSize = info.modules.size;
|
580
677
|
for (const module of item.modules) {
|
581
|
-
|
582
|
-
if (!module.chunkCondition(newChunk)) continue;
|
583
|
-
}
|
584
|
-
// Add module to new chunk
|
585
|
-
GraphHelpers.connectChunkAndModule(newChunk, module);
|
586
|
-
// Remove module from used chunks
|
587
|
-
for (const chunk of usedChunks) {
|
588
|
-
chunk.removeModule(module);
|
589
|
-
module.rewriteChunkInReasons(chunk, [newChunk]);
|
590
|
-
}
|
678
|
+
info.modules.delete(module);
|
591
679
|
}
|
592
|
-
|
593
|
-
|
594
|
-
|
595
|
-
for (const chunk of usedChunks) {
|
596
|
-
chunk.removeModule(module);
|
597
|
-
module.rewriteChunkInReasons(chunk, [newChunk]);
|
598
|
-
}
|
680
|
+
if (info.modules.size === 0) {
|
681
|
+
chunksInfoMap.delete(key);
|
682
|
+
continue;
|
599
683
|
}
|
600
|
-
|
601
|
-
|
602
|
-
|
603
|
-
if (isOverlap(info.chunks, item.chunks)) {
|
604
|
-
const oldSize = info.modules.size;
|
605
|
-
for (const module of item.modules) {
|
606
|
-
info.modules.delete(module);
|
607
|
-
}
|
608
|
-
if (info.modules.size === 0) {
|
684
|
+
if (info.modules.size !== oldSize) {
|
685
|
+
info.size = getModulesSize(info.modules);
|
686
|
+
if (info.size < info.cacheGroup.minSize)
|
609
687
|
chunksInfoMap.delete(key);
|
610
|
-
continue;
|
611
|
-
}
|
612
|
-
if (info.modules.size !== oldSize) {
|
613
|
-
info.size = getModulesSize(info.modules);
|
614
|
-
if (info.size < info.cacheGroup.minSize)
|
615
|
-
chunksInfoMap.delete(key);
|
616
|
-
}
|
617
688
|
}
|
618
689
|
}
|
619
690
|
}
|
package/lib/util/Queue.js
CHANGED
@@ -1,46 +1,46 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
/**
|
4
|
-
* @template T
|
5
|
-
*/
|
6
|
-
class Queue {
|
7
|
-
/**
|
8
|
-
* @param {IterableIterator<T>=} items The initial elements.
|
9
|
-
*/
|
10
|
-
constructor(items) {
|
11
|
-
/** @private @type {Set<T>} */
|
12
|
-
this.set = new Set(items);
|
13
|
-
/** @private @type {Iterator<T>} */
|
14
|
-
this.iterator = this.set[Symbol.iterator]();
|
15
|
-
}
|
16
|
-
|
17
|
-
/**
|
18
|
-
* Returns the number of elements in this queue.
|
19
|
-
* @returns {number} The number of elements in this queue.
|
20
|
-
*/
|
21
|
-
get length() {
|
22
|
-
return this.set.size;
|
23
|
-
}
|
24
|
-
|
25
|
-
/**
|
26
|
-
* Appends the specified element to this queue.
|
27
|
-
* @param {T} item The element to add.
|
28
|
-
* @returns {void}
|
29
|
-
*/
|
30
|
-
enqueue(item) {
|
31
|
-
this.set.add(item);
|
32
|
-
}
|
33
|
-
|
34
|
-
/**
|
35
|
-
* Retrieves and removes the head of this queue.
|
36
|
-
* @returns {T | undefined} The head of the queue of `undefined` if this queue is empty.
|
37
|
-
*/
|
38
|
-
dequeue() {
|
39
|
-
const result = this.iterator.next();
|
40
|
-
if (result.done) return undefined;
|
41
|
-
this.set.delete(result.value);
|
42
|
-
return result.value;
|
43
|
-
}
|
44
|
-
}
|
45
|
-
|
46
|
-
module.exports = Queue;
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* @template T
|
5
|
+
*/
|
6
|
+
class Queue {
|
7
|
+
/**
|
8
|
+
* @param {IterableIterator<T>=} items The initial elements.
|
9
|
+
*/
|
10
|
+
constructor(items) {
|
11
|
+
/** @private @type {Set<T>} */
|
12
|
+
this.set = new Set(items);
|
13
|
+
/** @private @type {Iterator<T>} */
|
14
|
+
this.iterator = this.set[Symbol.iterator]();
|
15
|
+
}
|
16
|
+
|
17
|
+
/**
|
18
|
+
* Returns the number of elements in this queue.
|
19
|
+
* @returns {number} The number of elements in this queue.
|
20
|
+
*/
|
21
|
+
get length() {
|
22
|
+
return this.set.size;
|
23
|
+
}
|
24
|
+
|
25
|
+
/**
|
26
|
+
* Appends the specified element to this queue.
|
27
|
+
* @param {T} item The element to add.
|
28
|
+
* @returns {void}
|
29
|
+
*/
|
30
|
+
enqueue(item) {
|
31
|
+
this.set.add(item);
|
32
|
+
}
|
33
|
+
|
34
|
+
/**
|
35
|
+
* Retrieves and removes the head of this queue.
|
36
|
+
* @returns {T | undefined} The head of the queue of `undefined` if this queue is empty.
|
37
|
+
*/
|
38
|
+
dequeue() {
|
39
|
+
const result = this.iterator.next();
|
40
|
+
if (result.done) return undefined;
|
41
|
+
this.set.delete(result.value);
|
42
|
+
return result.value;
|
43
|
+
}
|
44
|
+
}
|
45
|
+
|
46
|
+
module.exports = Queue;
|
package/lib/util/SetHelpers.js
CHANGED
@@ -1,48 +1,48 @@
|
|
1
|
-
"use strict";
|
2
|
-
|
3
|
-
/**
|
4
|
-
* intersect creates Set containing the intersection of elements between all sets
|
5
|
-
* @param {Set[]} sets an array of sets being checked for shared elements
|
6
|
-
* @returns {Set<TODO>} returns a new Set containing the intersecting items
|
7
|
-
*/
|
8
|
-
function intersect(sets) {
|
9
|
-
if (sets.length === 0) return new Set();
|
10
|
-
if (sets.length === 1) return new Set(sets[0]);
|
11
|
-
let minSize = Infinity;
|
12
|
-
let minIndex = -1;
|
13
|
-
for (let i = 0; i < sets.length; i++) {
|
14
|
-
const size = sets[i].size;
|
15
|
-
if (size < minSize) {
|
16
|
-
minIndex = i;
|
17
|
-
minSize = size;
|
18
|
-
}
|
19
|
-
}
|
20
|
-
const current = new Set(sets[minIndex]);
|
21
|
-
for (let i = 0; i < sets.length; i++) {
|
22
|
-
if (i === minIndex) continue;
|
23
|
-
const set = sets[i];
|
24
|
-
for (const item of current) {
|
25
|
-
if (!set.has(item)) {
|
26
|
-
current.delete(item);
|
27
|
-
}
|
28
|
-
}
|
29
|
-
}
|
30
|
-
return current;
|
31
|
-
}
|
32
|
-
|
33
|
-
/**
|
34
|
-
* Checks if a set is the subset of another set
|
35
|
-
* @param {Set<TODO>} bigSet a Set which contains the original elements to compare against
|
36
|
-
* @param {Set<TODO>} smallSet the set whos elements might be contained inside of bigSet
|
37
|
-
* @returns {boolean} returns true if smallSet contains all elements inside of the bigSet
|
38
|
-
*/
|
39
|
-
function isSubset(bigSet, smallSet) {
|
40
|
-
if (bigSet.size < smallSet.size) return false;
|
41
|
-
for (const item of smallSet) {
|
42
|
-
if (!bigSet.has(item)) return false;
|
43
|
-
}
|
44
|
-
return true;
|
45
|
-
}
|
46
|
-
|
47
|
-
exports.intersect = intersect;
|
48
|
-
exports.isSubset = isSubset;
|
1
|
+
"use strict";
|
2
|
+
|
3
|
+
/**
|
4
|
+
* intersect creates Set containing the intersection of elements between all sets
|
5
|
+
* @param {Set[]} sets an array of sets being checked for shared elements
|
6
|
+
* @returns {Set<TODO>} returns a new Set containing the intersecting items
|
7
|
+
*/
|
8
|
+
function intersect(sets) {
|
9
|
+
if (sets.length === 0) return new Set();
|
10
|
+
if (sets.length === 1) return new Set(sets[0]);
|
11
|
+
let minSize = Infinity;
|
12
|
+
let minIndex = -1;
|
13
|
+
for (let i = 0; i < sets.length; i++) {
|
14
|
+
const size = sets[i].size;
|
15
|
+
if (size < minSize) {
|
16
|
+
minIndex = i;
|
17
|
+
minSize = size;
|
18
|
+
}
|
19
|
+
}
|
20
|
+
const current = new Set(sets[minIndex]);
|
21
|
+
for (let i = 0; i < sets.length; i++) {
|
22
|
+
if (i === minIndex) continue;
|
23
|
+
const set = sets[i];
|
24
|
+
for (const item of current) {
|
25
|
+
if (!set.has(item)) {
|
26
|
+
current.delete(item);
|
27
|
+
}
|
28
|
+
}
|
29
|
+
}
|
30
|
+
return current;
|
31
|
+
}
|
32
|
+
|
33
|
+
/**
|
34
|
+
* Checks if a set is the subset of another set
|
35
|
+
* @param {Set<TODO>} bigSet a Set which contains the original elements to compare against
|
36
|
+
* @param {Set<TODO>} smallSet the set whos elements might be contained inside of bigSet
|
37
|
+
* @returns {boolean} returns true if smallSet contains all elements inside of the bigSet
|
38
|
+
*/
|
39
|
+
function isSubset(bigSet, smallSet) {
|
40
|
+
if (bigSet.size < smallSet.size) return false;
|
41
|
+
for (const item of smallSet) {
|
42
|
+
if (!bigSet.has(item)) return false;
|
43
|
+
}
|
44
|
+
return true;
|
45
|
+
}
|
46
|
+
|
47
|
+
exports.intersect = intersect;
|
48
|
+
exports.isSubset = isSubset;
|