1 |
|
2 |
|
3 |
|
4 |
|
5 | "use strict";
|
6 |
|
7 | const SortableSet = require("./util/SortableSet");
|
8 | const compareLocations = require("./compareLocations");
|
9 |
|
10 |
|
11 |
|
12 |
|
13 |
|
14 |
|
15 |
|
16 |
|
17 | let debugId = 5000;
|
18 |
|
19 |
|
20 |
|
21 |
|
22 |
|
23 |
|
24 | const getArray = set => Array.from(set);
|
25 |
|
26 | /**
|
27 | * A convenience method used to sort chunks based on their id's
|
28 | * @param {ChunkGroup} a first sorting comparator
|
29 | * @param {ChunkGroup} b second sorting comparator
|
30 | * @returns {1|0|-1} a sorting index to determine order
|
31 | */
|
32 | const sortById = (a, b) => {
|
33 | if (a.id < b.id) return -1;
|
34 | if (b.id < a.id) return 1;
|
35 | return 0;
|
36 | };
|
37 |
|
38 |
|
39 |
|
40 |
|
41 |
|
42 |
|
43 | const sortOrigin = (a, b) => {
|
44 | const aIdent = a.module ? a.module.identifier() : "";
|
45 | const bIdent = b.module ? b.module.identifier() : "";
|
46 | if (aIdent < bIdent) return -1;
|
47 | if (aIdent > bIdent) return 1;
|
48 | return compareLocations(a.loc, b.loc);
|
49 | };
|
50 |
|
51 | class ChunkGroup {
|
52 | |
53 |
|
54 |
|
55 |
|
56 | constructor(options) {
|
57 | if (typeof options === "string") {
|
58 | options = { name: options };
|
59 | } else if (!options) {
|
60 | options = { name: undefined };
|
61 | }
|
62 |
|
63 | this.groupDebugId = debugId++;
|
64 | this.options = options;
|
65 |
|
66 | this._children = new SortableSet(undefined, sortById);
|
67 | this._parents = new SortableSet(undefined, sortById);
|
68 | this._blocks = new SortableSet();
|
69 |
|
70 | this.chunks = [];
|
71 |
|
72 | this.origins = [];
|
73 |
|
74 |
|
75 | this._moduleIndices = new Map();
|
76 |
|
77 |
|
78 | this._moduleIndices2 = new Map();
|
79 | }
|
80 |
|
81 | |
82 |
|
83 |
|
84 |
|
85 |
|
86 | addOptions(options) {
|
87 | for (const key of Object.keys(options)) {
|
88 | if (this.options[key] === undefined) {
|
89 | this.options[key] = options[key];
|
90 | } else if (this.options[key] !== options[key]) {
|
91 | if (key.endsWith("Order")) {
|
92 | this.options[key] = Math.max(this.options[key], options[key]);
|
93 | } else {
|
94 | throw new Error(
|
95 | `ChunkGroup.addOptions: No option merge strategy for ${key}`
|
96 | );
|
97 | }
|
98 | }
|
99 | }
|
100 | }
|
101 |
|
102 | |
103 |
|
104 |
|
105 |
|
106 | get name() {
|
107 | return this.options.name;
|
108 | }
|
109 |
|
110 | |
111 |
|
112 |
|
113 |
|
114 |
|
115 | set name(value) {
|
116 | this.options.name = value;
|
117 | }
|
118 |
|
119 | |
120 |
|
121 |
|
122 |
|
123 | get debugId() {
|
124 | return Array.from(this.chunks, x => x.debugId).join("+");
|
125 | }
|
126 |
|
127 | |
128 |
|
129 |
|
130 |
|
131 | get id() {
|
132 | return Array.from(this.chunks, x => x.id).join("+");
|
133 | }
|
134 |
|
135 | |
136 |
|
137 |
|
138 |
|
139 |
|
140 | unshiftChunk(chunk) {
|
141 | const oldIdx = this.chunks.indexOf(chunk);
|
142 | if (oldIdx > 0) {
|
143 | this.chunks.splice(oldIdx, 1);
|
144 | this.chunks.unshift(chunk);
|
145 | } else if (oldIdx < 0) {
|
146 | this.chunks.unshift(chunk);
|
147 | return true;
|
148 | }
|
149 | return false;
|
150 | }
|
151 |
|
152 | |
153 |
|
154 |
|
155 |
|
156 |
|
157 |
|
158 | insertChunk(chunk, before) {
|
159 | const oldIdx = this.chunks.indexOf(chunk);
|
160 | const idx = this.chunks.indexOf(before);
|
161 | if (idx < 0) {
|
162 | throw new Error("before chunk not found");
|
163 | }
|
164 | if (oldIdx >= 0 && oldIdx > idx) {
|
165 | this.chunks.splice(oldIdx, 1);
|
166 | this.chunks.splice(idx, 0, chunk);
|
167 | } else if (oldIdx < 0) {
|
168 | this.chunks.splice(idx, 0, chunk);
|
169 | return true;
|
170 | }
|
171 | return false;
|
172 | }
|
173 |
|
174 | |
175 |
|
176 |
|
177 |
|
178 |
|
179 | pushChunk(chunk) {
|
180 | const oldIdx = this.chunks.indexOf(chunk);
|
181 | if (oldIdx >= 0) {
|
182 | return false;
|
183 | }
|
184 | this.chunks.push(chunk);
|
185 | return true;
|
186 | }
|
187 |
|
188 | |
189 |
|
190 |
|
191 |
|
192 |
|
193 | replaceChunk(oldChunk, newChunk) {
|
194 | const oldIdx = this.chunks.indexOf(oldChunk);
|
195 | if (oldIdx < 0) return false;
|
196 | const newIdx = this.chunks.indexOf(newChunk);
|
197 | if (newIdx < 0) {
|
198 | this.chunks[oldIdx] = newChunk;
|
199 | return true;
|
200 | }
|
201 | if (newIdx < oldIdx) {
|
202 | this.chunks.splice(oldIdx, 1);
|
203 | return true;
|
204 | } else if (newIdx !== oldIdx) {
|
205 | this.chunks[oldIdx] = newChunk;
|
206 | this.chunks.splice(newIdx, 1);
|
207 | return true;
|
208 | }
|
209 | }
|
210 |
|
211 | removeChunk(chunk) {
|
212 | const idx = this.chunks.indexOf(chunk);
|
213 | if (idx >= 0) {
|
214 | this.chunks.splice(idx, 1);
|
215 | return true;
|
216 | }
|
217 | return false;
|
218 | }
|
219 |
|
220 | isInitial() {
|
221 | return false;
|
222 | }
|
223 |
|
224 | addChild(chunk) {
|
225 | if (this._children.has(chunk)) {
|
226 | return false;
|
227 | }
|
228 | this._children.add(chunk);
|
229 | return true;
|
230 | }
|
231 |
|
232 | getChildren() {
|
233 | return this._children.getFromCache(getArray);
|
234 | }
|
235 |
|
236 | getNumberOfChildren() {
|
237 | return this._children.size;
|
238 | }
|
239 |
|
240 | get childrenIterable() {
|
241 | return this._children;
|
242 | }
|
243 |
|
244 | removeChild(chunk) {
|
245 | if (!this._children.has(chunk)) {
|
246 | return false;
|
247 | }
|
248 |
|
249 | this._children.delete(chunk);
|
250 | chunk.removeParent(this);
|
251 | return true;
|
252 | }
|
253 |
|
254 | addParent(parentChunk) {
|
255 | if (!this._parents.has(parentChunk)) {
|
256 | this._parents.add(parentChunk);
|
257 | return true;
|
258 | }
|
259 | return false;
|
260 | }
|
261 |
|
262 | getParents() {
|
263 | return this._parents.getFromCache(getArray);
|
264 | }
|
265 |
|
266 | setParents(newParents) {
|
267 | this._parents.clear();
|
268 | for (const p of newParents) {
|
269 | this._parents.add(p);
|
270 | }
|
271 | }
|
272 |
|
273 | getNumberOfParents() {
|
274 | return this._parents.size;
|
275 | }
|
276 |
|
277 | hasParent(parent) {
|
278 | return this._parents.has(parent);
|
279 | }
|
280 |
|
281 | get parentsIterable() {
|
282 | return this._parents;
|
283 | }
|
284 |
|
285 | removeParent(chunk) {
|
286 | if (this._parents.delete(chunk)) {
|
287 | chunk.removeChunk(this);
|
288 | return true;
|
289 | }
|
290 | return false;
|
291 | }
|
292 |
|
293 | |
294 |
|
295 |
|
296 | getBlocks() {
|
297 | return this._blocks.getFromCache(getArray);
|
298 | }
|
299 |
|
300 | getNumberOfBlocks() {
|
301 | return this._blocks.size;
|
302 | }
|
303 |
|
304 | hasBlock(block) {
|
305 | return this._blocks.has(block);
|
306 | }
|
307 |
|
308 | get blocksIterable() {
|
309 | return this._blocks;
|
310 | }
|
311 |
|
312 | addBlock(block) {
|
313 | if (!this._blocks.has(block)) {
|
314 | this._blocks.add(block);
|
315 | return true;
|
316 | }
|
317 | return false;
|
318 | }
|
319 |
|
320 | addOrigin(module, loc, request) {
|
321 | this.origins.push({
|
322 | module,
|
323 | loc,
|
324 | request
|
325 | });
|
326 | }
|
327 |
|
328 | containsModule(module) {
|
329 | for (const chunk of this.chunks) {
|
330 | if (chunk.containsModule(module)) return true;
|
331 | }
|
332 | return false;
|
333 | }
|
334 |
|
335 | getFiles() {
|
336 | const files = new Set();
|
337 |
|
338 | for (const chunk of this.chunks) {
|
339 | for (const file of chunk.files) {
|
340 | files.add(file);
|
341 | }
|
342 | }
|
343 |
|
344 | return Array.from(files);
|
345 | }
|
346 |
|
347 | |
348 |
|
349 |
|
350 |
|
351 | remove(reason) {
|
352 |
|
353 | for (const parentChunkGroup of this._parents) {
|
354 |
|
355 | parentChunkGroup._children.delete(this);
|
356 |
|
357 |
|
358 | for (const chunkGroup of this._children) {
|
359 | |
360 |
|
361 |
|
362 |
|
363 |
|
364 | chunkGroup.addParent(parentChunkGroup);
|
365 |
|
366 | parentChunkGroup.addChild(chunkGroup);
|
367 | }
|
368 | }
|
369 |
|
370 | |
371 |
|
372 |
|
373 |
|
374 |
|
375 |
|
376 | for (const chunkGroup of this._children) {
|
377 |
|
378 | chunkGroup._parents.delete(this);
|
379 | }
|
380 |
|
381 |
|
382 | for (const block of this._blocks) {
|
383 | block.chunkGroup = null;
|
384 | }
|
385 |
|
386 |
|
387 | for (const chunk of this.chunks) {
|
388 | chunk.removeGroup(this);
|
389 | }
|
390 | }
|
391 |
|
392 | sortItems() {
|
393 | this.origins.sort(sortOrigin);
|
394 | this._parents.sort();
|
395 | this._children.sort();
|
396 | }
|
397 |
|
398 | |
399 |
|
400 |
|
401 |
|
402 |
|
403 |
|
404 |
|
405 | compareTo(otherGroup) {
|
406 | if (this.chunks.length > otherGroup.chunks.length) return -1;
|
407 | if (this.chunks.length < otherGroup.chunks.length) return 1;
|
408 | const a = this.chunks[Symbol.iterator]();
|
409 | const b = otherGroup.chunks[Symbol.iterator]();
|
410 |
|
411 | while (true) {
|
412 | const aItem = a.next();
|
413 | const bItem = b.next();
|
414 | if (aItem.done) return 0;
|
415 | const cmp = aItem.value.compareTo(bItem.value);
|
416 | if (cmp !== 0) return cmp;
|
417 | }
|
418 | }
|
419 |
|
420 | getChildrenByOrders() {
|
421 | const lists = new Map();
|
422 | for (const childGroup of this._children) {
|
423 |
|
424 | if (typeof childGroup.options === "object") {
|
425 | for (const key of Object.keys(childGroup.options)) {
|
426 | if (key.endsWith("Order")) {
|
427 | const name = key.substr(0, key.length - "Order".length);
|
428 | let list = lists.get(name);
|
429 | if (list === undefined) {
|
430 | lists.set(name, (list = []));
|
431 | }
|
432 | list.push({
|
433 | order: childGroup.options[key],
|
434 | group: childGroup
|
435 | });
|
436 | }
|
437 | }
|
438 | }
|
439 | }
|
440 | const result = Object.create(null);
|
441 | for (const [name, list] of lists) {
|
442 | list.sort((a, b) => {
|
443 | const cmp = b.order - a.order;
|
444 | if (cmp !== 0) return cmp;
|
445 |
|
446 | if (a.group.compareTo) {
|
447 | return a.group.compareTo(b.group);
|
448 | }
|
449 | return 0;
|
450 | });
|
451 | result[name] = list.map(i => i.group);
|
452 | }
|
453 | return result;
|
454 | }
|
455 |
|
456 | |
457 |
|
458 |
|
459 |
|
460 |
|
461 |
|
462 | setModuleIndex(module, index) {
|
463 | this._moduleIndices.set(module, index);
|
464 | }
|
465 |
|
466 | |
467 |
|
468 |
|
469 |
|
470 |
|
471 | getModuleIndex(module) {
|
472 | return this._moduleIndices.get(module);
|
473 | }
|
474 |
|
475 | |
476 |
|
477 |
|
478 |
|
479 |
|
480 |
|
481 | setModuleIndex2(module, index) {
|
482 | this._moduleIndices2.set(module, index);
|
483 | }
|
484 |
|
485 | |
486 |
|
487 |
|
488 |
|
489 |
|
490 | getModuleIndex2(module) {
|
491 | return this._moduleIndices2.get(module);
|
492 | }
|
493 |
|
494 | checkConstraints() {
|
495 | const chunk = this;
|
496 | for (const child of chunk._children) {
|
497 | if (!child._parents.has(chunk)) {
|
498 | throw new Error(
|
499 | `checkConstraints: child missing parent ${chunk.debugId} -> ${child.debugId}`
|
500 | );
|
501 | }
|
502 | }
|
503 | for (const parentChunk of chunk._parents) {
|
504 | if (!parentChunk._children.has(chunk)) {
|
505 | throw new Error(
|
506 | `checkConstraints: parent missing child ${parentChunk.debugId} <- ${chunk.debugId}`
|
507 | );
|
508 | }
|
509 | }
|
510 | }
|
511 | }
|
512 |
|
513 | module.exports = ChunkGroup;
|