UNPKG

libcore

Version:

Kicks-start helpers for cross-browser libraries and different versions of nodejs

301 lines (221 loc) 6.14 kB
'use strict'; import { string, method, iterable } from "./type.js"; import { getModule } from "./chain.js"; var G = global, // 1 = namespace, 4 = position, 5 = item NAME_RE = /^(([^\.]+\.)*)((before|after)\:)?([a-zA-Z0-9\_\-\.]+)$/, POSITION_BEFORE = 1, POSITION_AFTER = 2, RUNNERS = {}, NAMESPACES = {}, INVALID_NAME = 'Invalid [name] parameter.', INVALID_HANDLER = 'Invalid [handler] parameter.', NATIVE_SET_IMMEDIATE = !!G.setImmediate, setAsync = NATIVE_SET_IMMEDIATE ? nativeSetImmediate : timeoutAsync, clearAsync = NATIVE_SET_IMMEDIATE ? nativeClearImmediate : clearTimeoutAsync; function empty() { } function get(name) { var info = getRunners(name); if (info) { return info[0][info[1]]; } return void(0); } function getRunners(name) { var list = RUNNERS, parsed = parseName(name); var access, position; if (parsed) { access = ':' + parsed[1]; if (access in list) { position = parsed[0]; return [list[access], getPositionAccess(position), position]; } } return void(0); } function purgeRunners(name, after) { var info = getRunners(name); var runners, access; if (info) { access = info[1]; switch (after) { case true: access = 'after'; break; case false: access = 'before'; break; case null: case undefined: access = false; } if (!access || access === 'before') { runners = info[0].before; runners.splice(0, runners.length); } if (!access || access === 'after') { runners = info[0].after; runners.splice(0, runners.length); } } return getModule(); } function getPositionAccess(input) { return input === POSITION_BEFORE ? 'before' : 'after'; } function parseName(name) { var match = string(name) && name.match(NAME_RE); var position, namespace; if (match) { namespace = match[1]; position = match[4] === 'before' ? POSITION_BEFORE : POSITION_AFTER; return [position, (namespace || '') + match[5]]; } return void(0); } function timeoutAsync(handler) { if (!method(handler)) { throw new Error(INVALID_HANDLER); } return G.setTimeout(handler, 1); } function clearTimeoutAsync(id) { try { G.clearTimeout(id); } catch (e) {} return getModule(); } function nativeSetImmediate (handler) { if (!method(handler)) { throw new Error(INVALID_HANDLER); } return G.setImmediate(handler); } function nativeClearImmediate(id) { try { G.clearImmediate(id); } catch (e) {} return getModule(); } function BaseMiddleware() { } BaseMiddleware.prototype = { constructor: BaseMiddleware, run: function (name, args, scope) { return run(this.access + name, args, scope); }, register: function (name, handler) { register(this.access + name, handler); return this; }, clear: function (name, after) { var access = this.access; if (!string(name)) { throw new Error(INVALID_NAME); } if (arguments.length > 1) { purgeRunners(access + name, after); } else { purgeRunners(access + name); } return this; } }; export { setAsync, clearAsync }; export function run(name, args, scope) { var c, l, runners, result; if (!string(name)) { throw new Error(INVALID_NAME); } runners = get(name); if (runners) { if (typeof scope === 'undefined') { scope = null; } args = iterable(args) ? Array.prototype.slice.call(args, 0) : []; for (c = -1, l = runners.length; l--;) { result = runners[++c].apply(scope, args); if (result !== undefined) { args = [result]; } } args.splice(0, args.length); return result; } return undefined; } export function register(name, handler) { var list = RUNNERS; var access, items, parsed; if (!string(name)) { throw new Error(INVALID_NAME); } parsed = parseName(name); if (!method(handler)) { throw new Error(INVALID_HANDLER); } if (parsed) { name = parsed[1]; access = ':' + name; if (!(access in list)) { list[access] = { name: name, before: [], after: [] }; } items = list[access][getPositionAccess(parsed[0])]; items[items.length] = handler; } return getModule(); } export function clearRunner(name, after) { if (!string(name)) { throw new Error(INVALID_NAME); } if (arguments.length > 1) { purgeRunners(name, after); } else { purgeRunners(name); } return getModule(); } export function middleware(name) { var list = NAMESPACES; var access, registered, proto; function Middleware() { BaseMiddleware.apply(this, arguments); } if (!string(name)) { throw new Error(INVALID_NAME); } access = name + '.'; if (!(access in list)) { empty.prototype = BaseMiddleware.prototype; proto = new empty(access); proto.constructor = Middleware; proto.access = access; Middleware.prototype = proto; list[access] = registered = new Middleware(); return registered; } return list[access]; }