| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | /* | 
					
						
							|  |  |  | 	MIT License http://www.opensource.org/licenses/mit-license.php
 | 
					
						
							|  |  |  | 	Author Tobias Koppers @sokra | 
					
						
							|  |  |  | */ | 
					
						
							|  |  |  | "use strict"; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const SortableSet = require("./util/SortableSet"); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | const compareLocations = require("./compareLocations"); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | let debugId = 5000; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | const getArray = set => Array.from(set); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | const sortById = (a, b) => { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	if (a.id < b.id) return -1; | 
					
						
							|  |  |  | 	if (b.id < a.id) return 1; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 18:28:45 +08:00
										 |  |  | const sortOrigin = (a, b) => { | 
					
						
							|  |  |  | 	const aIdent = a.module ? a.module.identifier() : ""; | 
					
						
							|  |  |  | 	const bIdent = b.module ? b.module.identifier() : ""; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 	if (aIdent < bIdent) return -1; | 
					
						
							|  |  |  | 	if (aIdent > bIdent) return 1; | 
					
						
							| 
									
										
										
										
											2018-01-20 18:28:45 +08:00
										 |  |  | 	return compareLocations(a.loc, b.loc); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | class ChunkGroup { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	constructor(name) { | 
					
						
							|  |  |  | 		this.groupDebugId = debugId++; | 
					
						
							|  |  |  | 		this.name = name; | 
					
						
							|  |  |  | 		this._children = new SortableSet(undefined, sortById); | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 		this._parents = new SortableSet(undefined, sortById); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		this._blocks = new SortableSet(); | 
					
						
							|  |  |  | 		this.chunks = []; | 
					
						
							|  |  |  | 		this.origins = []; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-21 18:12:36 +08:00
										 |  |  | 	/* istanbul ignore next */ | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	get debugId() { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		return Array.from(this.chunks, x => x.debugId).join("+"); | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get id() { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		return Array.from(this.chunks, x => x.id).join("+"); | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	unshiftChunk(chunk) { | 
					
						
							|  |  |  | 		const oldIdx = this.chunks.indexOf(chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (oldIdx > 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(oldIdx, 1); | 
					
						
							|  |  |  | 			this.chunks.unshift(chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if (oldIdx < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.unshift(chunk); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	insertChunk(chunk, before) { | 
					
						
							|  |  |  | 		const oldIdx = this.chunks.indexOf(chunk); | 
					
						
							|  |  |  | 		const idx = this.chunks.indexOf(before); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (idx < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			throw new Error("before chunk not found"); | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (oldIdx >= 0 && oldIdx > idx) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(oldIdx, 1); | 
					
						
							|  |  |  | 			this.chunks.splice(idx, 0, chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if (oldIdx < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(idx, 0, chunk); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	pushChunk(chunk) { | 
					
						
							|  |  |  | 		const oldIdx = this.chunks.indexOf(chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (oldIdx >= 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		this.chunks.push(chunk); | 
					
						
							|  |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	replaceChunk(oldChunk, newChunk) { | 
					
						
							|  |  |  | 		const oldIdx = this.chunks.indexOf(oldChunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (oldIdx < 0) return false; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		const newIdx = this.chunks.indexOf(newChunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (newIdx < 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 18:28:45 +08:00
										 |  |  | 			this.chunks[oldIdx] = newChunk; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (newIdx < oldIdx) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(oldIdx, 1); | 
					
						
							|  |  |  | 			return true; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		} else if (newIdx !== oldIdx) { | 
					
						
							| 
									
										
										
										
											2018-01-20 18:28:45 +08:00
										 |  |  | 			this.chunks[oldIdx] = newChunk; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(newIdx, 1); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	removeChunk(chunk) { | 
					
						
							|  |  |  | 		const idx = this.chunks.indexOf(chunk); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (idx >= 0) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this.chunks.splice(idx, 1); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	isInitial() { | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	addChild(chunk) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this._children.has(chunk)) { | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		this._children.add(chunk); | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 		return true; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	getChildren() { | 
					
						
							|  |  |  | 		return this._children.getFromCache(getArray); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getNumberOfChildren() { | 
					
						
							|  |  |  | 		return this._children.size; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	get childrenIterable() { | 
					
						
							|  |  |  | 		return this._children; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	removeChild(chunk) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (!this._children.has(chunk)) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			return false; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		this._children.delete(chunk); | 
					
						
							|  |  |  | 		chunk.removeParent(this); | 
					
						
							|  |  |  | 		return true; | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	addParent(parentChunk) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (!this._parents.has(parentChunk)) { | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 			this._parents.add(parentChunk); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getParents() { | 
					
						
							|  |  |  | 		return this._parents.getFromCache(getArray); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	setParents(newParents) { | 
					
						
							|  |  |  | 		this._parents.clear(); | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const p of newParents) this._parents.add(p); | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getNumberOfParents() { | 
					
						
							|  |  |  | 		return this._parents.size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hasParent(parent) { | 
					
						
							|  |  |  | 		return this._parents.has(parent); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get parentsIterable() { | 
					
						
							|  |  |  | 		return this._parents; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 	removeParent(chunk) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (this._parents.delete(chunk)) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			chunk.removeChunk(this); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	/** | 
					
						
							|  |  |  | 	 * @return {Array} - an array containing the blocks | 
					
						
							|  |  |  | 	 */ | 
					
						
							|  |  |  | 	getBlocks() { | 
					
						
							|  |  |  | 		return this._blocks.getFromCache(getArray); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	getNumberOfBlocks() { | 
					
						
							|  |  |  | 		return this._blocks.size; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	hasBlock(block) { | 
					
						
							|  |  |  | 		return this._blocks.has(block); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	get blocksIterable() { | 
					
						
							|  |  |  | 		return this._blocks; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	addBlock(block) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		if (!this._blocks.has(block)) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			this._blocks.add(block); | 
					
						
							|  |  |  | 			return true; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	addOrigin(module, loc, request) { | 
					
						
							|  |  |  | 		this.origins.push({ | 
					
						
							|  |  |  | 			module, | 
					
						
							|  |  |  | 			loc, | 
					
						
							|  |  |  | 			request | 
					
						
							|  |  |  | 		}); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	containsModule(module) { | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const chunk of this.chunks) { | 
					
						
							|  |  |  | 			if (chunk.containsModule(module)) return true; | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		return false; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	remove(reason) { | 
					
						
							|  |  |  | 		// cleanup parents
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const parentChunkGroup of this._parents) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			// remove this chunk from its parents
 | 
					
						
							|  |  |  | 			parentChunkGroup._children.delete(this); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			// cleanup "sub chunks"
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 			for (const chunkGroup of this._children) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 				/** | 
					
						
							|  |  |  | 				 * remove this chunk as "intermediary" and connect | 
					
						
							|  |  |  | 				 * it "sub chunks" and parents directly | 
					
						
							|  |  |  | 				 */ | 
					
						
							|  |  |  | 				// add parent to each "sub chunk"
 | 
					
						
							|  |  |  | 				chunkGroup.addParent(parentChunkGroup); | 
					
						
							|  |  |  | 				// add "sub chunk" to parent
 | 
					
						
							|  |  |  | 				parentChunkGroup.addChild(chunkGroup); | 
					
						
							| 
									
										
										
										
											2018-01-22 20:52:43 +08:00
										 |  |  | 			} | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		/** | 
					
						
							|  |  |  | 		 * we need to iterate again over the children | 
					
						
							|  |  |  | 		 * to remove this from the childs parents. | 
					
						
							|  |  |  | 		 * This can not be done in the above loop | 
					
						
							| 
									
										
										
										
											2018-02-26 10:30:35 +08:00
										 |  |  | 		 * as it is not guaranteed that `this._parents` contains anything. | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		 */ | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const chunkGroup of this._children) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			// remove this as parent of every "sub chunk"
 | 
					
						
							|  |  |  | 			chunkGroup._parents.delete(this); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// cleanup blocks
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const block of this._blocks) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			block.chunkGroup = null; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 		// remove chunks
 | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const chunk of this.chunks) { | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 			chunk.removeGroup(this); | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	sortItems() { | 
					
						
							| 
									
										
										
										
											2018-01-20 18:28:45 +08:00
										 |  |  | 		this.origins.sort(sortOrigin); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		this._parents.sort(); | 
					
						
							|  |  |  | 		this._children.sort(); | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	checkConstraints() { | 
					
						
							|  |  |  | 		const chunk = this; | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const child of chunk._children) { | 
					
						
							|  |  |  | 			if (!child._parents.has(chunk)) | 
					
						
							|  |  |  | 				throw new Error( | 
					
						
							|  |  |  | 					`checkConstraints: child missing parent ${chunk.debugId} -> ${ | 
					
						
							|  |  |  | 						child.debugId | 
					
						
							|  |  |  | 					}`
 | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2018-02-25 09:00:20 +08:00
										 |  |  | 		for (const parentChunk of chunk._parents) { | 
					
						
							|  |  |  | 			if (!parentChunk._children.has(chunk)) | 
					
						
							|  |  |  | 				throw new Error( | 
					
						
							|  |  |  | 					`checkConstraints: parent missing child ${parentChunk.debugId} <- ${ | 
					
						
							|  |  |  | 						chunk.debugId | 
					
						
							|  |  |  | 					}`
 | 
					
						
							|  |  |  | 				); | 
					
						
							| 
									
										
										
										
											2018-01-20 00:06:59 +08:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2018-01-10 05:39:16 +08:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | module.exports = ChunkGroup; |