@appolo/inject
Version:
dependency injection for node js
242 lines (168 loc) • 6.58 kB
text/typescript
import {InjectDefineSymbol} from "../decorators/decorators";
import {Define} from "../define/define";
export class Util {
public static getClassName(fn: Function): string {
return fn.name.charAt(0).toLowerCase() + fn.name.slice(1)
}
public static isUndefined(value: any): boolean {
return typeof value === 'undefined'
}
public static isObject(val: any): boolean {
if (val === null) {
return false;
}
return ((typeof val === 'function') || (typeof val === 'object'));
}
public static isFunction(obj: any): boolean {
return !!(obj && obj.constructor && obj.call && obj.apply);
};
public static getClassNameOrId(objectId: string | Function): string {
if (Util.isFunction(objectId)) {
objectId = Util.getClassName(objectId as Function);
}
return objectId as string;
}
public static isClass(v: any): boolean {
return typeof v === 'function' && v.name && /^\s*class\s+/.test(v.toString());
}
public static getClassDefinition(fn: any): Define {
return Util.getReflectData<Define>(InjectDefineSymbol, fn)
}
public static isString(str: any): boolean {
return (typeof str === 'string' || str instanceof String);
}
public static keyBy<T extends object>(arr: T[], key: string | ((item: T, index: number) => string)) {
let output: { [index: string]: T } = {};
for (let i = 0, len = (arr || []).length; i < len; i++) {
let item: any = arr[i];
let outputKey = Util.isFunction(key) ? (key as Function)(item, i) : item[key as string];
output[outputKey] = item;
}
return output;
}
public static keyByMap<T extends object, K extends any = string>(arr: T[], key: string | ((item: T, index: number) => string)): Map<K, T> {
let output = new Map<K, T>()
for (let i = 0, len = (arr || []).length; i < len; i++) {
let item: any = arr[i];
let outputKey = Util.isFunction(key) ? (key as Function)(item, i) : item[key as string];
output.set(outputKey, item)
}
return output;
}
public static removeFromArray<T>(list: T[], item: T): void {
if (!list || !list.length) {
return;
}
for (let i = list.length - 1; i >= 0; i--) {
if (list[i] === item) {
list.splice(i, 1);
}
}
}
public static groupByArray<T>(arr: T[], key: string | number | ((item: T) => string | number)): {
[index: string]: T[]
} {
let output: { [index: string]: T[] } = {};
for (let i = 0, len = arr.length; i < len; i++) {
let item = arr[i],
value = (typeof key === "function") ? key(item) : item[key],
dto = output[value] || (output[value] = []);
dto.push(item);
}
return output;
}
public static getClassId(fn: any): string {
if (!fn) {
return null;
}
if (Util.isString(fn)) {
return fn
}
let define = Util.getClassDefinition(fn);
if (define) {
return define.definition.id;
}
if (Util.isClass(fn)) {
return Util.getClassName(fn);
}
return null;
}
public static getFunctionArgs(func: (...args: any[]) => any): string[] {
const STRIP_COMMENTS = /((\/\/.*$)|(\/\*[\s\S]*?\*\/))/mg;
const ARGUMENT_NAMES = /([^\s,]+)/g;
let fnStr = func.toString().replace(STRIP_COMMENTS, '');
let args: string[] = fnStr.slice(fnStr.indexOf('(') + 1, fnStr.indexOf(')')).match(ARGUMENT_NAMES);
if (args === null) {
args = [];
}
args = Util.compactArray(args);
return args;
}
public static compactArray<T>(array: T[]): T[] {
let index = -1,
length = array == null ? 0 : array.length,
resIndex = 0,
result = [];
while (++index < length) {
let value = array[index];
if (value) {
result[resIndex++] = value;
}
}
return result;
}
public static getReflectData<T>(symbol: Symbol | string, klass, defaultValue?: T): T {
let value = Reflect.getOwnMetadata(symbol, klass);
if (!value && Reflect.hasMetadata(symbol, klass)) {
value = Util.cloneDeep(Reflect.getMetadata(symbol, klass));
Reflect.defineMetadata(symbol, value, klass);
}
if (!value && defaultValue != undefined) {
value = defaultValue;
Reflect.defineMetadata(symbol, value, klass);
}
return value
}
public static cloneDeep<T>(obj: T): T {
if (!obj) {
return;
}
let output = Array.isArray(obj) ? [] : {};
let keys = Object.keys(obj);
for (let i = 0, len = keys.length; i < len; i++) {
let key = keys[i], value = obj[key];
output[key] = (value == null || typeof value != "object") ? value : Util.cloneDeep(value)
}
return output as any;
}
public static mapPush(map: { [index: string]: Object[] }, key: string, obj: Object): void {
(!map[key]) && (map[key] = []);
map[key].push(obj);
}
public static createDelegate(fn: Function, obj: any, args: any[]): Function {
return function () {
let callArgs = (args || []).concat(arguments);
return fn.apply(obj, callArgs);
};
}
public static regroupByParallel<T>(arr: T[], fn: (item: T) => boolean): T[][] {
let output: T[][] = [];
for (let i = 0, len = arr ? arr.length : 0; i < len; i++) {
let item = arr[i], lastItemArr = output[output.length - 1];
if (fn(item) && lastItemArr && lastItemArr.length && fn(lastItemArr[0])) {
lastItemArr.push(item)
} else {
output.push([item])
}
}
return output;
}
public static async runRegroupByParallel<T>(arr: T[], fn: (item: T) => boolean, runFn: (item: T) => Promise<any>): Promise<void> {
let itemsArr = Util.regroupByParallel(arr, fn);
for (let i = 0, len = (itemsArr || []).length; i < len; i++) {
let items = itemsArr[i];
let promises = (items || []).map(item => runFn(item));
await Promise.all(promises)
}
}
}