Merge pull request 'Add API Module' (#12) from dev-mrkbear into master

Reviewed-on: http://git.mrkbear.com/MrKBear/mini-dlpu-v3/pulls/12
This commit is contained in:
MrKBear 2021-12-30 16:18:24 +08:00
commit 623307ef2b
7 changed files with 465 additions and 130 deletions

View File

@ -1,15 +1,23 @@
import { IAppAPIParam } from "./core/Api";
import { Logger } from "./core/Logger"; import { Logger } from "./core/Logger";
import { LevelLogLabel, LifeCycleLogLabel } from "./core/PresetLogLabel"; import { LevelLogLabel, LifeCycleLogLabel } from "./core/PresetLogLabel";
import { Storage } from "./core/Storage";
App<IAppAPIParam>({
App({ /**
* API
* "/core/Api"
*/
api: {
nextId: 1,
pool: []
},
/** /**
* *
*/ */
storageCache: new Set<string>(), // storageCache: new Set<string>(),
/** /**
* *
@ -17,14 +25,5 @@ App({
onLaunch() { onLaunch() {
Logger.log("小程序启动...", Logger.log("小程序启动...",
LevelLogLabel.TraceLabel, LifeCycleLogLabel.OnLaunchLabel); LevelLogLabel.TraceLabel, LifeCycleLogLabel.OnLaunchLabel);
let s = new Storage("test", {
a: new Date(),
be: 2
});
setTimeout(() => {
s.set("be", 12);
}, 1000)
} }
}) })

295
miniprogram/core/Api.ts Normal file
View File

@ -0,0 +1,295 @@
import { EventEmitter } from "./EventEmitter";
import { LogLabel } from "./LogLabel";
import { Logger } from "./Logger";
import { LevelLogLabel, colorRadio } from "./PresetLogLabel";
interface IAppAPIParam {
api: {
/**
* API
*/
nextId: number;
/**
*
*/
pool: API<IAnyData, IAnyData>[];
}
}
interface IAnyData {
[x:string]: any
}
type IWxRequestOption<O> = WechatMiniprogram.RequestOption<O>;
type DeepReadonly<T> = {
readonly [P in keyof T]: DeepReadonly<T[P]>;
};
/**
*
*/
type IParamSetting<T extends IAnyData> = {
[P in keyof T]: {
/**
*
*/
defaultValue?: T[P],
/**
* ###
* 1 \
* 2使 string === string \
* 3使 number === number \
* 4使
*/
tester?: RegExp | ((data:T[P]) => boolean) | string | number,
/**
* ###
* 1 \
* 2 undefined \
* 3
*
* @param data
* @param key
* @param all
* @returns
*/
parse?: ((data:T[P], key:string, all:DeepReadonly<Partial<T>>) => T[P] | undefined),
/**
*
*/
isHeader?: boolean,
/**
*
*/
isTemplate?: boolean
/**
*
*/
Optional?: boolean
}
}
/**
* API
*/
type IAPIEvent<I extends IAnyData, O extends IAnyData> = {
/**
*
*/
initData: Partial<I>;
/**
*
*/
parseRequestData: Partial<I>;
}
/**
*
*/
class API<I extends IAnyData, O extends IAnyData> extends EventEmitter<IAPIEvent<I, O>> {
/**
* URL
* TODO: 这里可能涉及负载均衡
*/
public static get baseUrl():string {
return "https://xxx.xxx";
}
public static defaultLogLabel:LogLabel = new LogLabel(
`API:API`, colorRadio(200, 120, 222)
);
/**
* Logger 使
*/
private LogLabel:LogLabel = API.defaultLogLabel;
/**
* Api ID
*/
public key:string = "API";
/**
* API url
*/
public url:string = "/";
/**
* API
*/
public params:IParamSetting<I> = {} as any;
/**
* API
*/
public data?:Partial<I>;
/**
*
*/
public requestData?:IWxRequestOption<O>;
//#region wx.request
public timeout?:number;
public method:HTTPMethod = HTTPMethod.GET;
public enableHttp2:boolean = false;
public enableQuic:boolean = false;
public enableCache:boolean = false;
/**
* json
* wx.request dataType
*/
public jsonParse:boolean = true;
//#endregion wx.request
/**
*
*/
public initLabel() {
this.LogLabel = new LogLabel(
`API:${ this.key }`, colorRadio(200, 120, 222)
);
}
/**
*
* data
* @param data API需要的全部数据
*/
public param(data?: Partial<I>) {
this.data = data;
if (this.data === void 0) {
Logger.log(`数据初始化异常: 没有输入 [data] 数据!`,
LevelLogLabel.FatalLabel, this.LogLabel);
return;
}
for (let key in this.params) {
let data = this.data[key];
let { defaultValue, Optional, tester } = this.params[key];
// 默认值赋予
if (data === void 0 && defaultValue !== void 0) {
this.data[key] = defaultValue;
}
// 数据存在测试
if (data === void 0 && !Optional) {
Logger.log(`数据校验异常: 数据 [${key}] 是必须的,但是并没有接收到!`,
LevelLogLabel.FatalLabel, this.LogLabel);
}
// 用户自定义测试
if (data !== void 0 && tester !== void 0) {
let testRes:boolean = false;
if (tester instanceof RegExp) {
testRes = tester.test(data!);
} else if (typeof tester === "string" || typeof tester === "number") {
testRes = tester === data;
} else if (tester instanceof Function) {
testRes = tester(data!);
} else {
Logger.logMultiple(
[LevelLogLabel.FatalLabel, this.LogLabel],
`数据校验异常: [${ key }] 参数存在未知类型的 tester:`, tester
);
}
if (!testRes) {
Logger.logMultiple(
[LevelLogLabel.FatalLabel, this.LogLabel],
`数据校验异常: [${ key }] 参数数据未通过自定义的 tester:`, data
);
}
}
}
// 触发数据初始化事件
this.emit("initData", this.data);
if (this.data === void 0) {
Logger.log(`收集请求数据异常: 没有输入 [data] 数据!`,
LevelLogLabel.FatalLabel, this.LogLabel);
return;
}
// 重置请求数据
const requestData:IWxRequestOption<O> = this.requestData = {
url: API.baseUrl + this.url,
data: {}, header: {},
timeout: this.timeout,
method: this.method,
dataType: this.jsonParse ? "json" : undefined,
enableHttp2: this.enableHttp2,
enableQuic: this.enableQuic,
enableCache: this.enableCache
};
// 数据解析
for (let key in this.params) {
let data = this.data[key];
let { parse } = this.params[key];
// 数据预解析
if (parse !== void 0) {
this.data[key] = parse(data!, key, this.data as DeepReadonly<Partial<I>>);
}
}
// 触发数据解析
this.emit("parseRequestData", this.data);
// 数据收集
for (let key in this.params) {
let data = this.data[key];
let { isHeader, isTemplate } = this.params[key];
// 加载数据
if (!isTemplate) {
if (isHeader) {
requestData.header![key] = data;
} else {
(requestData.data as IAnyData)[key] = data;
}
}
}
}
}
/**
* HTTP
*/
enum HTTPMethod {
OPTIONS = "OPTIONS",
GET = "GET",
HEAD = "HEAD",
POST = "POST",
PUT = "PUT",
DELETE = "DELETE",
TRACE = "TRACE",
CONNECT = "CONNECT"
}
export default API;
export { API, IParamSetting, IAppAPIParam, HTTPMethod }

View File

@ -18,102 +18,92 @@ export type EventHandlerMap<Events extends Record<EventType, unknown>> = Map<
EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events> EventHandlerList<Events[keyof Events]> | WildCardEventHandlerList<Events>
>; >;
export interface Emitter<Events extends Record<EventType, unknown>> { type GenericEventHandler<Events extends Record<EventType, unknown>> =
all: EventHandlerMap<Events>; | Handler<Events[keyof Events]>
| WildcardHandler<Events>;
export class EventEmitter<Events extends Record<EventType, unknown>> {
/**
* A Map of event names to registered handler functions.
*/
public all: EventHandlerMap<Events>;
public constructor() {
this.all = new Map();
}
on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void; on<Key extends keyof Events>(type: Key, handler: Handler<Events[Key]>): void;
on(type: '*', handler: WildcardHandler<Events>): void; on(type: '*', handler: WildcardHandler<Events>): void;
/**
* Register an event handler for the given type.
* @param {string|symbol} type Type of event to listen for, or `'*'` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
public on<Key extends keyof Events>(type: Key, handler: GenericEventHandler<Events>) {
const handlers: Array<GenericEventHandler<Events>> | undefined = this.all!.get(type);
if (handlers) {
handlers.push(handler);
}
else {
this.all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>);
}
}
off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void; off<Key extends keyof Events>(type: Key, handler?: Handler<Events[Key]>): void;
off(type: '*', handler: WildcardHandler<Events>): void; off(type: '*', handler: WildcardHandler<Events>): void;
emit<Key extends keyof Events>(type: Key, event: Events[Key]): void; /**
emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void; * Remove an event handler for the given type.
} * If `handler` is omitted, all handlers of the given type are removed.
* @param {string|symbol} type Type of event to unregister `handler` from, or `'*'`
/** * @param {Function} [handler] Handler function to remove
* Mitt: Tiny (~200b) functional event emitter / pubsub. * @memberOf mitt
* @name mitt */
* @returns {Mitt} public off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler<Events>) {
*/ const handlers: Array<GenericEventHandler<Events>> | undefined = this.all!.get(type);
export default function mitt<Events extends Record<EventType, unknown>>( if (handlers) {
all?: EventHandlerMap<Events> if (handler) {
): Emitter<Events> { handlers.splice(handlers.indexOf(handler) >>> 0, 1);
type GenericEventHandler =
| Handler<Events[keyof Events]>
| WildcardHandler<Events>;
all = all || new Map();
return {
/**
* A Map of event names to registered handler functions.
*/
all,
/**
* Register an event handler for the given type.
* @param {string|symbol} type Type of event to listen for, or `'*'` for all events
* @param {Function} handler Function to call in response to given event
* @memberOf mitt
*/
on<Key extends keyof Events>(type: Key, handler: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
if (handlers) {
handlers.push(handler);
} }
else { else {
all!.set(type, [handler] as EventHandlerList<Events[keyof Events]>); this.all!.set(type, []);
}
},
/**
* Remove an event handler for the given type.
* If `handler` is omitted, all handlers of the given type are removed.
* @param {string|symbol} type Type of event to unregister `handler` from, or `'*'`
* @param {Function} [handler] Handler function to remove
* @memberOf mitt
*/
off<Key extends keyof Events>(type: Key, handler?: GenericEventHandler) {
const handlers: Array<GenericEventHandler> | undefined = all!.get(type);
if (handlers) {
if (handler) {
handlers.splice(handlers.indexOf(handler) >>> 0, 1);
}
else {
all!.set(type, []);
}
}
},
/**
* Invoke all handlers for the given type.
* If present, `'*'` handlers are invoked after type-matched handlers.
*
* Note: Manually firing '*' handlers is not supported.
*
* @param {string|symbol} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
let handlers = all!.get(type);
if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>)
.slice()
.map((handler) => {
handler(evt!);
});
}
handlers = all!.get('*');
if (handlers) {
(handlers as WildCardEventHandlerList<Events>)
.slice()
.map((handler) => {
handler(type, evt!);
});
} }
} }
}; }
emit<Key extends keyof Events>(type: Key, event: Events[Key]): void;
emit<Key extends keyof Events>(type: undefined extends Events[Key] ? Key : never): void;
/**
* Invoke all handlers for the given type.
* If present, `'*'` handlers are invoked after type-matched handlers.
*
* Note: Manually firing '*' handlers is not supported.
*
* @param {string|symbol} type The event type to invoke
* @param {Any} [evt] Any value (object is recommended and powerful), passed to each handler
* @memberOf mitt
*/
emit<Key extends keyof Events>(type: Key, evt?: Events[Key]) {
let handlers = this.all!.get(type);
if (handlers) {
(handlers as EventHandlerList<Events[keyof Events]>)
.slice()
.map((handler) => {
handler(evt!);
});
}
handlers = this.all!.get('*');
if (handlers) {
(handlers as WildCardEventHandlerList<Events>)
.slice()
.map((handler) => {
handler(type, evt!);
});
}
}
} }

View File

@ -1,4 +1,4 @@
import mitt, { Emitter, EventHandlerMap, EventType, Handler, WildcardHandler } from "./EventEmitter"; import { EventEmitter, EventType } from "./EventEmitter";
import { LogLabel, LogStyle } from "./LogLabel"; import { LogLabel, LogStyle } from "./LogLabel";
import { Logger } from "./Logger"; import { Logger } from "./Logger";
import { LevelLogLabel } from "./PresetLogLabel"; import { LevelLogLabel } from "./PresetLogLabel";
@ -64,7 +64,8 @@ class Modular<
DEP extends Depends<M> = Depends<M>, DEP extends Depends<M> = Depends<M>,
E extends Record<EventType, unknown> = Record<EventType, unknown>, E extends Record<EventType, unknown> = Record<EventType, unknown>,
TD extends IAnyTypeObject = IAnyTypeObject> TD extends IAnyTypeObject = IAnyTypeObject>
implements WXContext<TD, IAnyTypeObject>, Emitter<E> { extends EventEmitter<E>
implements WXContext<TD, IAnyTypeObject> {
// [x:string]: any; // [x:string]: any;
@ -121,6 +122,8 @@ implements WXContext<TD, IAnyTypeObject>, Emitter<E> {
*/ */
public constructor(manager:M, nameSpace:string, depend?: DEP) { public constructor(manager:M, nameSpace:string, depend?: DEP) {
super();
// 保存微信上下文 // 保存微信上下文
this.manager = manager; this.manager = manager;
@ -131,34 +134,6 @@ implements WXContext<TD, IAnyTypeObject>, Emitter<E> {
this.functionList = new Set<string>(); this.functionList = new Set<string>();
this.paramList = new Set<string>(); this.paramList = new Set<string>();
this.nameSpace = nameSpace; this.nameSpace = nameSpace;
this.emitter = mitt<E>();
}
/**
*
*/
private emitter:Emitter<E>;
public get all():EventHandlerMap<E> { return this.emitter.all };
on<Key extends keyof E>(type: Key, handler: Handler<E[Key]>): void;
on(type: "*", handler: WildcardHandler<E>): void;
on(type: any, handler: any): void {
return this.emitter.on(type, handler);
}
off<Key extends keyof E>(type: Key, handler?: Handler<E[Key]>): void;
off(type: "*", handler: WildcardHandler<E>): void;
off(type: any, handler?: any): void {
return this.emitter.off(type, handler);
}
emit<Key extends keyof E>(type: Key, event: E[Key]): void;
emit<Key extends keyof E>(type: undefined extends E[Key] ? Key : never): void;
emit(type: any, event?: any): void {
return this.emitter.emit(type, event);
} }
public setData(data:Partial<TD>, callback?: () => void):void { public setData(data:Partial<TD>, callback?: () => void):void {

View File

@ -0,0 +1,74 @@
import { Modular, Manager, ILifetime } from "../../core/Module";
import { API, IParamSetting } from "../../core/Api";
import { Storage } from "../../core/Storage";
/**
*
*/
class TestCore<M extends Manager> extends Modular<M>
implements Partial<ILifetime> {
public onLoad() {
let s = new Storage("test", {
a: new Date(),
be: 2
});
setTimeout(() => {
s.set("be", 12);
}, 1000)
interface ITestApiInput {
name: string,
id: number,
info: {
data: string
}
}
class TestApi extends API<ITestApiInput, {}> {
public override key:string = "TestApi";
public override params: IParamSetting<ITestApiInput> = {
name: {
tester: "123",
isHeader: true
},
id: {
parse: (i) => ++i,
},
info: {}
}
public constructor() {
super();
this.initLabel();
this.emit("initData", {})
this.on("initData", (d) => {
})
this.on("parseRequestData", (data) => {
console.log("parseRequestData", data)
})
}
}
let api = new TestApi();
api.param({
name: "123",
id: 456,
info: {
data: "abc"
}
});
console.log(api);
}
}
export default TestCore;
export { TestCore };

View File

@ -1,5 +1,6 @@
import { Manager} from "../../core/Module"; import { Manager} from "../../core/Module";
import { StatusBar } from "./StatusBar"; import { StatusBar } from "./StatusBar";
import { TestCore } from "./TestCore";
/** /**
* 使 Manager * 使 Manager
@ -7,4 +8,5 @@ import { StatusBar } from "./StatusBar";
*/ */
Manager.Page((manager)=>{ Manager.Page((manager)=>{
manager.addModule(StatusBar, "statusBar"); manager.addModule(StatusBar, "statusBar");
manager.addModule(TestCore, "testCore");
}) })

View File

@ -35,7 +35,7 @@
"outputPath": "" "outputPath": ""
}, },
"enableEngineNative": false, "enableEngineNative": false,
"useIsolateContext": true, "useIsolateContext": false,
"userConfirmedBundleSwitch": false, "userConfirmedBundleSwitch": false,
"packNpmManually": false, "packNpmManually": false,
"packNpmRelationList": [], "packNpmRelationList": [],