source: frontend/node_modules/webpack/lib/util/smartGrouping.js

Last change on this file was 9af201e, checked in by MBK <marija.karapandzova@…>, 13 days ago

Fix frontend appearance

  • Property mode set to 100644
File size: 5.7 KB
RevLine 
[9af201e]1/*
2 MIT License http://www.opensource.org/licenses/mit-license.php
3 Author Tobias Koppers @sokra
4*/
5
6"use strict";
7
8/**
9 * Defines the group options type used by this module.
10 * @typedef {object} GroupOptions
11 * @property {boolean=} groupChildren
12 * @property {boolean=} force
13 * @property {number=} targetGroupCount
14 */
15
16/**
17 * Defines the group config type used by this module.
18 * @template I
19 * @template G
20 * @typedef {object} GroupConfig
21 * @property {(item: I) => string[] | undefined} getKeys
22 * @property {(name: string, items: I[]) => GroupOptions=} getOptions
23 * @property {(key: string, children: I[], items: I[]) => G} createGroup
24 */
25
26/**
27 * Defines the group type used by this module.
28 * @template I
29 * @template G
30 * @typedef {{ config: GroupConfig<I, G>, name: string, alreadyGrouped: boolean, items: Items<I, G> | undefined }} Group
31 */
32
33/**
34 * Defines the groups type used by this module.
35 * @template I, G
36 * @typedef {Set<Group<I, G>>} Groups
37 */
38
39/**
40 * Defines the item with groups type used by this module.
41 * @template I
42 * @template G
43 * @typedef {object} ItemWithGroups
44 * @property {I} item
45 * @property {Groups<I, G>} groups
46 */
47
48/**
49 * Defines the items type used by this module.
50 * @template T, G
51 * @typedef {Set<ItemWithGroups<T, G>>} Items
52 */
53
54/**
55 * Returns grouped items.
56 * @template I
57 * @template G
58 * @template R
59 * @param {I[]} items the list of items
60 * @param {GroupConfig<I, G>[]} groupConfigs configuration
61 * @returns {(I | G)[]} grouped items
62 */
63const smartGrouping = (items, groupConfigs) => {
64 /** @type {Items<I, G>} */
65 const itemsWithGroups = new Set();
66 /** @type {Map<string, Group<I, G>>} */
67 const allGroups = new Map();
68 for (const item of items) {
69 /** @type {Groups<I, G>} */
70 const groups = new Set();
71 for (let i = 0; i < groupConfigs.length; i++) {
72 const groupConfig = groupConfigs[i];
73 const keys = groupConfig.getKeys(item);
74 if (keys) {
75 for (const name of keys) {
76 const key = `${i}:${name}`;
77 let group = allGroups.get(key);
78 if (group === undefined) {
79 allGroups.set(
80 key,
81 (group = {
82 config: groupConfig,
83 name,
84 alreadyGrouped: false,
85 items: undefined
86 })
87 );
88 }
89 groups.add(group);
90 }
91 }
92 }
93 itemsWithGroups.add({
94 item,
95 groups
96 });
97 }
98
99 /**
100 * Returns groups items.
101 * @param {Items<I, G>} itemsWithGroups input items with groups
102 * @returns {(I | G)[]} groups items
103 */
104 const runGrouping = (itemsWithGroups) => {
105 const totalSize = itemsWithGroups.size;
106 for (const entry of itemsWithGroups) {
107 for (const group of entry.groups) {
108 if (group.alreadyGrouped) continue;
109 const items = group.items;
110 if (items === undefined) {
111 group.items = new Set([entry]);
112 } else {
113 items.add(entry);
114 }
115 }
116 }
117 /** @type {Map<Group<I, G>, { items: Items<I, G>, options: GroupOptions | false | undefined, used: boolean }>} */
118 const groupMap = new Map();
119 for (const group of allGroups.values()) {
120 if (group.items) {
121 const items = group.items;
122 group.items = undefined;
123 groupMap.set(group, {
124 items,
125 options: undefined,
126 used: false
127 });
128 }
129 }
130 /** @type {(I | G)[]} */
131 const results = [];
132 for (;;) {
133 /** @type {Group<I, G> | undefined} */
134 let bestGroup;
135 let bestGroupSize = -1;
136 /** @type {Items<I, G> | undefined} */
137 let bestGroupItems;
138 /** @type {GroupOptions | false | undefined} */
139 let bestGroupOptions;
140 for (const [group, state] of groupMap) {
141 const { items, used } = state;
142 let options = state.options;
143 if (options === undefined) {
144 const groupConfig = group.config;
145 state.options = options =
146 (groupConfig.getOptions &&
147 groupConfig.getOptions(
148 group.name,
149 Array.from(items, ({ item }) => item)
150 )) ||
151 false;
152 }
153
154 const force = options && options.force;
155 if (!force) {
156 if (bestGroupOptions && bestGroupOptions.force) continue;
157 if (used) continue;
158 if (items.size <= 1 || totalSize - items.size <= 1) {
159 continue;
160 }
161 }
162 const targetGroupCount = (options && options.targetGroupCount) || 4;
163 const sizeValue = force
164 ? items.size
165 : Math.min(
166 items.size,
167 (totalSize * 2) / targetGroupCount +
168 itemsWithGroups.size -
169 items.size
170 );
171 if (
172 sizeValue > bestGroupSize ||
173 (force && (!bestGroupOptions || !bestGroupOptions.force))
174 ) {
175 bestGroup = group;
176 bestGroupSize = sizeValue;
177 bestGroupItems = items;
178 bestGroupOptions = options;
179 }
180 }
181 if (bestGroup === undefined) {
182 break;
183 }
184 const items = new Set(bestGroupItems);
185 const options = bestGroupOptions;
186
187 const groupChildren = !options || options.groupChildren !== false;
188
189 for (const item of items) {
190 itemsWithGroups.delete(item);
191 // Remove all groups that items have from the map to not select them again
192 for (const group of item.groups) {
193 const state = groupMap.get(group);
194 if (state !== undefined) {
195 state.items.delete(item);
196 if (state.items.size === 0) {
197 groupMap.delete(group);
198 } else {
199 state.options = undefined;
200 if (groupChildren) {
201 state.used = true;
202 }
203 }
204 }
205 }
206 }
207 groupMap.delete(bestGroup);
208
209 const key = bestGroup.name;
210 const groupConfig = bestGroup.config;
211
212 const allItems = Array.from(items, ({ item }) => item);
213
214 bestGroup.alreadyGrouped = true;
215 const children = groupChildren ? runGrouping(items) : allItems;
216 bestGroup.alreadyGrouped = false;
217 results.push(
218 groupConfig.createGroup(key, /** @type {I[]} */ (children), allItems)
219 );
220 }
221 for (const { item } of itemsWithGroups) {
222 results.push(item);
223 }
224 return results;
225 };
226 return runGrouping(itemsWithGroups);
227};
228
229module.exports = smartGrouping;
Note: See TracBrowser for help on using the repository browser.