| /* |
| MIT License http://www.opensource.org/licenses/mit-license.php |
| Author Tobias Koppers @sokra |
| */ |
| "use strict"; |
| |
| class Hook { |
| constructor(args) { |
| if (!Array.isArray(args)) args = []; |
| this._args = args; |
| this.taps = []; |
| this.interceptors = []; |
| this.call = this._call; |
| this.promise = this._promise; |
| this.callAsync = this._callAsync; |
| this._x = undefined; |
| } |
| |
| compile(options) { |
| throw new Error("Abstract: should be overriden"); |
| } |
| |
| _createCall(type) { |
| return this.compile({ |
| taps: this.taps, |
| interceptors: this.interceptors, |
| args: this._args, |
| type: type |
| }); |
| } |
| |
| tap(options, fn) { |
| if (typeof options === "string") options = { name: options }; |
| if (typeof options !== "object" || options === null) |
| throw new Error( |
| "Invalid arguments to tap(options: Object, fn: function)" |
| ); |
| options = Object.assign({ type: "sync", fn: fn }, options); |
| if (typeof options.name !== "string" || options.name === "") |
| throw new Error("Missing name for tap"); |
| options = this._runRegisterInterceptors(options); |
| this._insert(options); |
| } |
| |
| tapAsync(options, fn) { |
| if (typeof options === "string") options = { name: options }; |
| if (typeof options !== "object" || options === null) |
| throw new Error( |
| "Invalid arguments to tapAsync(options: Object, fn: function)" |
| ); |
| options = Object.assign({ type: "async", fn: fn }, options); |
| if (typeof options.name !== "string" || options.name === "") |
| throw new Error("Missing name for tapAsync"); |
| options = this._runRegisterInterceptors(options); |
| this._insert(options); |
| } |
| |
| tapPromise(options, fn) { |
| if (typeof options === "string") options = { name: options }; |
| if (typeof options !== "object" || options === null) |
| throw new Error( |
| "Invalid arguments to tapPromise(options: Object, fn: function)" |
| ); |
| options = Object.assign({ type: "promise", fn: fn }, options); |
| if (typeof options.name !== "string" || options.name === "") |
| throw new Error("Missing name for tapPromise"); |
| options = this._runRegisterInterceptors(options); |
| this._insert(options); |
| } |
| |
| _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); |
| |
| // Prevent creating endless prototype chains |
| options = Object.assign({}, options, this._withOptions); |
| const base = this._withOptionsBase || this; |
| const newHook = Object.create(base); |
| |
| (newHook.tapAsync = (opt, fn) => base.tapAsync(mergeOptions(opt), fn)), |
| (newHook.tap = (opt, fn) => base.tap(mergeOptions(opt), fn)); |
| newHook.tapPromise = (opt, fn) => base.tapPromise(mergeOptions(opt), fn); |
| newHook._withOptions = options; |
| newHook._withOptionsBase = base; |
| return newHook; |
| } |
| |
| 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; |
| } |
| } |
| |
| function createCompileDelegate(name, type) { |
| return function lazyCompileHook(...args) { |
| this[name] = this._createCall(type); |
| return this[name](...args); |
| }; |
| } |
| |
| Object.defineProperties(Hook.prototype, { |
| _call: { |
| value: createCompileDelegate("call", "sync"), |
| configurable: true, |
| writable: true |
| }, |
| _promise: { |
| value: createCompileDelegate("promise", "promise"), |
| configurable: true, |
| writable: true |
| }, |
| _callAsync: { |
| value: createCompileDelegate("callAsync", "async"), |
| configurable: true, |
| writable: true |
| } |
| }); |
| |
| module.exports = Hook; |