UNPKG

cmkit

Version:

common web developer tool box.

615 lines (611 loc) 25.6 kB
interface String { /** * @description parse the url string to formated object */ readonly parsed: () => { readonly query: string; readonly host: string; readonly schema: string; readonly [key: string]: string; }; /** * @description fix the length of number * @example '1'.fixlen(2) -> '01' '12331'.fixlen(3)->'331' * @param len must be positive nonzero number otherwise use @default 2 */ readonly fixlen: (len?: number) => string; } interface Date { /** @example 59:45 */ readonly mmss: string; /** @example 08:00*/ readonly hhmm: string; /** @example 23:59:45*/ readonly hhmmss: string; /** * @description format the Date to string * @param fmt @example 'yyyy-MM-dd hh:mm:ss' */ readonly format: (fmt: string) => string; } interface Number { /** * @example Trun 1.3411111 to 1.35 when precision=2 * @param precision the permision must be nonnegative number otherwise use @default 0 */ readonly ceil: (precision?: number) => number; /** * @example Trun 1.34567 to 1.34 when precision=2 * @param precision the permision must be nonnegative number otherwise use @default 0 */ readonly floor: (precision?: number) => number; /** * @example Trun 1.34567 to 1.35 when precision=2 * @param precision the permision must be nonnegative number otherwise use @default 0 */ readonly round: (precision?: number) => number; /** * @description Insert comma symbol to the integer part * @notice The fractional part of the number will be ignore. * @example * console.log((23123.1234).comma); // '23,123' */ readonly comma: () => string; /** * @description fix the length of number * @example 1.fixlen(2) -> '01' 1987.fixlen(3) -> '987' * @param len must be positive nonzero number otherwise use @default 2 */ readonly fixlen: (len?: number) => string; /** * @description get index symbol of int number * @example * console.log((23).symidx);//rd */ readonly symidx: 'st' | 'nd' | 'rd' | 'th'; /** * @description Trun the number to kilo million billion trillion * @param max The max length affter format. @default 3 * @example * console.log((1000000).kmgtify(3));//1M * console.log((1000000).kmgtify(4));//1000K * console.log((1000000).kmgtify(5));//1000K * console.log((1000000).kmgtify(6));//1000K * console.log((10000000).kmgtify(3));//10M * console.log((10000000).kmgtify(4));//10M * console.log((10000000).kmgtify(5));//10000K * console.log((1000000000).kmgtify(3));//1G * console.log((999999999999999).kmgtify(3));//999T */ readonly kmgtify: (max?: 3 | 4 | 5 | 6) => string; /** * @description Trun the number to kilo million billion trillion * @param max The max length affter format. @default 3 * @example * console.log((1000000).kmgtify(3));//1m * console.log((1000000).kmgtify(4));//1000k * console.log((1000000).kmgtify(5));//1000k * console.log((1000000).kmgtify(6));//1000k * console.log((10000000).kmgtify(3));//10m * console.log((10000000).kmgtify(4));//10m * console.log((10000000).kmgtify(5));//10000k * console.log((1000000000).kmgtify(3));//1b * console.log((999999999999999).kmgtify(3));//999t * console.log((1.23 * Math.pow(10, 26 * 3 * 3 + 13)).kmbtify(3));//12cz */ readonly kmbtify: (max?: 3 | 4 | 5 | 6) => string; } interface Array<T> { /** * @description get the last element from the stack */ readonly last: T | undefined; /** * @description get the first element from the stack */ readonly first: T | undefined; /** * @description get an random index of array return -1 when empty */ readonly ranidx: number; /** * @description get an random item from arrary,if empty return undefined */ readonly random: T | undefined; /** * @description insert item at index * @param item the item to be insert * @param index the index of new item * @notice the max value of index is the length of befor ary */ readonly insert: (item: T, index: number) => void; /** * @description append other sequence of T * @param ary the sequence which will be append * @returns the length of self affter append. */ readonly append: (ary: T[]) => number; /** * @description delete an object from array * @returns the index that been deleted. if not found retrun -1 * @param item the object need to be delete */ readonly delete: (item: T) => number; /** * @description delete on at index * @returns the object that been deleted if out of bounds retrun undefined * @param index the index need to be delete */ readonly remove: (index: number) => T | undefined; /** * @description judge array contains the item or not. * @param item the target item. */ readonly contains: (item: T) => boolean; } declare namespace cm { /**@description print info message when debug allow */ const log: (msg: any, ...args: any[]) => void; /**@description print wining message when debug allow */ const warn: (msg: any, ...args: any[]) => void; /** * @description call func safely * @usually use for call callback function * @param func target function * @param args the @param func 's args * @notice thirArg of @param func is undefined */ const call: (func: Function, ...args: any[]) => void; /** * @description check an value is an available string * @usually use for form field verify * @notice only @param value is number or not empty string can pass * @param value witch to be verify */ const okstr: (value: any) => boolean; /** * @description check an value is an available integer * @usually use for form field verify * @notice only @param value is integer like can pass * @param value witch to be verify */ const okint: (value: any) => boolean; /** * @description check an value is an available number * @usually use for form field verify * @notice only @param value is number like can pass * @param value witch to be verify */ const oknum: (value: any) => boolean; /** @description config global value*/ const config: (host: string, debug?: boolean) => void; /** @description show debug info or not @default false*/ const debug: boolean; /** @description api server name @default undefined*/ const apihost: string; /** @description judge the device‘s screen ratio is greater than 16/9 if true maybe iphoneX */ const isslim: boolean; /** * @description global config Number.kmgtify formater * @default value.comma()+symbol * @param value the new number part * @param symbol the symbol flag e.g K M G T * @example * cm.kmgtfmt = value=>(value.toFixed(2)+symbol) * console.log((10000).kmgtify())//10.00K */ let kmgtfmt: (value: number, symbol: '' | 'K' | 'M' | 'G' | 'T') => string; /** * @description global config Number.kmbtify formater * @default value.comma()+symbol * @param value the new number part * @param symbol the symbol flag e.g k m b t aa ab ac ad ae ... zz * @example * cm.kmbtfmt = value=>(value.toFixed(2)+symbol) * console.log((10000).kmgtify())//10.00K */ let kmbtfmt: (value: number, symbol: string) => string; } declare namespace cm { class I18n<D = any> { private data: D; constructor(data?: D); /** * @description set the metadata for i18n * @param the metadata */ public setData: (data: D) => void; /** * @description get localized string from key and arguments * @param key The localize key * @param args The arguments of placeholder * @info The placeholder must be set like {0} {1} {2} ... * @example * ``` * cm.i18n.setData({YOUR_KEY:'example for i18n {0} {1}'}) * cm.i18n.localize('YOUR_KEY','hello','world') * ``` */ public localize: (key: keyof D, ...args: (string | number)[]) => string; } const i18n: I18n; abstract class Emitter<E extends string = string> { /** * @description register event handler to the emitter on target. * @notice Only one handler will exist in same target and same event. The later one will be ignore * @param event the event * @param target the callback's caller * @param callback the event handler */ public readonly on: (event: E, target: object, callback: Function) => void; /** * @description remove event handler of the emitter * @example * emiter.off('YOUR_EVENT') // remove all the handler of 'YOUR_EVENT' * emiter.off(this) // remove all the handler on the 'this' target * emiter.off('YOUR_EVENT',this) // only remove the handler of 'YOUR_EVENT' on this target * //The following usage is not recommended * emiter.off(this,other) // the same as emiter.off(this) other will be ignore. */ public readonly off: (eventOrTarget: E | object, target?: object) => void; /** * @description register once event handler to the emitter on target * @notice Only one handler will exist in same target and same event. The later one will be ignore * @param event the event * @param target the callback's caller * @param callback the event handler */ public readonly once: (event: E, target: object, callback: Function) => void; /** * @description dispatch event to all the rigsted handler * @param event the event * @param args the arguments of callback function */ protected readonly emit: (event: E, ...args: any[]) => void; /** * @description off all handlers */ protected readonly offall: () => void; } class NoticeCenter<T extends string = string> extends Emitter<T> { /** * @description dispatch event to all the rigsted handler * @param event the event * @param args the arguments of callback function */ public readonly emit: (event: T, ...args: any[]) => void; /** @description remove all handler */ public readonly offall: () => void; } /** @description A global shared notice center. */ const notice: NoticeCenter; interface IMetaClass<T> { new (json?: any): T; } abstract class Network { /** * @description define the key of maptask and mapreq * @default 'id' */ protected get mapkey(): 'id' | string; /** * @description auto show loading or not * @notice You must provide your loading UI in before or after hock. otherwith it does't work! * @see Network.before @see Network.after. * @default false */ protected get loading(): boolean; /** * @description wait time out settings * @default 0 wait forever */ protected get timeout(): number; /** * @description the response type for xhr.responseType * @default 'json' */ protected get restype(): 'json' | 'text'; /** * @description the global http request method * @override you shoud override this property and provide you custom headers * @default "POST" * @example * protected get method(): any { * return 'POST' * } */ protected get method(): Network.Method; /** * @description the global http headers. every request will include this headers * @override you shoud overwrite this property and provide you custom headers * @example * protected get headers(): any { * return { * token:'yourtoken', * userId:'yourUserId' * } * } */ protected get headers(): Record<string, string>; /** * @description the global request body data reslover * @override override point * @param data the user request data * @return the finnal request data */ protected params(data: any): any; /** * @description the global hock before every request * @override override point * @param path the relative uri * @param opts the request options * @returns go on request or not @default true */ protected before(path: string, opts?: Network.Options): boolean; /** * @description the global hock after every request * @override override point * @param path the relative uri * @param resp the response data or error */ protected after(path: string, resp?: any | Error): void; /** * @description global resove relative uri to full url * @param path the relative uri */ protected url(path: string): string; /** * @description resolve the data * @default retrun json * @param json the jsoned respons data */ protected resolve(json: any): any | Promise<any>; /** * @description transform the service error * @param error the origin network error * @default 'throw the origin error'; * @warn You must throw a new error for custom otherwise you can't get error message */ protected reject(error: Network.Error | Error): void; /** ----- network data request methods. */ readonly upload: <T = any>(path: string, upload: Network.Upload) => Network.UploadTask<T>; readonly anyreq: <T = any>(req: Network.Request<T>) => Network.DataTask<T>; readonly objreq: <T>(req: Network.Request<T>) => Network.DataTask<T>; readonly aryreq: <T>(req: Network.Request<T>) => Network.DataTask<T[]>; readonly mapreq: <T>(req: Network.Request<T>) => Network.DataTask<Record<keyof any, T>>; readonly anytask: <T = any>(path: string, data?: any, opts?: Network.Options) => Network.DataTask<T>; readonly objtask: <T>(meta: IMetaClass<T>, path: string, data?: any, opts?: Network.Options) => Network.DataTask<T>; readonly arytask: <T>(meta: IMetaClass<T>, path: string, data?: any, opts?: Network.Options) => Network.DataTask<T[]>; /** * @description convert respones data to map * @notice use opts.mapkey to define the key field otherwise use 'id' by default */ readonly maptask: <T>(meta: IMetaClass<T>, path: string, data?: any, opts?: Network.Options) => Network.DataTask<Record<keyof any, T>>; } namespace Network { type Method = 'GET' | 'PUT' | 'POST' | 'DELETE'; type ErrorType = 'abort' | 'timeout' | 'service'; interface Upload { readonly name: string; readonly data: Blob | File; readonly type?: string; //content-type readonly opts?: Options; readonly params?: Record<string, any>; } interface Request<T> { readonly path: string; readonly meta: IMetaClass<T> | T; readonly data?: any; readonly opts?: Options; } interface Options { /** @description use for override global methods */ readonly method?: Method; /** * @description define the key of maptask and mapreq * @default 'id' */ readonly mapkey?: 'id' | string; /** @description use for override global headers */ readonly headers?: Record<string, string>; /** @default 0 wait forever */ readonly timeout?: number; /** * @description auto show loading or not * @notice You must provide your loading UI in before or after hock. otherwith it does't work! * @see Network.before @see Network.after. * @default false */ readonly loading?: boolean; /** * @description the response type for xhr.responseType * @default 'json' */ readonly restype?: 'json' | 'text'; /** @description use for override global reslove method */ readonly parser?: (resp: any) => any; } class Error { readonly type: ErrorType; readonly info?: any; //the error detail info readonly status: number; readonly message?: string; //the error description private constructor(); static readonly abort: (status: number) => Error; static readonly timeout: (status: number) => Error; static readonly service: (status: number, info: any) => Error; } interface DataTask<T> { readonly then: <TResult1 = T, TResult2 = never>( onfulfilled?: (value: T) => TResult1 | PromiseLike<TResult1>, onrejected?: (reason: any) => TResult2 | PromiseLike<TResult2> ) => Promise<TResult1 | TResult2>; readonly catch: <TResult = never>(onrejected?: (reason: any) => TResult | PromiseLike<TResult>) => Promise<T | TResult>; readonly abort: () => void; readonly onProgress: (func: (evt: ProgressEvent) => void) => void; } interface UploadTask<T> extends DataTask<T> { readonly onProgress: (func: (evt: ProgressEvent) => void) => void; } /** * @description encode object to query string * @param params must be a plan key value object. the value of key suport plan array. * @warn plan value means string number boolean bigint * @example * const param = { a: 1, b: 2, c: [4, 5, 'haa'], d: true } * console.log(Network.encodeQuery(param)) // ?a=1&b=2&c=4&c=5&c=haa&d=true */ const encodeQuery: (params: object) => string; /** * @description replace your custome network implementation * @param impl You must provide your custome network implementation */ const replaceImpl: (impl: { request: (url: string, data: any, opts: Options) => [Promise<any>, { abort: () => void; onprogress: (evt: ProgressEvent) => void }]; }) => void; } /** @description Wrapped on WebSocket and has implement retry mechanis */ class Socket { binaryType: 'arraybuffer' | 'blob'; /** @default 'arraybuffer' */ readonly retry: Socket.Retry; /** @description retry settings */ readonly send: (data: string | ArrayBuffer | Blob) => void; readonly open: () => void; readonly close: (code?: number, reason?: string) => void; readonly isRetrying: boolean; readonly protocol: string; readonly extensions: string; readonly readyState: number; readonly bufferedAmount: number; onopen: (evt: Event, isRetry: boolean) => void; onclose: (evt: CloseEvent, reason: Socket.Reason) => void; onerror: (evt: ErrorEvent) => void; onmessage: (evt: MessageEvent) => void; constructor(builder: () => string, protocols?: string | string[]); } namespace Socket { const OPEN: number; const CLOSED: number; const CLOSING: number; const CONNECTING: number; type Reason = 'user' | 'ping' | 'retry' | 'server'; type Events = 'open' | 'error' | 'close' | 'message'; type Status = 'closed' | 'closing' | 'opened' | 'opening'; /** @description A retry machine for web socket */ interface Retry { /** * @description base attempt delay time @default 100 milliscond * @description the real delay time use a exponential random algorithm */ delay: number; /** @description allow ping pong mechanism or not. @default true */ allow: boolean; /** @description the max retry times when retrying @default 8 */ chance: number; } interface Ping { /** * @description allow ping pong mechanism or not. * @default true * @warn It doesn't work affter socket has been started. */ allow: boolean; /** * @description the time interval of ping * @default 30s * @notice It doesn't work affter socket has been started. */ interval: number; } /** * @description socket client wrapped on Socket * @description you must inherit this class to implements your logic * @implements client PING heartbeat mechanis * @implements client reconnect mechanis * @notice by defualt the client never emit any event. you must emit it at override point yourself. */ abstract class Client<E extends string = Events> extends Emitter<E> { /** * @description the client ping mechanis * @ping use socket.send("{\"type\":\"PING\"}") * @pong receive message = "{\"type\":\"PONG\"}" * @note the server must send the specified @pong when recived @ping otherwhis please close the ping */ protected readonly ping: Ping; /** the realy websocket handler */ protected readonly socket: Socket; /** Tell me your login status if not no retry */ protected abstract get isLogin(): boolean; /** @overwrite this method to provide url for web socket */ protected abstract buildurl(): string; /** call when get some message @override point @notice the msg has been parsed using JSON.parse.*/ protected abstract onMessage(msg: any): void; /** call when some error occur @override point */ protected onError(res: ErrorEvent): void; /** call when socket opened @override point */ protected onOpened(res: any, isRetry: boolean): void; /** call when socket closed @override point */ protected onClosed(res: CloseEvent, reason: Reason): void; readonly isConnected: boolean; /** the connection status */ readonly stop: () => void; /** disconnect and stop ping pong retry */ readonly start: () => void; /** connect the server and start ping pong retry */ } } namespace orm { /** * @description A class decorate use to store class. * @param clskey the class name of your storage class * @param idxkey the primary key field name of your storage class * @notice the idxkey must be exist in the metaclass */ const store: (clskey: string, idxkey: string) => <T>(target: IMetaClass<T>) => void; /** * @description A property decorate to mark a field also a store class. * @param cls the class of field. */ const field: <T>(cls: IMetaClass<T>, map?: boolean) => (target: Object, field: string) => void; /** * @description save an storage able class. * @param model the model class must be mark with @storage(...) * @throws did't mark error */ const save: <T>(model: T) => void; /** * @description find an storaged object whith id. * @param cls the storage class witch must be mark with @storage(...) * @param id the primary key of the cls * @throws did't mark error */ const find: <T>(cls: IMetaClass<T>, id: string | number) => T; /** * @description find all storaged object's primary key of cls. * @param cls the storage class witch must be mark with @storage(...) * @throws did't mark error */ const ids: <T>(cls: IMetaClass<T>) => string[]; /** * @description find all storaged object of cls. * @param cls the storage class witch must be mark with @storage(...) * @throws did't mark error */ const all: <T>(cls: IMetaClass<T>) => T[]; /** * @description get the count of all storaged object of cls. * @param cls the storage class witch must be mark with @storage(...) * @throws did't mark error */ const count: <T>(cls: IMetaClass<T>) => number; /** * @description remove all storaged object of cls. * @param cls the storage class witch must be mark with @storage(...) * @throws did't mark error */ const clear: <T>(cls: IMetaClass<T>) => void; /** * @description remove an special storaged object of cls. * @param cls the storage class witch must be mark with @storage(...) * @param id the primary key of the cls * @throws did't mark error */ const remove: <T>(cls: IMetaClass<T>, id: string | number) => void; } }