You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
		
			
		
			
				
					
					
						
							175 lines
						
					
					
						
							4.0 KiB
						
					
					
				
			
		
		
		
			
			
			
				
					
				
				
					
				
			
		
		
	
	
							175 lines
						
					
					
						
							4.0 KiB
						
					
					
				
								/*
							 | 
						|
									MIT License http://www.opensource.org/licenses/mit-license.php
							 | 
						|
									Author Tobias Koppers @sokra
							 | 
						|
								*/
							 | 
						|
								"use strict";
							 | 
						|
								
							 | 
						|
								const util = require("util");
							 | 
						|
								
							 | 
						|
								const deprecateContext = util.deprecate(() => {},
							 | 
						|
								"Hook.context is deprecated and will be removed");
							 | 
						|
								
							 | 
						|
								const CALL_DELEGATE = function(...args) {
							 | 
						|
									this.call = this._createCall("sync");
							 | 
						|
									return this.call(...args);
							 | 
						|
								};
							 | 
						|
								const CALL_ASYNC_DELEGATE = function(...args) {
							 | 
						|
									this.callAsync = this._createCall("async");
							 | 
						|
									return this.callAsync(...args);
							 | 
						|
								};
							 | 
						|
								const PROMISE_DELEGATE = function(...args) {
							 | 
						|
									this.promise = this._createCall("promise");
							 | 
						|
									return this.promise(...args);
							 | 
						|
								};
							 | 
						|
								
							 | 
						|
								class Hook {
							 | 
						|
									constructor(args = [], name = undefined) {
							 | 
						|
										this._args = args;
							 | 
						|
										this.name = name;
							 | 
						|
										this.taps = [];
							 | 
						|
										this.interceptors = [];
							 | 
						|
										this._call = CALL_DELEGATE;
							 | 
						|
										this.call = CALL_DELEGATE;
							 | 
						|
										this._callAsync = CALL_ASYNC_DELEGATE;
							 | 
						|
										this.callAsync = CALL_ASYNC_DELEGATE;
							 | 
						|
										this._promise = PROMISE_DELEGATE;
							 | 
						|
										this.promise = PROMISE_DELEGATE;
							 | 
						|
										this._x = undefined;
							 | 
						|
								
							 | 
						|
										this.compile = this.compile;
							 | 
						|
										this.tap = this.tap;
							 | 
						|
										this.tapAsync = this.tapAsync;
							 | 
						|
										this.tapPromise = this.tapPromise;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									compile(options) {
							 | 
						|
										throw new Error("Abstract: should be overridden");
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									_createCall(type) {
							 | 
						|
										return this.compile({
							 | 
						|
											taps: this.taps,
							 | 
						|
											interceptors: this.interceptors,
							 | 
						|
											args: this._args,
							 | 
						|
											type: type
							 | 
						|
										});
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									_tap(type, options, fn) {
							 | 
						|
										if (typeof options === "string") {
							 | 
						|
											options = {
							 | 
						|
												name: options.trim()
							 | 
						|
											};
							 | 
						|
										} else if (typeof options !== "object" || options === null) {
							 | 
						|
											throw new Error("Invalid tap options");
							 | 
						|
										}
							 | 
						|
										if (typeof options.name !== "string" || options.name === "") {
							 | 
						|
											throw new Error("Missing name for tap");
							 | 
						|
										}
							 | 
						|
										if (typeof options.context !== "undefined") {
							 | 
						|
											deprecateContext();
							 | 
						|
										}
							 | 
						|
										options = Object.assign({ type, fn }, options);
							 | 
						|
										options = this._runRegisterInterceptors(options);
							 | 
						|
										this._insert(options);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									tap(options, fn) {
							 | 
						|
										this._tap("sync", options, fn);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									tapAsync(options, fn) {
							 | 
						|
										this._tap("async", options, fn);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									tapPromise(options, fn) {
							 | 
						|
										this._tap("promise", options, fn);
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									_runRegisterInterceptors(options) {
							 | 
						|
										for (const interceptor of this.interceptors) {
							 | 
						|
											if (interceptor.register) {
							 | 
						|
												const newOptions = interceptor.register(options);
							 | 
						|
												if (newOptions !== undefined) {
							 | 
						|
													options = newOptions;
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
										return options;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									withOptions(options) {
							 | 
						|
										const mergeOptions = opt =>
							 | 
						|
											Object.assign({}, options, typeof opt === "string" ? { name: opt } : opt);
							 | 
						|
								
							 | 
						|
										return {
							 | 
						|
											name: this.name,
							 | 
						|
											tap: (opt, fn) => this.tap(mergeOptions(opt), fn),
							 | 
						|
											tapAsync: (opt, fn) => this.tapAsync(mergeOptions(opt), fn),
							 | 
						|
											tapPromise: (opt, fn) => this.tapPromise(mergeOptions(opt), fn),
							 | 
						|
											intercept: interceptor => this.intercept(interceptor),
							 | 
						|
											isUsed: () => this.isUsed(),
							 | 
						|
											withOptions: opt => this.withOptions(mergeOptions(opt))
							 | 
						|
										};
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									isUsed() {
							 | 
						|
										return this.taps.length > 0 || this.interceptors.length > 0;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									intercept(interceptor) {
							 | 
						|
										this._resetCompilation();
							 | 
						|
										this.interceptors.push(Object.assign({}, interceptor));
							 | 
						|
										if (interceptor.register) {
							 | 
						|
											for (let i = 0; i < this.taps.length; i++) {
							 | 
						|
												this.taps[i] = interceptor.register(this.taps[i]);
							 | 
						|
											}
							 | 
						|
										}
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									_resetCompilation() {
							 | 
						|
										this.call = this._call;
							 | 
						|
										this.callAsync = this._callAsync;
							 | 
						|
										this.promise = this._promise;
							 | 
						|
									}
							 | 
						|
								
							 | 
						|
									_insert(item) {
							 | 
						|
										this._resetCompilation();
							 | 
						|
										let before;
							 | 
						|
										if (typeof item.before === "string") {
							 | 
						|
											before = new Set([item.before]);
							 | 
						|
										} else if (Array.isArray(item.before)) {
							 | 
						|
											before = new Set(item.before);
							 | 
						|
										}
							 | 
						|
										let stage = 0;
							 | 
						|
										if (typeof item.stage === "number") {
							 | 
						|
											stage = item.stage;
							 | 
						|
										}
							 | 
						|
										let i = this.taps.length;
							 | 
						|
										while (i > 0) {
							 | 
						|
											i--;
							 | 
						|
											const x = this.taps[i];
							 | 
						|
											this.taps[i + 1] = x;
							 | 
						|
											const xStage = x.stage || 0;
							 | 
						|
											if (before) {
							 | 
						|
												if (before.has(x.name)) {
							 | 
						|
													before.delete(x.name);
							 | 
						|
													continue;
							 | 
						|
												}
							 | 
						|
												if (before.size > 0) {
							 | 
						|
													continue;
							 | 
						|
												}
							 | 
						|
											}
							 | 
						|
											if (xStage > stage) {
							 | 
						|
												continue;
							 | 
						|
											}
							 | 
						|
											i++;
							 | 
						|
											break;
							 | 
						|
										}
							 | 
						|
										this.taps[i] = item;
							 | 
						|
									}
							 | 
						|
								}
							 | 
						|
								
							 | 
						|
								Object.setPrototypeOf(Hook.prototype, null);
							 | 
						|
								
							 | 
						|
								module.exports = Hook;
							 |