настройка webpack
This commit is contained in:
274
node_modules/webpack/lib/util/deterministicGrouping.js
generated
vendored
Normal file
274
node_modules/webpack/lib/util/deterministicGrouping.js
generated
vendored
Normal file
@ -0,0 +1,274 @@
|
||||
"use strict";
|
||||
|
||||
// Simulations show these probabilities for a single change
|
||||
// 93.1% that one group is invalidated
|
||||
// 4.8% that two groups are invalidated
|
||||
// 1.1% that 3 groups are invalidated
|
||||
// 0.1% that 4 or more groups are invalidated
|
||||
//
|
||||
// And these for removing/adding 10 lexically adjacent files
|
||||
// 64.5% that one group is invalidated
|
||||
// 24.8% that two groups are invalidated
|
||||
// 7.8% that 3 groups are invalidated
|
||||
// 2.7% that 4 or more groups are invalidated
|
||||
//
|
||||
// And these for removing/adding 3 random files
|
||||
// 0% that one group is invalidated
|
||||
// 3.7% that two groups are invalidated
|
||||
// 80.8% that 3 groups are invalidated
|
||||
// 12.3% that 4 groups are invalidated
|
||||
// 3.2% that 5 or more groups are invalidated
|
||||
|
||||
/**
|
||||
*
|
||||
* @param {string} a key
|
||||
* @param {string} b key
|
||||
* @returns {number} the similarity as number
|
||||
*/
|
||||
const similarity = (a, b) => {
|
||||
const l = Math.min(a.length, b.length);
|
||||
let dist = 0;
|
||||
for (let i = 0; i < l; i++) {
|
||||
const ca = a.charCodeAt(i);
|
||||
const cb = b.charCodeAt(i);
|
||||
dist += Math.max(0, 10 - Math.abs(ca - cb));
|
||||
}
|
||||
return dist;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param {string} a key
|
||||
* @param {string} b key
|
||||
* @returns {string} the common part and a single char for the difference
|
||||
*/
|
||||
const getName = (a, b) => {
|
||||
const l = Math.min(a.length, b.length);
|
||||
let r = "";
|
||||
for (let i = 0; i < l; i++) {
|
||||
const ca = a.charAt(i);
|
||||
const cb = b.charAt(i);
|
||||
r += ca;
|
||||
if (ca === cb) {
|
||||
continue;
|
||||
}
|
||||
return r;
|
||||
}
|
||||
return a;
|
||||
};
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Node {
|
||||
/**
|
||||
* @param {T} item item
|
||||
* @param {string} key key
|
||||
* @param {number} size size
|
||||
*/
|
||||
constructor(item, key, size) {
|
||||
this.item = item;
|
||||
this.key = key;
|
||||
this.size = size;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Group {
|
||||
/**
|
||||
* @param {Node<T>[]} nodes nodes
|
||||
* @param {number[]} similarities similarities between the nodes (length = nodes.length - 1)
|
||||
*/
|
||||
constructor(nodes, similarities) {
|
||||
this.nodes = nodes;
|
||||
this.similarities = similarities;
|
||||
this.size = nodes.reduce((size, node) => size + node.size, 0);
|
||||
/** @type {string} */
|
||||
this.key = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} GroupedItems<T>
|
||||
* @property {string} key
|
||||
* @property {T[]} items
|
||||
* @property {number} size
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @typedef {Object} Options
|
||||
* @property {number} maxSize maximum size of a group
|
||||
* @property {number} minSize minimum size of a group (preferred over maximum size)
|
||||
* @property {Iterable<T>} items a list of items
|
||||
* @property {function(T): number} getSize function to get size of an item
|
||||
* @property {function(T): string} getKey function to get the key of an item
|
||||
*/
|
||||
|
||||
/**
|
||||
* @template T
|
||||
* @param {Options<T>} options options object
|
||||
* @returns {GroupedItems<T>[]} grouped items
|
||||
*/
|
||||
module.exports = ({ maxSize, minSize, items, getSize, getKey }) => {
|
||||
/** @type {Group<T>[]} */
|
||||
const result = [];
|
||||
|
||||
const nodes = Array.from(
|
||||
items,
|
||||
item => new Node(item, getKey(item), getSize(item))
|
||||
);
|
||||
|
||||
/** @type {Node<T>[]} */
|
||||
const initialNodes = [];
|
||||
|
||||
// lexically ordering of keys
|
||||
nodes.sort((a, b) => {
|
||||
if (a.key < b.key) return -1;
|
||||
if (a.key > b.key) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// return nodes bigger than maxSize directly as group
|
||||
for (const node of nodes) {
|
||||
if (node.size >= maxSize) {
|
||||
result.push(new Group([node], []));
|
||||
} else {
|
||||
initialNodes.push(node);
|
||||
}
|
||||
}
|
||||
|
||||
if (initialNodes.length > 0) {
|
||||
// calculate similarities between lexically adjacent nodes
|
||||
/** @type {number[]} */
|
||||
const similarities = [];
|
||||
for (let i = 1; i < initialNodes.length; i++) {
|
||||
const a = initialNodes[i - 1];
|
||||
const b = initialNodes[i];
|
||||
similarities.push(similarity(a.key, b.key));
|
||||
}
|
||||
|
||||
const initialGroup = new Group(initialNodes, similarities);
|
||||
|
||||
if (initialGroup.size < minSize) {
|
||||
// We hit an edgecase where the working set is already smaller than minSize
|
||||
// We merge it with the smallest result node to keep minSize intact
|
||||
if (result.length > 0) {
|
||||
const smallestGroup = result.reduce((min, group) =>
|
||||
min.size > group.size ? group : min
|
||||
);
|
||||
for (const node of initialGroup.nodes) smallestGroup.nodes.push(node);
|
||||
smallestGroup.nodes.sort((a, b) => {
|
||||
if (a.key < b.key) return -1;
|
||||
if (a.key > b.key) return 1;
|
||||
return 0;
|
||||
});
|
||||
} else {
|
||||
// There are no other nodes
|
||||
// We use all nodes and have to accept that it's smaller than minSize
|
||||
result.push(initialGroup);
|
||||
}
|
||||
} else {
|
||||
const queue = [initialGroup];
|
||||
|
||||
while (queue.length) {
|
||||
const group = queue.pop();
|
||||
// only groups bigger than maxSize need to be splitted
|
||||
if (group.size < maxSize) {
|
||||
result.push(group);
|
||||
continue;
|
||||
}
|
||||
|
||||
// find unsplittable area from left and right
|
||||
// going minSize from left and right
|
||||
// at least one node need to be included otherwise we get stuck
|
||||
let left = 0;
|
||||
let leftSize = 0;
|
||||
while (leftSize <= minSize) {
|
||||
leftSize += group.nodes[left].size;
|
||||
left++;
|
||||
}
|
||||
let right = group.nodes.length - 1;
|
||||
let rightSize = 0;
|
||||
while (rightSize <= minSize) {
|
||||
rightSize += group.nodes[right].size;
|
||||
right--;
|
||||
}
|
||||
|
||||
if (left - 1 > right) {
|
||||
// can't split group while holding minSize
|
||||
// because minSize is preferred of maxSize we return
|
||||
// the group here even while it's too big
|
||||
// To avoid this make sure maxSize > minSize * 3
|
||||
result.push(group);
|
||||
continue;
|
||||
}
|
||||
if (left <= right) {
|
||||
// when there is a area between left and right
|
||||
// we look for best split point
|
||||
// we split at the minimum similarity
|
||||
// here key space is separated the most
|
||||
let best = left - 1;
|
||||
let bestSimilarity = group.similarities[best];
|
||||
for (let i = left; i <= right; i++) {
|
||||
const similarity = group.similarities[i];
|
||||
if (similarity < bestSimilarity) {
|
||||
best = i;
|
||||
bestSimilarity = similarity;
|
||||
}
|
||||
}
|
||||
left = best + 1;
|
||||
right = best;
|
||||
}
|
||||
|
||||
// create two new groups for left and right area
|
||||
// and queue them up
|
||||
const rightNodes = [group.nodes[right + 1]];
|
||||
/** @type {number[]} */
|
||||
const rightSimilaries = [];
|
||||
for (let i = right + 2; i < group.nodes.length; i++) {
|
||||
rightSimilaries.push(group.similarities[i - 1]);
|
||||
rightNodes.push(group.nodes[i]);
|
||||
}
|
||||
queue.push(new Group(rightNodes, rightSimilaries));
|
||||
|
||||
const leftNodes = [group.nodes[0]];
|
||||
/** @type {number[]} */
|
||||
const leftSimilaries = [];
|
||||
for (let i = 1; i < left; i++) {
|
||||
leftSimilaries.push(group.similarities[i - 1]);
|
||||
leftNodes.push(group.nodes[i]);
|
||||
}
|
||||
queue.push(new Group(leftNodes, leftSimilaries));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// lexically ordering
|
||||
result.sort((a, b) => {
|
||||
if (a.nodes[0].key < b.nodes[0].key) return -1;
|
||||
if (a.nodes[0].key > b.nodes[0].key) return 1;
|
||||
return 0;
|
||||
});
|
||||
|
||||
// give every group a name
|
||||
for (let i = 0; i < result.length; i++) {
|
||||
const group = result[i];
|
||||
const first = group.nodes[0];
|
||||
const last = group.nodes[group.nodes.length - 1];
|
||||
let name = getName(first.key, last.key);
|
||||
group.key = name;
|
||||
}
|
||||
|
||||
// return the results
|
||||
return result.map(group => {
|
||||
/** @type {GroupedItems} */
|
||||
return {
|
||||
key: group.key,
|
||||
items: group.nodes.map(node => node.item),
|
||||
size: group.size
|
||||
};
|
||||
});
|
||||
};
|
||||
Reference in New Issue
Block a user